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