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