UNPKG

@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
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