* change resize math to absolute instead of delta * typings * small change for width on rotation * apply absolute resize to other sides * revert&change math.ts * polish, polish, polish * refactor with offset * eliminate nextX * rename to offsetPointer * fix curved lines * prefer arrow function * remove unused variables/comments for now Co-authored-by: daishi <daishi@axlight.com>
This commit is contained in:
parent
bd32a26653
commit
8efe0b7d05
@ -2,7 +2,7 @@ import { AppState } from "../types";
|
|||||||
import { SHIFT_LOCKING_ANGLE } from "../constants";
|
import { SHIFT_LOCKING_ANGLE } from "../constants";
|
||||||
import { getSelectedElements, globalSceneState } from "../scene";
|
import { getSelectedElements, globalSceneState } from "../scene";
|
||||||
import { rescalePoints } from "../points";
|
import { rescalePoints } from "../points";
|
||||||
import { rotate, adjustXYWithRotation } from "../math";
|
import { rotate, resizeXYWidthHightWithRotation } from "../math";
|
||||||
import {
|
import {
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
NonDeletedExcalidrawElement,
|
NonDeletedExcalidrawElement,
|
||||||
@ -27,7 +27,7 @@ export type ResizeArrowFnType = (
|
|||||||
deltaY: number,
|
deltaY: number,
|
||||||
pointerX: number,
|
pointerX: number,
|
||||||
pointerY: number,
|
pointerY: number,
|
||||||
perfect: boolean,
|
sidesWithSameLength: boolean,
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
const arrowResizeOrigin: ResizeArrowFnType = (
|
const arrowResizeOrigin: ResizeArrowFnType = (
|
||||||
@ -37,7 +37,7 @@ const arrowResizeOrigin: ResizeArrowFnType = (
|
|||||||
deltaY,
|
deltaY,
|
||||||
pointerX,
|
pointerX,
|
||||||
pointerY,
|
pointerY,
|
||||||
perfect,
|
sidesWithSameLength,
|
||||||
) => {
|
) => {
|
||||||
const [px, py] = element.points[pointIndex];
|
const [px, py] = element.points[pointIndex];
|
||||||
let x = element.x + deltaX;
|
let x = element.x + deltaX;
|
||||||
@ -45,7 +45,7 @@ const arrowResizeOrigin: ResizeArrowFnType = (
|
|||||||
let pointX = px - deltaX;
|
let pointX = px - deltaX;
|
||||||
let pointY = py - deltaY;
|
let pointY = py - deltaY;
|
||||||
|
|
||||||
if (perfect) {
|
if (sidesWithSameLength) {
|
||||||
const { width, height } = getPerfectElementSize(
|
const { width, height } = getPerfectElementSize(
|
||||||
element.type,
|
element.type,
|
||||||
px + element.x - pointerX,
|
px + element.x - pointerX,
|
||||||
@ -73,10 +73,10 @@ const arrowResizeEnd: ResizeArrowFnType = (
|
|||||||
deltaY,
|
deltaY,
|
||||||
pointerX,
|
pointerX,
|
||||||
pointerY,
|
pointerY,
|
||||||
perfect,
|
sidesWithSameLength,
|
||||||
) => {
|
) => {
|
||||||
const [px, py] = element.points[pointIndex];
|
const [px, py] = element.points[pointIndex];
|
||||||
if (perfect) {
|
if (sidesWithSameLength) {
|
||||||
const { width, height } = getPerfectElementSize(
|
const { width, height } = getPerfectElementSize(
|
||||||
element.type,
|
element.type,
|
||||||
pointerX - element.x,
|
pointerX - element.x,
|
||||||
@ -96,7 +96,31 @@ const arrowResizeEnd: ResizeArrowFnType = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function resizeElements(
|
const applyResizeArrowFn = (
|
||||||
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
|
resizeArrowFn: ResizeArrowFnType | null,
|
||||||
|
setResizeArrowFn: (fn: ResizeArrowFnType) => void,
|
||||||
|
isResizeEnd: boolean,
|
||||||
|
sidesWithSameLength: boolean,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
lastX: number,
|
||||||
|
lastY: number,
|
||||||
|
) => {
|
||||||
|
const angle = element.angle;
|
||||||
|
const [deltaX, deltaY] = rotate(x - lastX, y - lastY, 0, 0, -angle);
|
||||||
|
if (!resizeArrowFn) {
|
||||||
|
if (isResizeEnd) {
|
||||||
|
resizeArrowFn = arrowResizeEnd;
|
||||||
|
} else {
|
||||||
|
resizeArrowFn = arrowResizeOrigin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resizeArrowFn(element, 1, deltaX, deltaY, x, y, sidesWithSameLength);
|
||||||
|
setResizeArrowFn(resizeArrowFn);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resizeElements = (
|
||||||
resizeHandle: ResizeTestType,
|
resizeHandle: ResizeTestType,
|
||||||
setResizeHandle: (nextResizeHandle: ResizeTestType) => void,
|
setResizeHandle: (nextResizeHandle: ResizeTestType) => void,
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
@ -104,11 +128,11 @@ export function resizeElements(
|
|||||||
resizeArrowFn: ResizeArrowFnType | null,
|
resizeArrowFn: ResizeArrowFnType | null,
|
||||||
setResizeArrowFn: (fn: ResizeArrowFnType) => void,
|
setResizeArrowFn: (fn: ResizeArrowFnType) => void,
|
||||||
event: PointerEvent,
|
event: PointerEvent,
|
||||||
x: number,
|
xPointer: number,
|
||||||
y: number,
|
yPointer: number,
|
||||||
lastX: number,
|
lastX: number,
|
||||||
lastY: number,
|
lastY: number,
|
||||||
) {
|
) => {
|
||||||
setAppState({
|
setAppState({
|
||||||
isResizing: resizeHandle !== "rotation",
|
isResizing: resizeHandle !== "rotation",
|
||||||
isRotating: resizeHandle === "rotation",
|
isRotating: resizeHandle === "rotation",
|
||||||
@ -117,224 +141,79 @@ export function resizeElements(
|
|||||||
globalSceneState.getElements(),
|
globalSceneState.getElements(),
|
||||||
appState,
|
appState,
|
||||||
);
|
);
|
||||||
|
const handleOffset = 4 / appState.zoom; // XXX import constant
|
||||||
|
const dashedLinePadding = 4 / appState.zoom; // XXX import constant
|
||||||
|
const offsetPointer = handleOffset + dashedLinePadding;
|
||||||
|
const minSize = handleOffset * 4;
|
||||||
if (selectedElements.length === 1) {
|
if (selectedElements.length === 1) {
|
||||||
const element = selectedElements[0];
|
const [element] = selectedElements;
|
||||||
const angle = element.angle;
|
if (resizeHandle === "rotation") {
|
||||||
// reverse rotate delta
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||||
const [deltaX, deltaY] = rotate(x - lastX, y - lastY, 0, 0, -angle);
|
const cx = (x1 + x2) / 2;
|
||||||
switch (resizeHandle) {
|
const cy = (y1 + y2) / 2;
|
||||||
case "nw":
|
let angle = (5 * Math.PI) / 2 + Math.atan2(yPointer - cy, xPointer - cx);
|
||||||
if (isLinearElement(element) && element.points.length === 2) {
|
if (event.shiftKey) {
|
||||||
const [, p1] = element.points;
|
angle += SHIFT_LOCKING_ANGLE / 2;
|
||||||
|
angle -= angle % SHIFT_LOCKING_ANGLE;
|
||||||
if (!resizeArrowFn) {
|
|
||||||
if (p1[0] < 0 || p1[1] < 0) {
|
|
||||||
resizeArrowFn = arrowResizeEnd;
|
|
||||||
} else {
|
|
||||||
resizeArrowFn = arrowResizeOrigin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resizeArrowFn(element, 1, deltaX, deltaY, x, y, event.shiftKey);
|
|
||||||
setResizeArrowFn(resizeArrowFn);
|
|
||||||
} else {
|
|
||||||
const width = element.width - deltaX;
|
|
||||||
const height = event.shiftKey ? width : element.height - deltaY;
|
|
||||||
const dY = element.height - height;
|
|
||||||
mutateElement(element, {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
...adjustXYWithRotation("nw", element, deltaX, dY, angle),
|
|
||||||
...(isLinearElement(element) && width !== 0 && height !== 0
|
|
||||||
? {
|
|
||||||
points: rescalePoints(
|
|
||||||
0,
|
|
||||||
width,
|
|
||||||
rescalePoints(1, height, element.points),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ne":
|
|
||||||
if (isLinearElement(element) && element.points.length === 2) {
|
|
||||||
const [, p1] = element.points;
|
|
||||||
if (!resizeArrowFn) {
|
|
||||||
if (p1[0] >= 0) {
|
|
||||||
resizeArrowFn = arrowResizeEnd;
|
|
||||||
} else {
|
|
||||||
resizeArrowFn = arrowResizeOrigin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resizeArrowFn(element, 1, deltaX, deltaY, x, y, event.shiftKey);
|
|
||||||
setResizeArrowFn(resizeArrowFn);
|
|
||||||
} else {
|
|
||||||
const width = element.width + deltaX;
|
|
||||||
const height = event.shiftKey ? width : element.height - deltaY;
|
|
||||||
const dY = element.height - height;
|
|
||||||
mutateElement(element, {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
...adjustXYWithRotation("ne", element, deltaX, dY, angle),
|
|
||||||
...(isLinearElement(element) && width !== 0 && height !== 0
|
|
||||||
? {
|
|
||||||
points: rescalePoints(
|
|
||||||
0,
|
|
||||||
width,
|
|
||||||
rescalePoints(1, height, element.points),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "sw":
|
|
||||||
if (isLinearElement(element) && element.points.length === 2) {
|
|
||||||
const [, p1] = element.points;
|
|
||||||
if (!resizeArrowFn) {
|
|
||||||
if (p1[0] <= 0) {
|
|
||||||
resizeArrowFn = arrowResizeEnd;
|
|
||||||
} else {
|
|
||||||
resizeArrowFn = arrowResizeOrigin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resizeArrowFn(element, 1, deltaX, deltaY, x, y, event.shiftKey);
|
|
||||||
setResizeArrowFn(resizeArrowFn);
|
|
||||||
} else {
|
|
||||||
const width = element.width - deltaX;
|
|
||||||
const height = event.shiftKey ? width : element.height + deltaY;
|
|
||||||
const dY = height - element.height;
|
|
||||||
mutateElement(element, {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
...adjustXYWithRotation("sw", element, deltaX, dY, angle),
|
|
||||||
...(isLinearElement(element) && width !== 0 && height !== 0
|
|
||||||
? {
|
|
||||||
points: rescalePoints(
|
|
||||||
0,
|
|
||||||
width,
|
|
||||||
rescalePoints(1, height, element.points),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "se":
|
|
||||||
if (isLinearElement(element) && element.points.length === 2) {
|
|
||||||
const [, p1] = element.points;
|
|
||||||
if (!resizeArrowFn) {
|
|
||||||
if (p1[0] > 0 || p1[1] > 0) {
|
|
||||||
resizeArrowFn = arrowResizeEnd;
|
|
||||||
} else {
|
|
||||||
resizeArrowFn = arrowResizeOrigin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resizeArrowFn(element, 1, deltaX, deltaY, x, y, event.shiftKey);
|
|
||||||
setResizeArrowFn(resizeArrowFn);
|
|
||||||
} else {
|
|
||||||
const width = element.width + deltaX;
|
|
||||||
const height = event.shiftKey ? width : element.height + deltaY;
|
|
||||||
const dY = height - element.height;
|
|
||||||
mutateElement(element, {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
...adjustXYWithRotation("se", element, deltaX, dY, angle),
|
|
||||||
...(isLinearElement(element) && width !== 0 && height !== 0
|
|
||||||
? {
|
|
||||||
points: rescalePoints(
|
|
||||||
0,
|
|
||||||
width,
|
|
||||||
rescalePoints(1, height, element.points),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "n": {
|
|
||||||
const height = element.height - deltaY;
|
|
||||||
|
|
||||||
if (isLinearElement(element) && height !== 0) {
|
|
||||||
mutateElement(element, {
|
|
||||||
height,
|
|
||||||
...adjustXYWithRotation("n", element, 0, deltaY, angle),
|
|
||||||
points: rescalePoints(1, height, element.points),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
mutateElement(element, {
|
|
||||||
height,
|
|
||||||
...adjustXYWithRotation("n", element, 0, deltaY, angle),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "w": {
|
if (angle >= 2 * Math.PI) {
|
||||||
const width = element.width - deltaX;
|
angle -= 2 * Math.PI;
|
||||||
|
|
||||||
if (isLinearElement(element) && width !== 0) {
|
|
||||||
mutateElement(element, {
|
|
||||||
width,
|
|
||||||
...adjustXYWithRotation("w", element, deltaX, 0, angle),
|
|
||||||
points: rescalePoints(0, width, element.points),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
mutateElement(element, {
|
|
||||||
width,
|
|
||||||
...adjustXYWithRotation("w", element, deltaX, 0, angle),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "s": {
|
mutateElement(element, { angle });
|
||||||
const height = element.height + deltaY;
|
} else if (
|
||||||
|
isLinearElement(element) &&
|
||||||
if (isLinearElement(element) && height !== 0) {
|
element.points.length === 2 &&
|
||||||
mutateElement(element, {
|
(resizeHandle === "nw" ||
|
||||||
height,
|
resizeHandle === "ne" ||
|
||||||
...adjustXYWithRotation("s", element, 0, deltaY, angle),
|
resizeHandle === "sw" ||
|
||||||
points: rescalePoints(1, height, element.points),
|
resizeHandle === "se")
|
||||||
});
|
) {
|
||||||
} else {
|
const [, [px, py]] = element.points;
|
||||||
mutateElement(element, {
|
const isResizeEnd =
|
||||||
height,
|
(resizeHandle === "nw" && (px < 0 || py < 0)) ||
|
||||||
...adjustXYWithRotation("s", element, 0, deltaY, angle),
|
(resizeHandle === "ne" && px >= 0) ||
|
||||||
});
|
(resizeHandle === "sw" && px <= 0) ||
|
||||||
}
|
(resizeHandle === "se" && (px > 0 || py > 0));
|
||||||
break;
|
applyResizeArrowFn(
|
||||||
}
|
element,
|
||||||
case "e": {
|
resizeArrowFn,
|
||||||
const width = element.width + deltaX;
|
setResizeArrowFn,
|
||||||
|
isResizeEnd,
|
||||||
if (isLinearElement(element) && width !== 0) {
|
event.shiftKey,
|
||||||
mutateElement(element, {
|
xPointer,
|
||||||
width,
|
yPointer,
|
||||||
...adjustXYWithRotation("e", element, deltaX, 0, angle),
|
lastX,
|
||||||
points: rescalePoints(0, width, element.points),
|
lastY,
|
||||||
});
|
);
|
||||||
} else {
|
} else if (resizeHandle) {
|
||||||
mutateElement(element, {
|
const [x1, y1] = getElementAbsoluteCoords(element);
|
||||||
width,
|
const resized = resizeXYWidthHightWithRotation(
|
||||||
...adjustXYWithRotation("e", element, deltaX, 0, angle),
|
resizeHandle,
|
||||||
});
|
x1,
|
||||||
}
|
y1,
|
||||||
break;
|
element.width,
|
||||||
}
|
element.height,
|
||||||
case "rotation": {
|
x1 - element.x,
|
||||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
y1 - element.y,
|
||||||
const cx = (x1 + x2) / 2;
|
element.angle,
|
||||||
const cy = (y1 + y2) / 2;
|
xPointer,
|
||||||
let angle = (5 * Math.PI) / 2 + Math.atan2(y - cy, x - cx);
|
yPointer,
|
||||||
if (event.shiftKey) {
|
offsetPointer,
|
||||||
angle += SHIFT_LOCKING_ANGLE / 2;
|
event.shiftKey,
|
||||||
angle -= angle % SHIFT_LOCKING_ANGLE;
|
);
|
||||||
}
|
if (resized.width !== 0 && resized.height !== 0) {
|
||||||
if (angle >= 2 * Math.PI) {
|
mutateElement(element, {
|
||||||
angle -= 2 * Math.PI;
|
...resized,
|
||||||
}
|
...(isLinearElement(element)
|
||||||
mutateElement(element, { angle });
|
? {
|
||||||
break;
|
points: rescalePoints(
|
||||||
|
0,
|
||||||
|
resized.width,
|
||||||
|
rescalePoints(1, resized.height, element.points),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,15 +238,12 @@ export function resizeElements(
|
|||||||
return true;
|
return true;
|
||||||
} else if (selectedElements.length > 1) {
|
} else if (selectedElements.length > 1) {
|
||||||
const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
|
const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
|
||||||
const handleOffset = 4 / appState.zoom; // XXX import constant
|
|
||||||
const dashedLinePadding = 4 / appState.zoom; // XXX import constant
|
|
||||||
const minSize = handleOffset * 4;
|
|
||||||
const minScale = Math.max(minSize / (x2 - x1), minSize / (y2 - y1));
|
const minScale = Math.max(minSize / (x2 - x1), minSize / (y2 - y1));
|
||||||
switch (resizeHandle) {
|
switch (resizeHandle) {
|
||||||
case "se": {
|
case "se": {
|
||||||
const scale = Math.max(
|
const scale = Math.max(
|
||||||
(x - handleOffset - dashedLinePadding - x1) / (x2 - x1),
|
(xPointer - offsetPointer - x1) / (x2 - x1),
|
||||||
(y - handleOffset - dashedLinePadding - y1) / (y2 - y1),
|
(yPointer - offsetPointer - y1) / (y2 - y1),
|
||||||
);
|
);
|
||||||
if (scale > minScale) {
|
if (scale > minScale) {
|
||||||
selectedElements.forEach((element) => {
|
selectedElements.forEach((element) => {
|
||||||
@ -382,8 +258,8 @@ export function resizeElements(
|
|||||||
}
|
}
|
||||||
case "nw": {
|
case "nw": {
|
||||||
const scale = Math.max(
|
const scale = Math.max(
|
||||||
(x2 - handleOffset - dashedLinePadding - x) / (x2 - x1),
|
(x2 - offsetPointer - xPointer) / (x2 - x1),
|
||||||
(y2 - handleOffset - dashedLinePadding - y) / (y2 - y1),
|
(y2 - offsetPointer - yPointer) / (y2 - y1),
|
||||||
);
|
);
|
||||||
if (scale > minScale) {
|
if (scale > minScale) {
|
||||||
selectedElements.forEach((element) => {
|
selectedElements.forEach((element) => {
|
||||||
@ -398,8 +274,8 @@ export function resizeElements(
|
|||||||
}
|
}
|
||||||
case "ne": {
|
case "ne": {
|
||||||
const scale = Math.max(
|
const scale = Math.max(
|
||||||
(x - handleOffset - dashedLinePadding - x1) / (x2 - x1),
|
(xPointer - offsetPointer - x1) / (x2 - x1),
|
||||||
(y2 - handleOffset - dashedLinePadding - y) / (y2 - y1),
|
(y2 - offsetPointer - yPointer) / (y2 - y1),
|
||||||
);
|
);
|
||||||
if (scale > minScale) {
|
if (scale > minScale) {
|
||||||
selectedElements.forEach((element) => {
|
selectedElements.forEach((element) => {
|
||||||
@ -414,8 +290,8 @@ export function resizeElements(
|
|||||||
}
|
}
|
||||||
case "sw": {
|
case "sw": {
|
||||||
const scale = Math.max(
|
const scale = Math.max(
|
||||||
(x2 - handleOffset - dashedLinePadding - x) / (x2 - x1),
|
(x2 - offsetPointer - xPointer) / (x2 - x1),
|
||||||
(y - handleOffset - dashedLinePadding - y1) / (y2 - y1),
|
(yPointer - offsetPointer - y1) / (y2 - y1),
|
||||||
);
|
);
|
||||||
if (scale > minScale) {
|
if (scale > minScale) {
|
||||||
selectedElements.forEach((element) => {
|
selectedElements.forEach((element) => {
|
||||||
@ -431,12 +307,12 @@ export function resizeElements(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function canResizeMutlipleElements(
|
export const canResizeMutlipleElements = (
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
) {
|
) => {
|
||||||
return elements.every((element) =>
|
return elements.every((element) =>
|
||||||
["rectangle", "diamond", "ellipse"].includes(element.type),
|
["rectangle", "diamond", "ellipse"].includes(element.type),
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
15
src/math.test.ts
Normal file
15
src/math.test.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { rotate } from "./math";
|
||||||
|
|
||||||
|
describe("rotate", () => {
|
||||||
|
it("should rotate over (x2, y2) and return the rotated coordinates for (x1, y1)", () => {
|
||||||
|
const x1 = 10;
|
||||||
|
const y1 = 20;
|
||||||
|
const x2 = 20;
|
||||||
|
const y2 = 30;
|
||||||
|
const angle = Math.PI / 2;
|
||||||
|
const [rotatedX, rotatedY] = rotate(x1, y1, x2, y2, angle);
|
||||||
|
expect([rotatedX, rotatedY]).toEqual([30, 20]);
|
||||||
|
const res2 = rotate(rotatedX, rotatedY, x2, y2, -angle);
|
||||||
|
expect(res2).toEqual([x1, x2]);
|
||||||
|
});
|
||||||
|
});
|
88
src/math.ts
88
src/math.ts
@ -56,32 +56,92 @@ export function rotate(
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function adjustXYWithRotation(
|
const adjustXYWithRotation = (
|
||||||
side: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
|
side: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
|
||||||
position: { x: number; y: number },
|
x: number,
|
||||||
|
y: number,
|
||||||
|
angle: number,
|
||||||
deltaX: number,
|
deltaX: number,
|
||||||
deltaY: number,
|
deltaY: number,
|
||||||
angle: number,
|
) => {
|
||||||
) {
|
const cos = Math.cos(angle);
|
||||||
let { x, y } = position;
|
const sin = Math.sin(angle);
|
||||||
|
deltaX /= 2;
|
||||||
|
deltaY /= 2;
|
||||||
if (side === "e" || side === "ne" || side === "se") {
|
if (side === "e" || side === "ne" || side === "se") {
|
||||||
x -= (deltaX / 2) * (1 - Math.cos(angle));
|
x += deltaX * (1 - cos);
|
||||||
y -= (deltaX / 2) * -Math.sin(angle);
|
y += deltaX * -sin;
|
||||||
}
|
}
|
||||||
if (side === "s" || side === "sw" || side === "se") {
|
if (side === "s" || side === "sw" || side === "se") {
|
||||||
x -= (deltaY / 2) * Math.sin(angle);
|
x += deltaY * sin;
|
||||||
y -= (deltaY / 2) * (1 - Math.cos(angle));
|
y += deltaY * (1 - cos);
|
||||||
}
|
}
|
||||||
if (side === "w" || side === "nw" || side === "sw") {
|
if (side === "w" || side === "nw" || side === "sw") {
|
||||||
x += (deltaX / 2) * (1 + Math.cos(angle));
|
x += deltaX * (1 + cos);
|
||||||
y += (deltaX / 2) * Math.sin(angle);
|
y += deltaX * sin;
|
||||||
}
|
}
|
||||||
if (side === "n" || side === "nw" || side === "ne") {
|
if (side === "n" || side === "nw" || side === "ne") {
|
||||||
x += (deltaY / 2) * -Math.sin(angle);
|
x += deltaY * -sin;
|
||||||
y += (deltaY / 2) * (1 + Math.cos(angle));
|
y += deltaY * (1 + cos);
|
||||||
}
|
}
|
||||||
return { x, y };
|
return { x, y };
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const resizeXYWidthHightWithRotation = (
|
||||||
|
side: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
offsetX: number,
|
||||||
|
offsetY: number,
|
||||||
|
angle: number,
|
||||||
|
xPointer: number,
|
||||||
|
yPointer: number,
|
||||||
|
offsetPointer: number,
|
||||||
|
sidesWithSameLength: boolean,
|
||||||
|
) => {
|
||||||
|
// center point for rotation
|
||||||
|
const cx = x + width / 2;
|
||||||
|
const cy = y + height / 2;
|
||||||
|
|
||||||
|
// rotation with current angle
|
||||||
|
const [rotatedX, rotatedY] = rotate(xPointer, yPointer, cx, cy, -angle);
|
||||||
|
|
||||||
|
let scaleX = 1;
|
||||||
|
let scaleY = 1;
|
||||||
|
if (side === "e" || side === "ne" || side === "se") {
|
||||||
|
scaleX = (rotatedX - offsetPointer - x) / width;
|
||||||
|
}
|
||||||
|
if (side === "s" || side === "sw" || side === "se") {
|
||||||
|
scaleY = (rotatedY - offsetPointer - y) / height;
|
||||||
|
}
|
||||||
|
if (side === "w" || side === "nw" || side === "sw") {
|
||||||
|
scaleX = (x + width - offsetPointer - rotatedX) / width;
|
||||||
|
}
|
||||||
|
if (side === "n" || side === "nw" || side === "ne") {
|
||||||
|
scaleY = (y + height - offsetPointer - rotatedY) / height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nextWidth = width * scaleX;
|
||||||
|
let nextHeight = height * scaleY;
|
||||||
|
if (sidesWithSameLength) {
|
||||||
|
nextWidth = nextHeight = Math.max(nextWidth, nextHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: nextWidth,
|
||||||
|
height: nextHeight,
|
||||||
|
...adjustXYWithRotation(
|
||||||
|
side,
|
||||||
|
x - offsetX,
|
||||||
|
y - offsetY,
|
||||||
|
angle,
|
||||||
|
width - nextWidth,
|
||||||
|
height - nextHeight,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getPointOnAPath = (point: Point, path: Point[]) => {
|
export const getPointOnAPath = (point: Point, path: Point[]) => {
|
||||||
const [px, py] = point;
|
const [px, py] = point;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user