@aurigma/design-atoms
Version:
Design Atoms is a part of Customer's Canvas SDK which allows for manipulating individual design elements through your code.
312 lines • 16.4 kB
JavaScript
import { BaseInputHandler } from "../BaseInputHandler";
import { InputState } from "./../../../Input/InputManager/IInputManager";
import Environment from "@aurigma/design-atoms-model/Utils/Environment";
import { EventWithSenderArg } from "@aurigma/design-atoms-model/EventObject";
import { RgbColor } from "@aurigma/design-atoms-model/Colors";
import { Cursor } from "./../../../Utils/Common";
import { PointF, RectangleF, SizeF } from "@aurigma/design-atoms-model/Math";
import { CoordinatesConvertUtils } from "./../../../Utils/CoordinatesConvertUtils";
import { RotateHandler } from "./../../../RotateHandler";
import { Graphics } from "./../../../Graphics";
import { PrintAreaBoundsType } from "@aurigma/design-atoms-model/Product/PrintAreaBoundsType";
import { clamp } from "./../../../Utils/Math";
export class SelectPixelInputHandler extends BaseInputHandler {
constructor(inputManager, _viewer, _canvasElementHandler) {
super(inputManager);
this._viewer = _viewer;
this._canvasElementHandler = _canvasElementHandler;
this._mobileMode = Environment.IsTouchDevice();
this._cursorSize = 10;
this._pixelRadius = this._mobileMode ? 6.5 : 8.5;
this._zoom = 10;
this._lenseRadius = this._pixelRadius * this._zoom;
this._textYPosition = 130;
this._textPadding = { v: 4, h: 10 };
this._buttonsElementMargin = 8;
this._lenseCaptured = false;
this._onCompletedEvent = new EventWithSenderArg();
this._currentColorData = null;
this._createButtonsElement = () => {
const element = document.createElement("div");
this._canvas.viewer.whitespaceDiv.appendChild(element);
element.className = "floating-btn-group btn-group color-select";
element.style.position = "absolute";
const rejectButton = document.createElement("button");
rejectButton.className = "btn btn-default reject-button cc-icon-arrow-close";
rejectButton.addEventListener("click", this._onReject);
element.appendChild(rejectButton);
const acceptButton = document.createElement("button");
acceptButton.className = "btn btn-default accept-button cc-icon-check-image";
acceptButton.addEventListener("click", this._onAccept);
element.appendChild(acceptButton);
this._buttonsElement = element;
};
this._onAccept = () => {
this._onSelectPixelEnd(this._currentColorData);
};
this._onReject = () => {
this._onSelectPixelEnd(null);
};
this._onSelectPixelEnd = (result) => {
this._onCompletedEvent.notify(this, result);
this._canvas.viewer.eventManager.selectPixelFinished.notify(result);
this._selection.unlock();
};
this._updateCreateButtonsPosition = () => {
if (this._buttonsElement == null)
return;
const lenseLeft = parseFloat(this._canvasLensElement.style.left);
const lenseTop = parseFloat(this._canvasLensElement.style.top);
const lenseWidth = parseFloat(this._canvasLensElement.style.height);
const lenseHeight = parseFloat(this._canvasLensElement.style.height);
const buttonElementRect = this._buttonsElement.getBoundingClientRect();
this._buttonsElement.style.left = (lenseLeft + lenseWidth / 2 - buttonElementRect.width / 2) + "px";
let buttonsElementTop = lenseTop - buttonElementRect.height - this._buttonsElementMargin;
if (lenseTop - buttonElementRect.height - this._buttonsElementMargin <= 0) {
buttonsElementTop = lenseTop + lenseHeight + this._buttonsElementMargin;
}
this._buttonsElement.style.top = `${buttonsElementTop}px`;
};
this._updateView = (point = null) => {
const targetPoint = point || this._currentPoint;
this._updateLensImage(targetPoint);
this._changePosition(targetPoint);
if (this._mobileMode)
this._updateCreateButtonsPosition();
};
this._createLensCanvas = () => {
const canvasElement = document.createElement("canvas");
canvasElement.width = this._lenseRadius * 2;
canvasElement.height = this._lenseRadius * 2;
canvasElement.style.width = `${this._lenseRadius * 2}px`;
canvasElement.style.height = `${this._lenseRadius * 2}px`;
canvasElement.style.position = "absolute";
canvasElement.style.borderRadius = `${this._lenseRadius}px`;
canvasElement.style.borderWidth = "1px";
canvasElement.style.borderColor = "rgb(0,0,0,0.7)";
canvasElement.style.borderStyle = "solid";
canvasElement.style.userSelect = "none";
canvasElement.tabIndex = -1;
canvasElement.addEventListener("keydown", this._onKeyDown);
const context = canvasElement.getContext("2d");
context.imageSmoothingEnabled = false;
context.imageSmoothingQuality = "low";
setTimeout(() => canvasElement.focus());
return canvasElement;
};
this._onKeyDown = (event) => {
// if ESC
if (event.keyCode === 27)
this._onReject();
};
// Select pixel needs one canvas as input, and we can reach this goal if call clear selection command.
const cv = this._viewer.canvas;
this._viewer.setCursor(Cursor.cross);
cv.selection.lock(true);
this._viewer.ignoreDocumentClickOnce();
if (!this._mobileMode)
return;
this._canvasLensElement = this._createLensCanvas();
this._canvasElementHandler.addChild(this._canvasLensElement);
this._createButtonsElement();
this._putLenseOnWhitespaceCenter();
cv.viewer.add_onResize(this._updateView);
}
get _canvas() {
return this._viewer.canvas;
}
get _selection() {
return this._viewer.canvas.selection;
}
async _onClick(params) {
if (params.isMobile)
return;
this._canvas.viewer.ignoreDocumentClickOnce();
this._updateView(params.page);
this._onAccept();
}
async _onMove(params) {
if (!params.isMobile)
return;
switch (params.state) {
case InputState.Started:
const canvasLensCenter = new PointF(parseInt(this._canvasLensElement.style.left) + this._lenseRadius, parseInt(this._canvasLensElement.style.top) + this._lenseRadius);
const wsPoint = CoordinatesConvertUtils.pageToControlPoint(params.startPage, this._viewer);
const distance = Math.sqrt(Math.pow(wsPoint.x - canvasLensCenter.x, 2) +
Math.pow(wsPoint.y - canvasLensCenter.y, 2));
if (distance < this._lenseRadius) {
this._lenseCaptured = true;
this._capturedPoint = params.startPage.clone();
this._moveLenseByNewPoint(params.page);
}
break;
case InputState.InProgress:
if (this._lenseCaptured)
this._moveLenseByNewPoint(params.page);
break;
case InputState.Finished:
if (!this._lenseCaptured)
return;
this._lenseCaptured = false;
this._currentPoint = new PointF(this._currentPoint.x + params.page.x - this._capturedPoint.x, this._currentPoint.y + params.page.y - this._capturedPoint.y);
this._capturedPoint = null;
break;
}
}
_moveLenseByNewPoint(point) {
const newPoint = new PointF(this._currentPoint.x + point.x - this._capturedPoint.x, this._currentPoint.y + point.y - this._capturedPoint.y);
this._updateView(newPoint);
}
async _onHover(params) {
if (this._canvasLensElement == null) {
this._canvasLensElement = this._createLensCanvas();
this._canvasElementHandler.addChild(this._canvasLensElement);
}
this._updateView(params.page);
}
async _onKey(params) {
if (params.state === InputState.Finished && params.code === "Escape")
this._onReject();
}
addOnCompleted(handler) { this._onCompletedEvent.add(handler); }
removeOnCompleted(handler) { this._onCompletedEvent.remove(handler); }
_putLenseOnWhitespaceCenter() {
const vw = this._canvas.viewer;
const wsDiv = vw.whitespaceDiv;
const whitespaceCenter = new PointF(wsDiv.offsetWidth / 2, wsDiv.offsetHeight / 2);
const point = CoordinatesConvertUtils.whitespaceToWorkspacePoint(whitespaceCenter, vw);
this._currentPoint = point;
this._updateView();
}
_calculateLensBounds() {
const whitespaceDiv = this._canvas.viewer.whitespaceDiv;
const viewportDiv = this._canvas.viewer.viewportDiv;
const wsClientRect = whitespaceDiv.getBoundingClientRect();
const vpClientRect = viewportDiv.getBoundingClientRect();
let left = wsClientRect.left < vpClientRect.left ? vpClientRect.left - wsClientRect.left : 0;
let right = left + vpClientRect.width;
let top = wsClientRect.top < vpClientRect.top ? vpClientRect.top - wsClientRect.top : 0;
let bottom = top + vpClientRect.height;
return { left: left, top: top, right: right, bottom: bottom };
}
_changePosition(point) {
const vw = this._canvas.viewer;
const whitespaceCoord = CoordinatesConvertUtils.pageToWhitespace(point, vw);
const diameter = this._lenseRadius * 2;
const whitespaceDiv = vw.whitespaceDiv;
if (this._mobileMode) {
this._canvasLensElement.style.left =
`${clamp(whitespaceCoord.x, this._lenseRadius, whitespaceDiv.offsetWidth - this._lenseRadius) - this._lenseRadius}px`;
this._canvasLensElement.style.top =
`${clamp(whitespaceCoord.y, this._lenseRadius, whitespaceDiv.offsetHeight - this._lenseRadius) - this._lenseRadius}px`;
}
else {
const bounds = this._calculateLensBounds();
let left;
let top;
if (whitespaceCoord.x + this._cursorSize + diameter < bounds.right)
left = whitespaceCoord.x + this._cursorSize;
else
left = whitespaceCoord.x - this._cursorSize - diameter;
if (whitespaceCoord.y + this._cursorSize + diameter < bounds.bottom)
top = whitespaceCoord.y + this._cursorSize;
else
top = whitespaceCoord.y - this._cursorSize - diameter;
left = Math.max(left, bounds.left);
left = Math.min(left, bounds.right - diameter);
top = Math.max(top, bounds.top);
top = Math.min(top, bounds.bottom - diameter);
this._canvasLensElement.style.left = `${left}px`;
this._canvasLensElement.style.top = `${top}px`;
}
}
_updateLensImage(point) {
const vw = this._canvas.viewer;
const size = this._pixelRadius * 2;
const contentPoint = CoordinatesConvertUtils.pageToControlPoint(point, vw);
const rulerWidth = this._canvas.viewer.actualRulerWidth;
contentPoint.translate(-rulerWidth, -rulerWidth);
contentPoint.x *= window.devicePixelRatio;
contentPoint.y *= window.devicePixelRatio;
const lenseSize = this._lenseRadius * 2;
var rect = new RectangleF(contentPoint.x - Math.trunc(this._pixelRadius), contentPoint.y - Math.trunc(this._pixelRadius) + 1, size, size);
/* rect.x += this._canvas.offset.x;
rect.y += this._canvas.offset.y; */
const ctx = this._canvasElementHandler.viewportSurfaceCanvas.getContext("2d");
const imageData = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
const middle = Math.trunc(size / 2);
const lensContext = this._canvasLensElement.getContext("2d");
lensContext.resetTransform();
Graphics.clearCanvas(lensContext);
const data = imageData.data;
const canvasSize = new SizeF(size, size);
for (let i = 0; i < data.length; i += 4) {
const colorIndex = i / 4;
const rowNum = Math.trunc(colorIndex / size);
const columnNum = colorIndex % size;
const alpha = data[i + 3] / 255;
const whitePart = 255 * (1 - alpha);
const cd = {
r: Math.min(Math.round(data[i] * alpha + whitePart), 255),
g: Math.min(Math.round(data[i + 1] * alpha + whitePart), 255),
b: Math.min(Math.round(data[i + 2] * alpha + whitePart), 255)
};
lensContext.fillStyle = `rgba(${cd.r},${cd.g},${cd.b})`;
const rotatedPoint = RotateHandler.getRotatedPointFromSize(new PointF(columnNum, rowNum), canvasSize, 0);
lensContext.fillRect(rotatedPoint.x * this._zoom, rotatedPoint.y * this._zoom, this._zoom, this._zoom);
if (middle === rowNum && middle === columnNum) {
this._currentColorData = new RgbColor(cd.r, cd.g, cd.b, 255);
}
}
for (let i = 0; i < size; i++) {
Graphics.drawLine(lensContext, i * this._zoom, 0, i * this._zoom, lenseSize, 1, "black", 0.15);
Graphics.drawLine(lensContext, 0, i * this._zoom, lenseSize, i * this._zoom, 1, "black", 0.15);
}
ctx.globalAlpha = 1;
lensContext.lineWidth = 1;
lensContext.strokeStyle = "#000";
lensContext.strokeRect(middle * this._zoom, middle * this._zoom, this._zoom, this._zoom);
lensContext.strokeStyle = "#fff";
lensContext.strokeRect(middle * this._zoom - 1, middle * this._zoom - 1, this._zoom + 2, this._zoom + 2);
const bounds = this._canvas.viewer.surfaceHandler.getBounds(PrintAreaBoundsType.Total);
if (!bounds.contains(point, true)) {
/*this._currentColorData = null;
console.log(`_currentColorData => null`);
return;*/
}
if (this._mobileMode)
return;
const dt = this._currentColorData;
const colorString = `RGB: ${dt.r} ${dt.g} ${dt.b}`;
const stringWidth = ctx.measureText(colorString).width;
lensContext.font = "10px Roboto";
lensContext.fillStyle = "black";
const textLeft = (lenseSize - stringWidth) / 2;
lensContext.fillStyle = "rgba(0, 0, 0, 0.7)";
Graphics.drawRoundedRectangle(lensContext, new RectangleF(textLeft - this._textPadding.h, this._textYPosition - 10, stringWidth + this._textPadding.h * 2, 20), 10);
lensContext.fillStyle = "white";
lensContext.fillText(colorString, textLeft + 2, this._textYPosition + 3, lenseSize);
}
dispose() {
super.dispose();
this._viewer.setCursor(Cursor.defaultCursor);
if (this._buttonsElement != null) {
this._buttonsElement.querySelector(".accept-button").removeEventListener("click", this._onAccept);
this._buttonsElement.querySelector(".accept-button").removeEventListener("touchend", this._onAccept);
this._buttonsElement.querySelector(".reject-button").removeEventListener("click", this._onAccept);
this._buttonsElement.querySelector(".reject-button").removeEventListener("touchend", this._onAccept);
this._buttonsElement.remove();
}
if (this._canvasLensElement != null) {
this._canvasLensElement.removeEventListener("keydown", this._onKeyDown);
this._canvasLensElement.remove();
}
this._viewer.remove_onResize(this._updateView);
}
async _onLongTap(params) { }
async _onTransform(params) { }
async _onWheel(params) { }
async _onPointerDown(params) { }
async _onDoubleClick(params) { }
}
//# sourceMappingURL=SelectPixelInputHandler.js.map