|
@@ -3,17 +3,21 @@ import { SHIFT_LOCKING_ANGLE } from "../constants";
|
|
|
import { getSelectedElements, globalSceneState } from "../scene";
|
|
|
import { rescalePoints } from "../points";
|
|
|
|
|
|
-import { rotate, resizeXYWidthHightWithRotation } from "../math";
|
|
|
+import { rotate, adjustXYWithRotation, getFlipAdjustment } from "../math";
|
|
|
import {
|
|
|
ExcalidrawLinearElement,
|
|
|
NonDeletedExcalidrawElement,
|
|
|
NonDeleted,
|
|
|
ResizeArrowFnType,
|
|
|
} from "./types";
|
|
|
-import { getElementAbsoluteCoords, getCommonBounds } from "./bounds";
|
|
|
+import {
|
|
|
+ getElementAbsoluteCoords,
|
|
|
+ getCommonBounds,
|
|
|
+ getResizedElementAbsoluteCoords,
|
|
|
+} from "./bounds";
|
|
|
import { isLinearElement } from "./typeChecks";
|
|
|
import { mutateElement } from "./mutateElement";
|
|
|
-import { getPerfectElementSize, normalizeDimensions } from "./sizeHelpers";
|
|
|
+import { getPerfectElementSize } from "./sizeHelpers";
|
|
|
import {
|
|
|
resizeTest,
|
|
|
getCursorForResizingElement,
|
|
@@ -26,6 +30,155 @@ import {
|
|
|
|
|
|
type ResizeTestType = ReturnType<typeof resizeTest>;
|
|
|
|
|
|
+export const resizeElements = (
|
|
|
+ resizeHandle: ResizeTestType,
|
|
|
+ setResizeHandle: (nextResizeHandle: ResizeTestType) => void,
|
|
|
+ appState: AppState,
|
|
|
+ setAppState: (obj: any) => void,
|
|
|
+ resizeArrowFn: ResizeArrowFnType | null, // XXX eliminate in #1339
|
|
|
+ setResizeArrowFn: (fn: ResizeArrowFnType) => void, // XXX eliminate in #1339
|
|
|
+ event: PointerEvent, // XXX we want to make it independent?
|
|
|
+ xPointer: number,
|
|
|
+ yPointer: number,
|
|
|
+ lastX: number, // XXX eliminate in #1339
|
|
|
+ lastY: number, // XXX eliminate in #1339
|
|
|
+) => {
|
|
|
+ setAppState({
|
|
|
+ isResizing: resizeHandle && resizeHandle !== "rotation",
|
|
|
+ isRotating: resizeHandle === "rotation",
|
|
|
+ });
|
|
|
+ const selectedElements = getSelectedElements(
|
|
|
+ globalSceneState.getElements(),
|
|
|
+ appState,
|
|
|
+ );
|
|
|
+ const handleOffset = 4 / appState.zoom; // XXX import constant
|
|
|
+ const dashedLinePadding = 4 / appState.zoom; // XXX import constant
|
|
|
+ const offsetPointer = handleOffset + dashedLinePadding;
|
|
|
+ if (selectedElements.length === 1) {
|
|
|
+ const [element] = selectedElements;
|
|
|
+ if (resizeHandle === "rotation") {
|
|
|
+ rotateSingleElement(element, xPointer, yPointer, event.shiftKey);
|
|
|
+ } else if (
|
|
|
+ isLinearElement(element) &&
|
|
|
+ element.points.length === 2 &&
|
|
|
+ (resizeHandle === "nw" ||
|
|
|
+ resizeHandle === "ne" ||
|
|
|
+ resizeHandle === "sw" ||
|
|
|
+ resizeHandle === "se")
|
|
|
+ ) {
|
|
|
+ resizeSingleTwoPointElement(
|
|
|
+ element,
|
|
|
+ resizeHandle,
|
|
|
+ resizeArrowFn,
|
|
|
+ setResizeArrowFn,
|
|
|
+ event.shiftKey,
|
|
|
+ xPointer,
|
|
|
+ yPointer,
|
|
|
+ lastX,
|
|
|
+ lastY,
|
|
|
+ );
|
|
|
+ } else if (resizeHandle) {
|
|
|
+ resizeSingleElement(
|
|
|
+ element,
|
|
|
+ resizeHandle,
|
|
|
+ getResizeWithSidesSameLengthKey(event),
|
|
|
+ getResizeCenterPointKey(event),
|
|
|
+ xPointer,
|
|
|
+ yPointer,
|
|
|
+ offsetPointer,
|
|
|
+ );
|
|
|
+ setResizeHandle(normalizeResizeHandle(element, resizeHandle));
|
|
|
+ if (element.width < 0) {
|
|
|
+ mutateElement(element, { width: -element.width });
|
|
|
+ }
|
|
|
+ if (element.height < 0) {
|
|
|
+ mutateElement(element, { height: -element.height });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // XXX do we need this?
|
|
|
+ document.documentElement.style.cursor = getCursorForResizingElement({
|
|
|
+ element,
|
|
|
+ resizeHandle,
|
|
|
+ });
|
|
|
+ // XXX why do we need this?
|
|
|
+ if (appState.resizingElement) {
|
|
|
+ mutateElement(appState.resizingElement, {
|
|
|
+ x: element.x,
|
|
|
+ y: element.y,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } else if (
|
|
|
+ selectedElements.length > 1 &&
|
|
|
+ (resizeHandle === "nw" ||
|
|
|
+ resizeHandle === "ne" ||
|
|
|
+ resizeHandle === "sw" ||
|
|
|
+ resizeHandle === "se")
|
|
|
+ ) {
|
|
|
+ resizeMultipleElements(
|
|
|
+ selectedElements,
|
|
|
+ resizeHandle,
|
|
|
+ xPointer,
|
|
|
+ yPointer,
|
|
|
+ offsetPointer,
|
|
|
+ );
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+};
|
|
|
+
|
|
|
+const rotateSingleElement = (
|
|
|
+ element: NonDeletedExcalidrawElement,
|
|
|
+ xPointer: number,
|
|
|
+ yPointer: number,
|
|
|
+ isAngleLocking: boolean,
|
|
|
+) => {
|
|
|
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
|
+ const cx = (x1 + x2) / 2;
|
|
|
+ const cy = (y1 + y2) / 2;
|
|
|
+ let angle = (5 * Math.PI) / 2 + Math.atan2(yPointer - cy, xPointer - cx);
|
|
|
+ if (isAngleLocking) {
|
|
|
+ angle += SHIFT_LOCKING_ANGLE / 2;
|
|
|
+ angle -= angle % SHIFT_LOCKING_ANGLE;
|
|
|
+ }
|
|
|
+ if (angle >= 2 * Math.PI) {
|
|
|
+ angle -= 2 * Math.PI;
|
|
|
+ }
|
|
|
+ mutateElement(element, { angle });
|
|
|
+};
|
|
|
+
|
|
|
+const resizeSingleTwoPointElement = (
|
|
|
+ element: NonDeleted<ExcalidrawLinearElement>,
|
|
|
+ resizeHandle: "nw" | "ne" | "sw" | "se",
|
|
|
+ resizeArrowFn: ResizeArrowFnType | null,
|
|
|
+ setResizeArrowFn: (fn: ResizeArrowFnType) => void,
|
|
|
+ sidesWithSameLength: boolean,
|
|
|
+ xPointer: number,
|
|
|
+ yPointer: number,
|
|
|
+ lastX: number,
|
|
|
+ lastY: number,
|
|
|
+) => {
|
|
|
+ const [, [px, py]] = element.points;
|
|
|
+ const isResizeEnd =
|
|
|
+ (resizeHandle === "nw" && (px < 0 || py < 0)) ||
|
|
|
+ (resizeHandle === "ne" && px >= 0) ||
|
|
|
+ (resizeHandle === "sw" && px <= 0) ||
|
|
|
+ (resizeHandle === "se" && (px > 0 || py > 0));
|
|
|
+ applyResizeArrowFn(
|
|
|
+ element,
|
|
|
+ resizeArrowFn,
|
|
|
+ setResizeArrowFn,
|
|
|
+ isResizeEnd,
|
|
|
+ sidesWithSameLength,
|
|
|
+ xPointer,
|
|
|
+ yPointer,
|
|
|
+ lastX,
|
|
|
+ lastY,
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
const arrowResizeOrigin: ResizeArrowFnType = (
|
|
|
element,
|
|
|
pointIndex,
|
|
@@ -116,199 +269,196 @@ const applyResizeArrowFn = (
|
|
|
setResizeArrowFn(resizeArrowFn);
|
|
|
};
|
|
|
|
|
|
-export const resizeElements = (
|
|
|
- resizeHandle: ResizeTestType,
|
|
|
- setResizeHandle: (nextResizeHandle: ResizeTestType) => void,
|
|
|
- appState: AppState,
|
|
|
- setAppState: (obj: any) => void,
|
|
|
- resizeArrowFn: ResizeArrowFnType | null, // XXX eliminate in #1339
|
|
|
- setResizeArrowFn: (fn: ResizeArrowFnType) => void, // XXX eliminate in #1339
|
|
|
- event: PointerEvent, // XXX we want to make it independent?
|
|
|
+const resizeSingleElement = (
|
|
|
+ element: NonDeletedExcalidrawElement,
|
|
|
+ resizeHandle: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
|
|
|
+ sidesWithSameLength: boolean,
|
|
|
+ isResizeFromCenter: boolean,
|
|
|
xPointer: number,
|
|
|
yPointer: number,
|
|
|
- lastX: number, // XXX eliminate in #1339
|
|
|
- lastY: number, // XXX eliminate in #1339
|
|
|
+ offsetPointer: number,
|
|
|
) => {
|
|
|
- setAppState({
|
|
|
- isResizing: resizeHandle !== "rotation",
|
|
|
- isRotating: resizeHandle === "rotation",
|
|
|
- });
|
|
|
- const selectedElements = getSelectedElements(
|
|
|
- globalSceneState.getElements(),
|
|
|
- appState,
|
|
|
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
|
+ const cx = (x1 + x2) / 2;
|
|
|
+ const cy = (y1 + y2) / 2;
|
|
|
+ // rotation pointer with reverse angle
|
|
|
+ const [rotatedX, rotatedY] = rotate(
|
|
|
+ xPointer,
|
|
|
+ yPointer,
|
|
|
+ cx,
|
|
|
+ cy,
|
|
|
+ -element.angle,
|
|
|
);
|
|
|
- const handleOffset = 4 / appState.zoom; // XXX import constant
|
|
|
- const dashedLinePadding = 4 / appState.zoom; // XXX import constant
|
|
|
- const offsetPointer = handleOffset + dashedLinePadding;
|
|
|
- const minSize = 0;
|
|
|
- if (selectedElements.length === 1) {
|
|
|
- const [element] = selectedElements;
|
|
|
- if (resizeHandle === "rotation") {
|
|
|
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
|
- const cx = (x1 + x2) / 2;
|
|
|
- const cy = (y1 + y2) / 2;
|
|
|
- let angle = (5 * Math.PI) / 2 + Math.atan2(yPointer - cy, xPointer - cx);
|
|
|
- if (event.shiftKey) {
|
|
|
- angle += SHIFT_LOCKING_ANGLE / 2;
|
|
|
- angle -= angle % SHIFT_LOCKING_ANGLE;
|
|
|
- }
|
|
|
- if (angle >= 2 * Math.PI) {
|
|
|
- angle -= 2 * Math.PI;
|
|
|
+ // XXX this might be slow with closure
|
|
|
+ const adjustWithOffsetPointer = (wh: number) => {
|
|
|
+ if (wh > offsetPointer) {
|
|
|
+ return wh - offsetPointer;
|
|
|
+ } else if (wh < -offsetPointer) {
|
|
|
+ return wh + offsetPointer;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ };
|
|
|
+ let scaleX = 1;
|
|
|
+ let scaleY = 1;
|
|
|
+ if (resizeHandle === "e" || resizeHandle === "ne" || resizeHandle === "se") {
|
|
|
+ scaleX = adjustWithOffsetPointer(rotatedX - x1) / (x2 - x1);
|
|
|
+ }
|
|
|
+ if (resizeHandle === "s" || resizeHandle === "sw" || resizeHandle === "se") {
|
|
|
+ scaleY = adjustWithOffsetPointer(rotatedY - y1) / (y2 - y1);
|
|
|
+ }
|
|
|
+ if (resizeHandle === "w" || resizeHandle === "nw" || resizeHandle === "sw") {
|
|
|
+ scaleX = adjustWithOffsetPointer(x2 - rotatedX) / (x2 - x1);
|
|
|
+ }
|
|
|
+ if (resizeHandle === "n" || resizeHandle === "nw" || resizeHandle === "ne") {
|
|
|
+ scaleY = adjustWithOffsetPointer(y2 - rotatedY) / (y2 - y1);
|
|
|
+ }
|
|
|
+ let nextWidth = element.width * scaleX;
|
|
|
+ let nextHeight = element.height * scaleY;
|
|
|
+ if (sidesWithSameLength) {
|
|
|
+ nextWidth = nextHeight = Math.max(nextWidth, nextHeight);
|
|
|
+ }
|
|
|
+ const [nextX1, nextY1, nextX2, nextY2] = getResizedElementAbsoluteCoords(
|
|
|
+ element,
|
|
|
+ nextWidth,
|
|
|
+ nextHeight,
|
|
|
+ );
|
|
|
+ const deltaX1 = (x1 - nextX1) / 2;
|
|
|
+ const deltaY1 = (y1 - nextY1) / 2;
|
|
|
+ const deltaX2 = (x2 - nextX2) / 2;
|
|
|
+ const deltaY2 = (y2 - nextY2) / 2;
|
|
|
+ const rescaledPoints = isLinearElement(element)
|
|
|
+ ? {
|
|
|
+ points: rescalePoints(
|
|
|
+ 0,
|
|
|
+ nextWidth,
|
|
|
+ rescalePoints(1, nextHeight, element.points),
|
|
|
+ ),
|
|
|
}
|
|
|
- mutateElement(element, { angle });
|
|
|
- } else if (
|
|
|
- isLinearElement(element) &&
|
|
|
- element.points.length === 2 &&
|
|
|
- (resizeHandle === "nw" ||
|
|
|
- resizeHandle === "ne" ||
|
|
|
- resizeHandle === "sw" ||
|
|
|
- resizeHandle === "se")
|
|
|
- ) {
|
|
|
- const [, [px, py]] = element.points;
|
|
|
- const isResizeEnd =
|
|
|
- (resizeHandle === "nw" && (px < 0 || py < 0)) ||
|
|
|
- (resizeHandle === "ne" && px >= 0) ||
|
|
|
- (resizeHandle === "sw" && px <= 0) ||
|
|
|
- (resizeHandle === "se" && (px > 0 || py > 0));
|
|
|
- applyResizeArrowFn(
|
|
|
- element,
|
|
|
- resizeArrowFn,
|
|
|
- setResizeArrowFn,
|
|
|
- isResizeEnd,
|
|
|
- event.shiftKey,
|
|
|
- xPointer,
|
|
|
- yPointer,
|
|
|
- lastX,
|
|
|
- lastY,
|
|
|
- );
|
|
|
- } else if (resizeHandle) {
|
|
|
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
|
- const resized = resizeXYWidthHightWithRotation(
|
|
|
- resizeHandle,
|
|
|
- x1,
|
|
|
- y1,
|
|
|
- x2,
|
|
|
- y2,
|
|
|
- element.width,
|
|
|
- element.height,
|
|
|
- element.x,
|
|
|
- element.y,
|
|
|
- element.angle,
|
|
|
- xPointer,
|
|
|
- yPointer,
|
|
|
- offsetPointer,
|
|
|
- getResizeWithSidesSameLengthKey(event),
|
|
|
- getResizeCenterPointKey(event),
|
|
|
+ : {};
|
|
|
+ const [finalX1, finalY1, finalX2, finalY2] = getResizedElementAbsoluteCoords(
|
|
|
+ {
|
|
|
+ ...element,
|
|
|
+ ...rescaledPoints,
|
|
|
+ },
|
|
|
+ Math.abs(nextWidth),
|
|
|
+ Math.abs(nextHeight),
|
|
|
+ );
|
|
|
+ const [flipDiffX, flipDiffY] = getFlipAdjustment(
|
|
|
+ resizeHandle,
|
|
|
+ nextWidth,
|
|
|
+ nextHeight,
|
|
|
+ nextX1,
|
|
|
+ nextY1,
|
|
|
+ nextX2,
|
|
|
+ nextY2,
|
|
|
+ finalX1,
|
|
|
+ finalY1,
|
|
|
+ finalX2,
|
|
|
+ finalY2,
|
|
|
+ isLinearElement(element),
|
|
|
+ element.angle,
|
|
|
+ );
|
|
|
+ const [nextElementX, nextElementY] = adjustXYWithRotation(
|
|
|
+ resizeHandle,
|
|
|
+ element.x - flipDiffX,
|
|
|
+ element.y - flipDiffY,
|
|
|
+ element.angle,
|
|
|
+ deltaX1,
|
|
|
+ deltaY1,
|
|
|
+ deltaX2,
|
|
|
+ deltaY2,
|
|
|
+ isResizeFromCenter,
|
|
|
+ );
|
|
|
+ if (
|
|
|
+ nextWidth !== 0 &&
|
|
|
+ nextHeight !== 0 &&
|
|
|
+ Number.isFinite(nextElementX) &&
|
|
|
+ Number.isFinite(nextElementY)
|
|
|
+ ) {
|
|
|
+ mutateElement(element, {
|
|
|
+ width: nextWidth,
|
|
|
+ height: nextHeight,
|
|
|
+ x: nextElementX,
|
|
|
+ y: nextElementY,
|
|
|
+ ...rescaledPoints,
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const resizeMultipleElements = (
|
|
|
+ elements: readonly NonDeletedExcalidrawElement[],
|
|
|
+ resizeHandle: "nw" | "ne" | "sw" | "se",
|
|
|
+ xPointer: number,
|
|
|
+ yPointer: number,
|
|
|
+ offsetPointer: number,
|
|
|
+) => {
|
|
|
+ const [x1, y1, x2, y2] = getCommonBounds(elements);
|
|
|
+ switch (resizeHandle) {
|
|
|
+ case "se": {
|
|
|
+ const scale = Math.max(
|
|
|
+ (xPointer - offsetPointer - x1) / (x2 - x1),
|
|
|
+ (yPointer - offsetPointer - y1) / (y2 - y1),
|
|
|
);
|
|
|
- if (
|
|
|
- Math.abs(resized.width) > minSize &&
|
|
|
- Math.abs(resized.height) > minSize
|
|
|
- ) {
|
|
|
- mutateElement(element, {
|
|
|
- ...resized,
|
|
|
- ...(isLinearElement(element)
|
|
|
- ? {
|
|
|
- points: rescalePoints(
|
|
|
- 0,
|
|
|
- resized.width,
|
|
|
- rescalePoints(1, resized.height, element.points),
|
|
|
- ),
|
|
|
- }
|
|
|
- : {}),
|
|
|
+ if (scale > 0) {
|
|
|
+ elements.forEach((element) => {
|
|
|
+ const width = element.width * scale;
|
|
|
+ const height = element.height * scale;
|
|
|
+ const x = element.x + (element.x - x1) * (scale - 1);
|
|
|
+ const y = element.y + (element.y - y1) * (scale - 1);
|
|
|
+ mutateElement(element, { width, height, x, y });
|
|
|
});
|
|
|
}
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
- if (resizeHandle) {
|
|
|
- setResizeHandle(normalizeResizeHandle(element, resizeHandle));
|
|
|
- }
|
|
|
- normalizeDimensions(element);
|
|
|
-
|
|
|
- // do we need this?
|
|
|
- document.documentElement.style.cursor = getCursorForResizingElement({
|
|
|
- element,
|
|
|
- resizeHandle,
|
|
|
- });
|
|
|
- // why do we need this?
|
|
|
- if (appState.resizingElement) {
|
|
|
- mutateElement(appState.resizingElement, {
|
|
|
- x: element.x,
|
|
|
- y: element.y,
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- } else if (selectedElements.length > 1) {
|
|
|
- const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
|
|
|
- const minScale = Math.max(minSize / (x2 - x1), minSize / (y2 - y1));
|
|
|
- switch (resizeHandle) {
|
|
|
- case "se": {
|
|
|
- const scale = Math.max(
|
|
|
- (xPointer - offsetPointer - x1) / (x2 - x1),
|
|
|
- (yPointer - offsetPointer - y1) / (y2 - y1),
|
|
|
- );
|
|
|
- if (scale > minScale) {
|
|
|
- selectedElements.forEach((element) => {
|
|
|
- const width = element.width * scale;
|
|
|
- const height = element.height * scale;
|
|
|
- const x = element.x + (element.x - x1) * (scale - 1);
|
|
|
- const y = element.y + (element.y - y1) * (scale - 1);
|
|
|
- mutateElement(element, { width, height, x, y });
|
|
|
- });
|
|
|
- }
|
|
|
- return true;
|
|
|
- }
|
|
|
- case "nw": {
|
|
|
- const scale = Math.max(
|
|
|
- (x2 - offsetPointer - xPointer) / (x2 - x1),
|
|
|
- (y2 - offsetPointer - yPointer) / (y2 - y1),
|
|
|
- );
|
|
|
- if (scale > minScale) {
|
|
|
- selectedElements.forEach((element) => {
|
|
|
- const width = element.width * scale;
|
|
|
- const height = element.height * scale;
|
|
|
- const x = element.x - (x2 - element.x) * (scale - 1);
|
|
|
- const y = element.y - (y2 - element.y) * (scale - 1);
|
|
|
- mutateElement(element, { width, height, x, y });
|
|
|
- });
|
|
|
- }
|
|
|
- return true;
|
|
|
+ case "nw": {
|
|
|
+ const scale = Math.max(
|
|
|
+ (x2 - offsetPointer - xPointer) / (x2 - x1),
|
|
|
+ (y2 - offsetPointer - yPointer) / (y2 - y1),
|
|
|
+ );
|
|
|
+ if (scale > 0) {
|
|
|
+ elements.forEach((element) => {
|
|
|
+ const width = element.width * scale;
|
|
|
+ const height = element.height * scale;
|
|
|
+ const x = element.x - (x2 - element.x) * (scale - 1);
|
|
|
+ const y = element.y - (y2 - element.y) * (scale - 1);
|
|
|
+ mutateElement(element, { width, height, x, y });
|
|
|
+ });
|
|
|
}
|
|
|
- case "ne": {
|
|
|
- const scale = Math.max(
|
|
|
- (xPointer - offsetPointer - x1) / (x2 - x1),
|
|
|
- (y2 - offsetPointer - yPointer) / (y2 - y1),
|
|
|
- );
|
|
|
- if (scale > minScale) {
|
|
|
- selectedElements.forEach((element) => {
|
|
|
- const width = element.width * scale;
|
|
|
- const height = element.height * scale;
|
|
|
- const x = element.x + (element.x - x1) * (scale - 1);
|
|
|
- const y = element.y - (y2 - element.y) * (scale - 1);
|
|
|
- mutateElement(element, { width, height, x, y });
|
|
|
- });
|
|
|
- }
|
|
|
- return true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case "ne": {
|
|
|
+ const scale = Math.max(
|
|
|
+ (xPointer - offsetPointer - x1) / (x2 - x1),
|
|
|
+ (y2 - offsetPointer - yPointer) / (y2 - y1),
|
|
|
+ );
|
|
|
+ if (scale > 0) {
|
|
|
+ elements.forEach((element) => {
|
|
|
+ const width = element.width * scale;
|
|
|
+ const height = element.height * scale;
|
|
|
+ const x = element.x + (element.x - x1) * (scale - 1);
|
|
|
+ const y = element.y - (y2 - element.y) * (scale - 1);
|
|
|
+ mutateElement(element, { width, height, x, y });
|
|
|
+ });
|
|
|
}
|
|
|
- case "sw": {
|
|
|
- const scale = Math.max(
|
|
|
- (x2 - offsetPointer - xPointer) / (x2 - x1),
|
|
|
- (yPointer - offsetPointer - y1) / (y2 - y1),
|
|
|
- );
|
|
|
- if (scale > minScale) {
|
|
|
- selectedElements.forEach((element) => {
|
|
|
- const width = element.width * scale;
|
|
|
- const height = element.height * scale;
|
|
|
- const x = element.x - (x2 - element.x) * (scale - 1);
|
|
|
- const y = element.y + (element.y - y1) * (scale - 1);
|
|
|
- mutateElement(element, { width, height, x, y });
|
|
|
- });
|
|
|
- }
|
|
|
- return true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case "sw": {
|
|
|
+ const scale = Math.max(
|
|
|
+ (x2 - offsetPointer - xPointer) / (x2 - x1),
|
|
|
+ (yPointer - offsetPointer - y1) / (y2 - y1),
|
|
|
+ );
|
|
|
+ if (scale > 0) {
|
|
|
+ elements.forEach((element) => {
|
|
|
+ const width = element.width * scale;
|
|
|
+ const height = element.height * scale;
|
|
|
+ const x = element.x - (x2 - element.x) * (scale - 1);
|
|
|
+ const y = element.y + (element.y - y1) * (scale - 1);
|
|
|
+ mutateElement(element, { width, height, x, y });
|
|
|
+ });
|
|
|
}
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
- return false;
|
|
|
};
|
|
|
|
|
|
export const canResizeMutlipleElements = (
|