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.

322 lines 17.9 kB
import { RotatedRectangleF, PointF, RectangleF, EqualsOfFloatNumbers, normalizeAngle, SizeF, ConvertDegreeToRadian } from "@aurigma/design-atoms-model/Math"; import { PlaceholderItemHandler, BaseRectangleItemHandler } from "../../ItemHandlers"; import { getRotatedRectangleWithBorder } from "../../Utils/Math"; import { MinDpiResizeConstraint } from "./Constraints/Resize/MinDpiResizeConstraint"; export class SelectionProcessModifier { constructor(_selectionHandler, _canvas, _snapLinesHandler) { this._selectionHandler = _selectionHandler; this._canvas = _canvas; this._snapLinesHandler = _snapLinesHandler; this._minDpiResizeConstraint = new MinDpiResizeConstraint(); } set ignoreSnapLines(value) { this._ignoreSnapLines = value; } beforeMovePerformed(data) { var _a; const contentEditingPlaceholderItemHandler = this._canvas.contentEditingPlaceholderItemHandler; let result = data.delta; if (this._ignoreSnapLines) { this._snapLinesHandler.resetActiveLines(); } else if (this._canvas.contentEditingPlaceholderItemHandler == null) { const perms = this._selectionHandler.manipulationPermissions; data.border = this._selectionHandler.border; result = this._snapLinesHandler.constrainMoveDataToSnapLines(data, this._canvas, perms.allowMoveHorizontal, perms.allowMoveVertical); } const startRectWithFrames = this.getRectWithFrames(data.startRectangle); if (contentEditingPlaceholderItemHandler == null) { result = this._constrainMoveDataToRegion(startRectWithFrames.bounds, result); } else if (contentEditingPlaceholderItemHandler.item.isCoverMode) { result = this._constrainMoveDataToPlaceholderCover(data.startRectangle, contentEditingPlaceholderItemHandler.rectangle, result); } return (_a = result !== null && result !== void 0 ? result : data.delta) !== null && _a !== void 0 ? _a : data.momentDelta; } beforeResizePerformed(data) { var _a, _b; let result = null; const contentEditingPlaceholderItemHandler = this._canvas.contentEditingPlaceholderItemHandler; if (contentEditingPlaceholderItemHandler != null && contentEditingPlaceholderItemHandler.item.isCoverMode) { result = this._constrainResizeDataToPlaceholderCover(data.currentRect, data.startRectangle, contentEditingPlaceholderItemHandler.rectangle, data.resizeIndex); } const { minWidth, minHeight } = this._getMinSizeConstraintConfiguration(data.startRectangle, data.startItemHandlersRects); result = this._constrainResizeDataToMinSize(data.startRectangle, result !== null && result !== void 0 ? result : data.currentRect, data.arbitraryResize, data.resizeIndex, minWidth, minHeight); if (this._canvas.contentEditingPlaceholderItemHandler == null) result = this._constrainResizeDataToSnapLines(data, result !== null && result !== void 0 ? result : data.currentRect); const minDpi = (_b = (_a = this._canvas.viewer.configuration) === null || _a === void 0 ? void 0 : _a.handlers) === null || _b === void 0 ? void 0 : _b.imageMinDpi; if (minDpi != null) result = this._minDpiResizeConstraint.applyTo(result !== null && result !== void 0 ? result : data.currentRect, data, minDpi); result = result !== null && result !== void 0 ? result : data.currentRect; return this._validateRectRelativeToRegion(result) ? result : data.previousRectangle; } beforeRotatePerformed(data) { return this._validateRectRelativeToRegion(data.currentRect) ? data.currentRect : data.previousRectangle; } getRectWithFrames(rectangle) { const itemHandlers = this._selectionHandler.selectedItemHandlers; var rectWithFrames = this.getRectangleWithBorder(rectangle); for (let j = 0; j < itemHandlers.length; j++) { const itemHandler = itemHandlers.getItem(j); if (itemHandler == null || !(itemHandler instanceof PlaceholderItemHandler)) continue; const placeholderRectWithFrames = itemHandler.getRectangleIncludingFrames(); const updatedPlaceholderRectWithFrames = BaseRectangleItemHandler.transformRectangleByTwoRectanglesDiff(placeholderRectWithFrames, this._selectionHandler.rectangle, rectangle); rectWithFrames = RotatedRectangleF.union(updatedPlaceholderRectWithFrames, rectWithFrames); } return rectWithFrames; } getRectangleWithBorder(rectangle) { const border = this._selectionHandler.border; return getRotatedRectangleWithBorder(rectangle, border); } get _region() { return this._selectionHandler.region; } _validateRectRelativeToRegion(rect) { if (!this._canvas.suppressOutOfRegionManipulation || this._canvas.contentEditingPlaceholderItemHandler != null || this._region == null) return true; const extendedRectBounds = this.getRectWithFrames(rect).bounds; return this._region.containsRectangle(extendedRectBounds); } _constrainMoveDataToRegion(bounds, diff) { if (!this._canvas.suppressOutOfRegionManipulation || this._region == null) return diff; if (bounds.left + diff.x < this._region.left) diff.x = this._region.left - bounds.left; if (bounds.top + diff.y < this._region.top) diff.y = this._region.top - bounds.top; if (bounds.right + diff.x > this._region.left + this._region.width) diff.x = this._region.left + this._region.width - bounds.right; if (bounds.bottom + diff.y > this._region.top + this._region.height) diff.y = this._region.top + this._region.height - bounds.bottom; return diff; } _constrainMoveDataToPlaceholderCover(placeholderContentRectangle, placeholderRectangle, diff) { var angle = placeholderRectangle.angle; placeholderRectangle.angle = 0; var placeholderBounds = placeholderRectangle.bounds; var placeholderContentRectangleWithoutAngle = placeholderContentRectangle.clone(); placeholderContentRectangleWithoutAngle.rotateAt(-angle, placeholderRectangle.center); var placeholderContentBounds = placeholderContentRectangleWithoutAngle.bounds; diff.rotate(-angle); if (placeholderContentBounds.left + diff.x > placeholderBounds.left) diff.x = placeholderBounds.left - placeholderContentBounds.left; if (placeholderContentBounds.top + diff.y > placeholderBounds.top) diff.y = placeholderBounds.top - placeholderContentBounds.top; if (placeholderContentBounds.right + diff.x < placeholderBounds.left + placeholderBounds.width) diff.x = placeholderBounds.left + placeholderBounds.width - placeholderContentBounds.right; if (placeholderContentBounds.bottom + diff.y < placeholderBounds.top + placeholderBounds.height) diff.y = placeholderBounds.top + placeholderBounds.height - placeholderContentBounds.bottom; diff.rotate(angle); return diff; } _constrainResizeDataToPlaceholderCover(r, startRectangle, placeholderRectangle, resizeIndex) { const contentAngle = r.angle; var angle = placeholderRectangle.angle; const isContentAngleRotatedOn90Or270 = EqualsOfFloatNumbers(90, normalizeAngle(contentAngle - angle) % 180); placeholderRectangle.angle = 0; var placeholderBounds = placeholderRectangle.bounds; r.rotateAt(-angle, placeholderRectangle.center); var rectangleBounds = r.bounds; var left = Math.min(rectangleBounds.left, placeholderBounds.left); var top = Math.min(rectangleBounds.top, placeholderBounds.top); var right = Math.max(rectangleBounds.right, placeholderBounds.right); var bottom = Math.max(rectangleBounds.bottom, placeholderBounds.bottom); var width = right - left; var height = bottom - top; var xyScale = isContentAngleRotatedOn90Or270 ? startRectangle.height / startRectangle.width : startRectangle.width / startRectangle.height; var curXyScale = width / height; var grip = (((resizeIndex - 1) + Math.round(normalizeAngle(contentAngle - angle) / 90)) % 4) + 1; if (curXyScale > xyScale) { var dh = Math.abs(width / xyScale - width / curXyScale); if (grip === 1 || grip === 2) top = top - dh; else // 3 || 4 bottom = bottom + dh; } if (curXyScale < xyScale) { var dw = Math.abs(height * xyScale - height * curXyScale); if (grip === 2 || grip === 3) right = right + dw; else // 1 || 4 left = left - dw; } var rf = new RectangleF(left, top, right - left, bottom - top); if (!EqualsOfFloatNumbers(0, contentAngle - angle % 360)) { var rotatedRectangle = RotatedRectangleF.fromRectangleF(rf); rotatedRectangle.rotateAt(angle - contentAngle, placeholderRectangle.center); rf = rotatedRectangle.bounds; } var result = RotatedRectangleF.fromRectangleF(rf); result.rotateAt(contentAngle, placeholderRectangle.center); return result; } _getMinSizeConstraintConfiguration(startRect, handlersRects) { const getHandlerMinSize = (e) => { var _a, _b; let resizeLimitConfig = (_b = (_a = this._canvas.viewer.configuration) === null || _a === void 0 ? void 0 : _a.handlers) === null || _b === void 0 ? void 0 : _b.resizeLimits; if (resizeLimitConfig) { for (let prop in resizeLimitConfig) { if (`${prop}Item`.toLowerCase() == e.itemType.toLowerCase()) return resizeLimitConfig[prop]; } } if ((resizeLimitConfig === null || resizeLimitConfig === void 0 ? void 0 : resizeLimitConfig.common) != null) return resizeLimitConfig.common; return new SizeF(null, null); }; const calcResizeWidthCoeff = (elementStartRect, deltaAngleRad) => { let cos = Math.abs(Math.cos(deltaAngleRad)); let sin = Math.abs(Math.sin(deltaAngleRad)); let projectedWidth = cos * elementStartRect.width; let projectedHeight = sin * elementStartRect.width; return { projectedWidth, projectedHeight, cos, sin }; }; const calcResizeHeightCoeff = (elementStartRect, deltaAngleRad) => { let cos = Math.abs(Math.cos(deltaAngleRad)); let sin = Math.abs(Math.sin(deltaAngleRad)); let projectedHeight = cos * elementStartRect.height; let projectedWidth = sin * elementStartRect.height; return { projectedWidth, projectedHeight, cos, sin }; }; let globalMinWidth = null; let globalMinHeight = null; handlersRects.forEach(element => { let minSize = getHandlerMinSize(element); let deltaAngle = (element.startRectangle.angle - startRect.angle) % 180; let deltaAngleRad = ConvertDegreeToRadian(deltaAngle); let fromWidthCoeff = calcResizeWidthCoeff(element.startRectangle, deltaAngleRad); if (!EqualsOfFloatNumbers(fromWidthCoeff.cos, 0) && minSize.width !== null) { let minPw = fromWidthCoeff.cos * minSize.width; let minGw = minPw * startRect.width / fromWidthCoeff.projectedWidth; if (globalMinWidth == null || globalMinWidth < minGw) globalMinWidth = minGw; } if (!EqualsOfFloatNumbers(fromWidthCoeff.sin, 0) && minSize.width !== null) { let minPh = minSize.width * fromWidthCoeff.sin; let minGh = minPh * startRect.height / fromWidthCoeff.projectedHeight; if (globalMinWidth == null || globalMinWidth < minGh) globalMinHeight = minGh; } let fromHeightCoeff = calcResizeHeightCoeff(element.startRectangle, deltaAngleRad); if (!EqualsOfFloatNumbers(fromHeightCoeff.cos, 0) && minSize.height !== null) { let minPh = minSize.height * fromHeightCoeff.cos; let minGh = minPh * startRect.height / fromHeightCoeff.projectedHeight; if (globalMinHeight == null || globalMinHeight < minGh) globalMinHeight = minGh; } if (!EqualsOfFloatNumbers(fromHeightCoeff.sin, 0) && minSize.height !== null) { let minPw = minSize.height * fromHeightCoeff.sin; let minGw = minPw * startRect.width / fromHeightCoeff.projectedWidth; if (globalMinHeight == null || globalMinHeight < minGw) globalMinHeight = minGw; } }); return { minWidth: globalMinWidth, minHeight: globalMinHeight }; } _constrainResizeDataToMinSize(startRect, rect, arbitraryResize, resizeIndex, minWidth, minHeight) { minWidth = Math.min(minWidth, startRect.width); minHeight = Math.min(minHeight, startRect.height); const resultRect = rect.clone(); let inverseWidth = false; let inverseHeight = false; if (resultRect.width < 0) inverseWidth = true; if (resultRect.height < 0) inverseHeight = true; let whRatio = startRect.width / startRect.height; let { resultWidth, resultHeight, isChanged } = this._calculateMinWidthAndHeight(Math.abs(rect.width), Math.abs(rect.height), minWidth, minHeight, whRatio, arbitraryResize); if (isChanged) { resultRect.width = inverseWidth ? -resultWidth : resultWidth; resultRect.height = inverseHeight ? -resultHeight : resultHeight; this._alignRectangleWithStartRectangle(startRect, resultRect, resizeIndex); } return resultRect; } _calculateMinWidthAndHeight(curWidth, curHeight, minWidth, minHeight, whRatio, arbitraryResize) { let resultWidth = curWidth; let resultHeight = curHeight; let isChangedWidth = false; let isChangedHeight = false; if (resultWidth < minWidth) { resultWidth = minWidth; isChangedWidth = true; } if (resultHeight < minHeight) { resultHeight = minHeight; isChangedHeight = true; } const isChanged = isChangedHeight || isChangedWidth; if (isChanged && !arbitraryResize) { const correctWidth = (h) => h * whRatio; const correctHeight = (w) => w * (1 / whRatio); if (isChangedWidth) { resultHeight = correctHeight(resultWidth); if (resultHeight < minHeight) { resultHeight = minHeight; resultWidth = correctWidth(resultHeight); } } else if (isChangedHeight) { resultWidth = correctWidth(resultHeight); if (resultWidth < minWidth) { resultWidth = minWidth; resultHeight = correctHeight(resultWidth); } } } return { resultWidth: resultWidth, resultHeight: resultHeight, isChanged: isChanged }; } _alignRectangleWithStartRectangle(startRect, rect, resizeIndex) { // resize index // 1 6 2 // 5 7 // 4 8 3 let startPoint; let rectPoint; switch (resizeIndex) { case 1: startPoint = startRect.getBottomRightCorner(); rectPoint = rect.getBottomRightCorner(); break; case 2: startPoint = startRect.getBottomLeftCorner(); rectPoint = rect.getBottomLeftCorner(); break; case 3: startPoint = startRect.getUpperLeftCorner(); rectPoint = rect.getUpperLeftCorner(); break; case 4: startPoint = startRect.getUpperRightCorner(); rectPoint = rect.getUpperRightCorner(); break; case 5: startPoint = startRect.getRightCenterPoint(); rectPoint = rect.getRightCenterPoint(); break; case 6: startPoint = startRect.getBottomCenterPoint(); rectPoint = rect.getBottomCenterPoint(); break; case 7: startPoint = startRect.getLeftCenterPoint(); rectPoint = rect.getLeftCenterPoint(); break; case 8: startPoint = startRect.getUpperCenterPoint(); rectPoint = rect.getUpperCenterPoint(); break; } let diff = new PointF(startPoint.x - rectPoint.x, startPoint.y - rectPoint.y); rect.translate(diff.x, diff.y); } _constrainResizeDataToSnapLines(params, currentRect) { return this._snapLinesHandler.constrainRectangleToSnapLines(currentRect, this.getRectangleWithBorder(params.previousRectangle), params.arbitraryResize, params.resizeIndex, this.getRectWithFrames(currentRect), this.getRectangleWithBorder(currentRect), this._canvas, this._selectionHandler.border); } } //# sourceMappingURL=SelectionProcessModifier.js.map