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.

520 lines 27.8 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; import { RectangleF, PointF, EqualsOfFloatNumbers, RotatedRectangleF, getTriangleAngle, ConvertDegreeToRadian, getSquareDistanceToPoint } from "@aurigma/design-atoms-model/Math"; import { assign } from "@aurigma/design-atoms-model/Utils/Utils"; import { SelectionHandler } from "../Services/Selection/SelectionHandler"; import { BaseRectangleItemHandler } from "../ItemHandlers"; import { ItemUtils } from "../Utils/ItemUtils"; import { GridItemHandler } from "../ItemHandlers/GridItemHandler"; import { MockupContainer } from "@aurigma/design-atoms-model/Product"; import { SafetyLinesHandler } from "./SafetyLinesHandler"; import { SnapElementType } from "./Interfaces"; import { getRotatedRectangleWithBorder } from "../Utils/Math"; var SnapLinesHandler = /** @class */ (function () { function SnapLinesHandler(conf) { this.setConfiguration(conf); this._snapData = { xAnchors: [], yAnchors: [], defaultBounds: null, activeXAnchorIndex: null, activeYAnchorIndex: null, //points of startRectangle (in points) through which snapline can pass xPoints: [], yPoints: [], activeXPointIndex: null, activeYPointIndex: null }; } Object.defineProperty(SnapLinesHandler.prototype, "currentItemRectangle", { get: function () { return this._currentItemRectangle; }, enumerable: true, configurable: true }); SnapLinesHandler.prototype.setConfiguration = function (conf) { this._conf = assign(this._getDefaultConf, [conf || {}]); }; Object.defineProperty(SnapLinesHandler.prototype, "configuration", { get: function () { return this._conf; }, enumerable: true, configurable: true }); SnapLinesHandler.prototype.resetActiveLines = function () { this._snapData.activeXAnchorIndex = null; this._snapData.activeYAnchorIndex = null; }; SnapLinesHandler.prototype.constrainMoveDataToSnapLines = function (moveData, canvas, allowMoveHorizontal, allowMoveVertical) { this._currentItemRectangle = null; if (!this._enabled) return moveData.delta; var resultDiff = moveData.delta.clone(); this._snapData.activeXAnchorIndex = null; if (allowMoveHorizontal) { var snapResultX = this._findSnap(canvas, moveData.delta.x, moveData.momentDelta.x, this._snapData.xAnchors, this._snapData.xPoints); resultDiff.x = snapResultX.diffValue; this._snapData.activeXAnchorIndex = snapResultX.activeAnchorIndex; this._snapData.activeXPointIndex = snapResultX.activePointIndex; } this._snapData.activeYAnchorIndex = null; if (allowMoveVertical) { var snapResultY = this._findSnap(canvas, moveData.delta.y, moveData.momentDelta.y, this._snapData.yAnchors, this._snapData.yPoints); resultDiff.y = snapResultY.diffValue; this._snapData.activeYAnchorIndex = snapResultY.activeAnchorIndex; this._snapData.activeYPointIndex = snapResultY.activePointIndex; } if (moveData.startRectangle) { var curRotRect = moveData.startRectangle.clone(); curRotRect.translate(resultDiff.x, resultDiff.y); this._currentItemRectangle = getRotatedRectangleWithBorder(curRotRect, moveData.border); } return resultDiff; }; SnapLinesHandler.prototype._findSnap = function (canvas, diff, direction, anchors, points) { var result = new SnapLinesHandler.SnapResult(); result.diffValue = diff; var anchorStart = direction > 0 ? 0 : anchors.length - 1; var anchorEnd = direction > 0 ? anchors.length - 1 : 0; var anchorStep = direction > 0 ? 1 : -1; var pointStart = direction > 0 ? points.length - 1 : 0; var pointEnd = direction > 0 ? 0 : points.length - 1; var pointStep = direction > 0 ? -1 : 1; for (var anchorIndex = anchorStart; anchorIndex !== (anchorEnd + anchorStep); anchorIndex += anchorStep) { var anchor = anchors[anchorIndex]; for (var pointIndex = pointStart; pointIndex !== (pointEnd + pointStep); pointIndex += pointStep) { var yPoint = points[pointIndex]; var tolerance = this._getSnapLineTolerance(canvas, anchor.type); if (Math.abs(yPoint + diff - anchor.position) >= tolerance) continue; var oldTypeConf = result.activeAnchorIndex != null ? this._conf.snapElements[anchors[result.activeAnchorIndex].type] : null; var currentTypeConf = this._conf.snapElements[anchor.type]; if (result.activeAnchorIndex == null || currentTypeConf.priority > oldTypeConf.priority) { result.diffValue = anchor.position - yPoint; result.activeAnchorIndex = anchorIndex; result.activePointIndex = pointIndex; } } } return result; }; SnapLinesHandler.prototype.getVerticalLineData = function () { if (this._snapData.activeXAnchorIndex == null) return null; var xAnchor = this._snapData.xAnchors[this._snapData.activeXAnchorIndex]; var config = this._conf.snapElements[xAnchor.type]; return { anchor: xAnchor, config: config }; }; SnapLinesHandler.prototype.getHorizontalLineData = function () { if (this._snapData.activeYAnchorIndex == null) return null; var yAnchor = this._snapData.yAnchors[this._snapData.activeYAnchorIndex]; var config = this._conf.snapElements[yAnchor.type]; return { anchor: yAnchor, config: config }; }; SnapLinesHandler.prototype.constrainRectangleToSnapLines = function (rect, oldRectWithBorder, arbitraryResize, resizeIndex, rectWithFramesAndBorder, rectWithBorder, canvas, border) { var _this = this; this._currentItemRectangle = null; if (!this._enabled) return rect; var r = rect.clone(); this._snapData.xPoints = []; this._snapData.yPoints = []; var activePoint; //the point that the user pulls var activeFramePoint; //the point corresponding to activePoint, taking into account its frame var activePointIndex = resizeIndex - 1; if (resizeIndex > 4) { activeFramePoint = new PointF(rectWithFramesAndBorder.centerX + SelectionHandler.cw[resizeIndex] * (rectWithFramesAndBorder.width / 2), rectWithFramesAndBorder.centerY + SelectionHandler.ch[resizeIndex] * (rectWithFramesAndBorder.height / 2)); activeFramePoint.rotateAt(r.angle, rectWithFramesAndBorder.center); activePoint = new PointF(rectWithBorder.centerX + SelectionHandler.cw[resizeIndex] * (rectWithBorder.width / 2), rectWithBorder.centerY + SelectionHandler.ch[resizeIndex] * (rectWithBorder.height / 2)); activePoint.rotateAt(r.angle, rectWithBorder.center); } else { activeFramePoint = rectWithFramesAndBorder.getCornerByIndex(activePointIndex); activePoint = rectWithBorder.getCornerByIndex(activePointIndex); } var self = this; var fillSnapData = function (fillX, fillY) { if (fillX === void 0) { fillX = null; } if (fillY === void 0) { fillY = null; } fillX = fillX != null ? fillX : true; fillY = fillY != null ? fillY : true; if (!fillX && !fillY) return; var snapDataTolerance = _this._getSnapLineTolerance(canvas, SnapElementType.Items); if (fillX) { self._snapData.xPoints = [activeFramePoint.x]; if (Math.abs(activeFramePoint.x - activePoint.x) > snapDataTolerance) { self._snapData.xPoints.push(activePoint.x); } } if (fillY) { self._snapData.yPoints = [activeFramePoint.y]; if (Math.abs(activeFramePoint.y - activePoint.y) > snapDataTolerance) { self._snapData.yPoints.push(activePoint.y); } } }; var targetActivePoint; //The resulting point (it belongs to either a frame or the main rectangle) var isFrameActivePoint; if (arbitraryResize) { //When resizing the rectangle by using one of the sides, a snapline appears only if the rotation angle is a multiple of 90. if (rectWithFramesAndBorder.angle % 90 !== 0 && resizeIndex > 4) { return rect; } var center = r.center; //When resizing the rectangle by using sides and rotating at 90 or 270 degrees, we will swap the Width and Height for convenience. var isReverse = resizeIndex > 4 && (r.angle - 90) % 180 === 0; fillSnapData(SelectionHandler.cw[resizeIndex] !== (0 ^ (isReverse ? 1 : 0)), SelectionHandler.ch[resizeIndex] !== (0 ^ (isReverse ? 1 : 0))); var moveData = { delta: new PointF(), momentDelta: new PointF(), startPoint: activeFramePoint, border: border }; var snapLinesDiff = this.constrainMoveDataToSnapLines(moveData, canvas, true, true); if (snapLinesDiff == null || (EqualsOfFloatNumbers(snapLinesDiff.x, 0, 0.1) && EqualsOfFloatNumbers(snapLinesDiff.y, 0, 0.01))) { return rect; } isFrameActivePoint = snapLinesDiff.x !== 0 && this._snapData.activeXPointIndex === 0 || snapLinesDiff.y !== 0 && this._snapData.activeYPointIndex === 0; targetActivePoint = isFrameActivePoint ? activeFramePoint : activePoint; var snapPoint = new PointF(targetActivePoint.x + snapLinesDiff.x, targetActivePoint.y + snapLinesDiff.y); var angle = r.angle; snapPoint.rotateAt(-angle, center); targetActivePoint.rotateAt(-r.angle, center); r.angle = 0; var arbitraryResizeDiff = new PointF((snapPoint.x - targetActivePoint.x) * (isFrameActivePoint ? (r.width / rectWithFramesAndBorder.width) : 1), (snapPoint.y - targetActivePoint.y) * (isFrameActivePoint ? (r.height / rectWithFramesAndBorder.height) : 1)); r.centerX += (arbitraryResizeDiff.x / 2); r.width += SelectionHandler.cw[resizeIndex] * arbitraryResizeDiff.x; r.centerY += (arbitraryResizeDiff.y / 2); r.height += SelectionHandler.ch[resizeIndex] * arbitraryResizeDiff.y; r.rotateAt(angle, center); } else if (!arbitraryResize) { if (oldRectWithBorder.getCornerByIndex(activePointIndex).equals(activePoint, 0.01)) { return rect; } fillSnapData(); var moveData = { delta: new PointF(), momentDelta: new PointF(), startPoint: activePoint, border: border }; var proportionalLinesDiff = this.constrainMoveDataToSnapLines(moveData, canvas, true, true); var ifXDiffIsZero = EqualsOfFloatNumbers(proportionalLinesDiff.x, 0, 0.01); var ifYDiffIsZero = EqualsOfFloatNumbers(proportionalLinesDiff.y, 0, 0.01); if (ifXDiffIsZero && ifYDiffIsZero) { return rect; } isFrameActivePoint = !ifXDiffIsZero && this._snapData.activeXPointIndex === 0 || !ifYDiffIsZero && this._snapData.activeYPointIndex === 0; targetActivePoint = isFrameActivePoint ? activeFramePoint : activePoint; //at the proportional resize we find a static point opposite to the active point. var staticPointIndex = (activePointIndex + 2) % 4; //the opposite index var staticPoint = rectWithBorder.getCornerByIndex(staticPointIndex); //Projection of the static point on the snap line. It's needed to find the angle of the resize direction. var projectionPoint; if (!ifXDiffIsZero) { projectionPoint = new PointF(targetActivePoint.x + proportionalLinesDiff.x, staticPoint.y); } else { projectionPoint = new PointF(staticPoint.x, targetActivePoint.y + proportionalLinesDiff.y); } //Find an angle near the static point for the resize direction. var triangleAngleInDegrees = getTriangleAngle(projectionPoint, targetActivePoint, staticPoint); var triangleAngle = ConvertDegreeToRadian(triangleAngleInDegrees); //Find the difference between the hypotenuse of the triangle and resize the rectangle. var newHypotenuseWidth = Math.sqrt(getSquareDistanceToPoint(staticPoint, projectionPoint)) / Math.cos(triangleAngle); var oldHypotenuseWidth = Math.sqrt(getSquareDistanceToPoint(staticPoint, targetActivePoint)); var multiplier = newHypotenuseWidth / oldHypotenuseWidth; if (multiplier == null) { return rect; } var oldStaticPoint = r.getCornerByIndex(staticPointIndex); r.width *= multiplier; r.height *= multiplier; var newStaticPoint = r.getCornerByIndex(staticPointIndex); r.centerX += (oldStaticPoint.x - newStaticPoint.x); r.centerY += (oldStaticPoint.y - newStaticPoint.y); } this._currentItemRectangle = getRotatedRectangleWithBorder(r.clone(), border); return r; }; SnapLinesHandler.prototype.fillSnapData = function (startRectangle, startRectangleWithFrames, startRectangleWithBorder, region, interactiveZonesBounds, canvas /*TODO: replace to ProductHandler after refactoring ending*/, isDrag) { var _a; this.clearSnapData(); var printArea = canvas.viewer.surface.printAreas.get(0); if (printArea == null) return; this._snapData.defaultBounds = canvas.viewer.surface.printAreas.get(0).bounds; if (!this._enabled || startRectangle == null) return; var xAnchors = [], yAnchors = []; var getRectLimitPoints = function (rect) { return { vertical: [rect.top, rect.bottom], horizontal: [rect.left, rect.right] }; }; var addRectangleToAnchors = function (rectangle, snapElementType, addCenter) { var cornerPoints = [rectangle.getUpperLeftCorner(), rectangle.getUpperRightCorner(), rectangle.getBottomLeftCorner(), rectangle.getBottomRightCorner()]; var points = addCenter ? __spread(cornerPoints, [rectangle.center]) : cornerPoints; var bounds = rectangle.bounds; var center = rectangle.center; var byx = new Map(); var byy = new Map(); points.forEach(function (pt) { if (region != null && canvas.suppressOutOfRegionManipulation && !region.contains(pt, true)) return; if (EqualsOfFloatNumbers(pt.x, center.x)) { var anchor = { position: pt.x, limitPoints: [bounds.bottom, bounds.top], type: snapElementType }; byx.set(pt.x, anchor); } else if (EqualsOfFloatNumbers(pt.x, bounds.left) || EqualsOfFloatNumbers(pt.x, bounds.right)) { if (!byx.has(pt.x)) { var anchor = { position: pt.x, limitPoints: [pt.y], type: snapElementType }; byx.set(pt.x, anchor); } else { var anchor = byx.get(pt.x); anchor.limitPoints = __spread(anchor.limitPoints, [pt.y]); } } if (EqualsOfFloatNumbers(pt.y, center.y)) { var anchor = { position: pt.y, limitPoints: [bounds.left, bounds.right], type: snapElementType }; byy.set(pt.y, anchor); } else if (EqualsOfFloatNumbers(pt.y, bounds.top) || EqualsOfFloatNumbers(pt.y, bounds.bottom)) { if (!byy.has(pt.y)) { var anchor = { position: pt.y, limitPoints: [pt.x], type: snapElementType }; byy.set(pt.y, anchor); } else { var anchor = byy.get(pt.y); anchor.limitPoints = __spread(anchor.limitPoints, [pt.x]); } } }); xAnchors.push.apply(xAnchors, __spread(byx.values())); yAnchors.push.apply(yAnchors, __spread(byy.values())); }; var addBoundsToAnchors = function (bounds, snapElementType) { var rectangle = region != null && canvas.suppressOutOfRegionManipulation ? RectangleF.intersect(bounds, region) : bounds; if (!rectangle.isEmpty()) { var limitPoints = getRectLimitPoints(rectangle); xAnchors.push({ position: rectangle.left, limitPoints: limitPoints.vertical, rect: rectangle, type: snapElementType }, { position: rectangle.left + rectangle.width / 2, limitPoints: limitPoints.vertical, rect: rectangle, type: snapElementType }, { position: rectangle.right, limitPoints: limitPoints.vertical, rect: rectangle, type: snapElementType }); yAnchors.push({ position: rectangle.top, limitPoints: limitPoints.horizontal, type: snapElementType }, { position: rectangle.top + rectangle.height / 2, limitPoints: limitPoints.horizontal, type: snapElementType }, { position: rectangle.bottom, limitPoints: limitPoints.horizontal, type: snapElementType }); } }; var snapConf = this._conf.snapElements; if (region != null && snapConf.region.enabled) addBoundsToAnchors(region, SnapElementType.Region); if (this._snapData.defaultBounds != null && snapConf.printArea.enabled) addBoundsToAnchors(this._snapData.defaultBounds, SnapElementType.PrintArea); if (interactiveZonesBounds != null && snapConf.interactiveZones.enabled) { interactiveZonesBounds.forEach(function (x) { addBoundsToAnchors(x, SnapElementType.InteractiveZones); }); } var blackListFilter = function (handler) { return handler instanceof GridItemHandler || //skip grid handler.item.parentContainer instanceof MockupContainer || // skip mockup ItemUtils.isBgContainerItem(handler.item) || ItemUtils.isFgContainerItem(handler.item); //skip bg and fg containers }; var snapableItemHandlers = canvas.getAllItemHandlers({ onlyVisible: true, onlyUnlocked: !snapConf.items.includeLocked, whiteListFilter: SafetyLinesHandler.isSafetyLineItemHandler, blackListFilter: blackListFilter, flatGroupItems: true }); if (snapConf.items.enabled || snapConf.safetyLines.enabled) { snapableItemHandlers.forEach(function (itemHandler) { if (!itemHandler.layer.visible) return; if (SafetyLinesHandler.isSafetyLineItemHandler(itemHandler)) { if (!snapConf.safetyLines.enabled) return; if (itemHandler.item.name === SafetyLinesHandler.handlerPrefix + "_region_shape") return; var point0 = itemHandler.controlPoints[0]; var point1 = itemHandler.controlPoints[1]; addRectangleToAnchors(RotatedRectangleF.fromRectangleF(RectangleF.fromPoints(point0, point1)), SnapElementType.SafetyLines, false); } else if (!canvas.isItemHandlerSelected(itemHandler) && snapConf.items.enabled) { if (itemHandler instanceof BaseRectangleItemHandler) { var margin = itemHandler.getBorderMargin(); var border = { left: margin, top: margin, right: margin, bottom: margin }; var rectWithBorder = getRotatedRectangleWithBorder(itemHandler.getSelectionRectangle(), border); addRectangleToAnchors(rectWithBorder, SnapElementType.Items, true); } } }); } if (((_a = snapConf.grid) === null || _a === void 0 ? void 0 : _a.enabled) && canvas.viewer.gridHandler.visible) { var grid = canvas.viewer.gridHandler.getGridParameters(); if (grid != null) { for (var i = 0; i <= grid.cols; i++) { xAnchors.push({ position: grid.location.x + i * grid.stepX, type: SnapElementType.Grid }); } for (var i = 0; i <= grid.rows; i++) { yAnchors.push({ position: grid.location.y + i * grid.stepY, type: SnapElementType.Grid }); } } } var sortAndRemoveDuplicatesFromAnchorArray = function (array, tolerance) { if (tolerance === void 0) { tolerance = null; } var sortedArray = array.sort(function (a, b) { return a.position - b.position; }); var result = []; sortedArray.forEach(function (value, index) { var lastElement = result.slice(-1)[0]; if (index === 0 || !EqualsOfFloatNumbers(lastElement.position, value.position, tolerance != null ? tolerance : 0.01) || lastElement.type !== value.type) result.push(value); }); return result; }; var sortAndRemoveDuplicates = function (array, tolerance) { if (tolerance === void 0) { tolerance = null; } var sortedArray = array.sort(function (a, b) { return a - b; }); var result = []; sortedArray.forEach(function (value, index) { if (index === 0 || !EqualsOfFloatNumbers(result.slice(-1)[0], value, tolerance != null ? tolerance : 0.01)) result.push(value); }); return result; }; this._snapData.xAnchors = sortAndRemoveDuplicatesFromAnchorArray(xAnchors); this._snapData.yAnchors = sortAndRemoveDuplicatesFromAnchorArray(yAnchors); if (!isDrag) return; var startRectangleWithFramesAndBorder = startRectangleWithFrames.bounds; this._snapData.xPoints = [ startRectangleWithBorder.left, startRectangle.centerX, startRectangleWithBorder.right ]; this._snapData.yPoints = [ startRectangleWithBorder.top, startRectangle.centerY, startRectangleWithBorder.bottom ]; var snapDataTolerance = this._getSnapLineTolerance(canvas, SnapElementType.Items); this._snapData.xPoints = sortAndRemoveDuplicates([ startRectangleWithFramesAndBorder.left, startRectangleWithBorder.left, startRectangleWithFrames.centerX, startRectangle.centerX, startRectangleWithBorder.right, startRectangleWithFramesAndBorder.right ], snapDataTolerance); this._snapData.yPoints = sortAndRemoveDuplicates([ startRectangleWithFramesAndBorder.top, startRectangleWithBorder.top, startRectangleWithFrames.centerY, startRectangle.centerY, startRectangleWithBorder.bottom, startRectangleWithFramesAndBorder.bottom ], snapDataTolerance); }; SnapLinesHandler.prototype.clearSnapData = function () { this._snapData.xAnchors = []; this._snapData.yAnchors = []; this._snapData.activeXAnchorIndex = null; this._snapData.activeYAnchorIndex = null; this._snapData.xPoints = []; this._snapData.yPoints = []; }; SnapLinesHandler.prototype._getSnapLineTolerance = function (canvas, snapElementType) { return Math.abs(this._conf.snapElements[snapElementType.toString()].tolerance / canvas.zoom); }; Object.defineProperty(SnapLinesHandler.prototype, "_getDefaultConf", { get: function () { var defaultElementConf = { tolerance: 5, color: "rgb(255,0,255)", enabled: false, priority: 0 }; return { snapElements: { items: __assign(__assign({}, defaultElementConf), { includeLocked: false }), printArea: __assign({}, defaultElementConf), safetyLines: __assign({}, defaultElementConf), region: __assign({}, defaultElementConf), grid: __assign({}, defaultElementConf) } }; }, enumerable: true, configurable: true }); Object.defineProperty(SnapLinesHandler.prototype, "_enabled", { get: function () { var snapElements = this._conf.snapElements; return snapElements.items.enabled || snapElements.printArea.enabled || snapElements.region.enabled || snapElements.safetyLines.enabled || snapElements.grid.enabled; }, enumerable: true, configurable: true }); SnapLinesHandler.SnapResult = /** @class */ (function () { function class_1() { this.diffValue = null; this.activeAnchorIndex = null; this.activePointIndex = null; } return class_1; }()); return SnapLinesHandler; }()); export { SnapLinesHandler }; //# sourceMappingURL=SnapLinesHandler.js.map