mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Further reverse refactor
This commit is contained in:
parent
1f97420475
commit
b3946aa3b4
3 changed files with 256 additions and 101 deletions
|
@ -8,9 +8,18 @@ import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
import type Scene from "@excalidraw/element/Scene";
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { handlePositionChange } from "./utils";
|
import {
|
||||||
|
getAtomicUnits,
|
||||||
|
getStepSizedValue,
|
||||||
|
isPropertyEditable,
|
||||||
|
moveElements,
|
||||||
|
moveGroupTo,
|
||||||
|
STEP_SIZE,
|
||||||
|
type AtomicUnit,
|
||||||
|
} from "./utils";
|
||||||
|
import { getElementsInAtomicUnit, moveElement } from "./utils";
|
||||||
|
|
||||||
import type { AtomicUnit } from "./utils";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface MultiPositionProps {
|
interface MultiPositionProps {
|
||||||
|
@ -22,6 +31,100 @@ interface MultiPositionProps {
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePositionChange: DragInputCallbackType<
|
||||||
|
MultiPositionProps["property"]
|
||||||
|
> = ({
|
||||||
|
accumulatedChange,
|
||||||
|
originalElements,
|
||||||
|
originalElementsMap,
|
||||||
|
shouldChangeByStepSize,
|
||||||
|
nextValue,
|
||||||
|
property,
|
||||||
|
scene,
|
||||||
|
originalAppState,
|
||||||
|
}) => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
|
if (nextValue !== undefined) {
|
||||||
|
for (const atomicUnit of getAtomicUnits(
|
||||||
|
originalElements,
|
||||||
|
originalAppState,
|
||||||
|
)) {
|
||||||
|
const elementsInUnit = getElementsInAtomicUnit(
|
||||||
|
atomicUnit,
|
||||||
|
elementsMap,
|
||||||
|
originalElementsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (elementsInUnit.length > 1) {
|
||||||
|
const [x1, y1, ,] = getCommonBounds(
|
||||||
|
elementsInUnit.map((el) => el.latest!),
|
||||||
|
);
|
||||||
|
const newTopLeftX = property === "x" ? nextValue : x1;
|
||||||
|
const newTopLeftY = property === "y" ? nextValue : y1;
|
||||||
|
|
||||||
|
moveGroupTo(
|
||||||
|
newTopLeftX,
|
||||||
|
newTopLeftY,
|
||||||
|
elementsInUnit.map((el) => el.original),
|
||||||
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const origElement = elementsInUnit[0]?.original;
|
||||||
|
const latestElement = elementsInUnit[0]?.latest;
|
||||||
|
if (
|
||||||
|
origElement &&
|
||||||
|
latestElement &&
|
||||||
|
isPropertyEditable(latestElement, property)
|
||||||
|
) {
|
||||||
|
const [cx, cy] = [
|
||||||
|
origElement.x + origElement.width / 2,
|
||||||
|
origElement.y + origElement.height / 2,
|
||||||
|
];
|
||||||
|
const [topLeftX, topLeftY] = pointRotateRads(
|
||||||
|
pointFrom(origElement.x, origElement.y),
|
||||||
|
pointFrom(cx, cy),
|
||||||
|
origElement.angle,
|
||||||
|
);
|
||||||
|
|
||||||
|
const newTopLeftX = property === "x" ? nextValue : topLeftX;
|
||||||
|
const newTopLeftY = property === "y" ? nextValue : topLeftY;
|
||||||
|
moveElement(
|
||||||
|
newTopLeftX,
|
||||||
|
newTopLeftY,
|
||||||
|
origElement,
|
||||||
|
scene,
|
||||||
|
originalElementsMap,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.triggerUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const change = shouldChangeByStepSize
|
||||||
|
? getStepSizedValue(accumulatedChange, STEP_SIZE)
|
||||||
|
: accumulatedChange;
|
||||||
|
|
||||||
|
const changeInTopX = property === "x" ? change : 0;
|
||||||
|
const changeInTopY = property === "y" ? change : 0;
|
||||||
|
|
||||||
|
moveElements(
|
||||||
|
property,
|
||||||
|
changeInTopX,
|
||||||
|
changeInTopY,
|
||||||
|
originalElements,
|
||||||
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
|
);
|
||||||
|
|
||||||
|
scene.triggerUpdate();
|
||||||
|
};
|
||||||
|
|
||||||
const MultiPosition = ({
|
const MultiPosition = ({
|
||||||
property,
|
property,
|
||||||
elements,
|
elements,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { pointFrom, pointRotateRads, round } from "@excalidraw/math";
|
import { clamp, pointFrom, pointRotateRads, round } from "@excalidraw/math";
|
||||||
|
|
||||||
import { getFlipAdjustedCropPosition } from "@excalidraw/element/cropElement";
|
import {
|
||||||
|
getFlipAdjustedCropPosition,
|
||||||
|
getUncroppedWidthAndHeight,
|
||||||
|
} from "@excalidraw/element/cropElement";
|
||||||
import { isImageElement } from "@excalidraw/element/typeChecks";
|
import { isImageElement } from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
@ -8,8 +11,9 @@ import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
import type Scene from "@excalidraw/element/Scene";
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { handlePositionChange } from "./utils";
|
import { getStepSizedValue, moveElement, STEP_SIZE } from "./utils";
|
||||||
|
|
||||||
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
interface PositionProps {
|
interface PositionProps {
|
||||||
|
@ -20,6 +24,148 @@ interface PositionProps {
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
|
accumulatedChange,
|
||||||
|
instantChange,
|
||||||
|
originalElements,
|
||||||
|
originalElementsMap,
|
||||||
|
shouldChangeByStepSize,
|
||||||
|
nextValue,
|
||||||
|
property,
|
||||||
|
scene,
|
||||||
|
originalAppState,
|
||||||
|
}) => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
const origElement = originalElements[0];
|
||||||
|
const [cx, cy] = [
|
||||||
|
origElement.x + origElement.width / 2,
|
||||||
|
origElement.y + origElement.height / 2,
|
||||||
|
];
|
||||||
|
const [topLeftX, topLeftY] = pointRotateRads(
|
||||||
|
pointFrom(origElement.x, origElement.y),
|
||||||
|
pointFrom(cx, cy),
|
||||||
|
origElement.angle,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (originalAppState.croppingElementId === origElement.id) {
|
||||||
|
const element = elementsMap.get(origElement.id);
|
||||||
|
|
||||||
|
if (!element || !isImageElement(element) || !element.crop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const crop = element.crop;
|
||||||
|
let nextCrop = crop;
|
||||||
|
const isFlippedByX = element.scale[0] === -1;
|
||||||
|
const isFlippedByY = element.scale[1] === -1;
|
||||||
|
const { width: uncroppedWidth, height: uncroppedHeight } =
|
||||||
|
getUncroppedWidthAndHeight(element);
|
||||||
|
|
||||||
|
if (nextValue !== undefined) {
|
||||||
|
if (property === "x") {
|
||||||
|
const nextValueInNatural =
|
||||||
|
nextValue * (crop.naturalWidth / uncroppedWidth);
|
||||||
|
|
||||||
|
if (isFlippedByX) {
|
||||||
|
nextCrop = {
|
||||||
|
...crop,
|
||||||
|
x: clamp(
|
||||||
|
crop.naturalWidth - nextValueInNatural - crop.width,
|
||||||
|
0,
|
||||||
|
crop.naturalWidth - crop.width,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
nextCrop = {
|
||||||
|
...crop,
|
||||||
|
x: clamp(
|
||||||
|
nextValue * (crop.naturalWidth / uncroppedWidth),
|
||||||
|
0,
|
||||||
|
crop.naturalWidth - crop.width,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property === "y") {
|
||||||
|
nextCrop = {
|
||||||
|
...crop,
|
||||||
|
y: clamp(
|
||||||
|
nextValue * (crop.naturalHeight / uncroppedHeight),
|
||||||
|
0,
|
||||||
|
crop.naturalHeight - crop.height,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.mutateElement(element, {
|
||||||
|
crop: nextCrop,
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeInX =
|
||||||
|
(property === "x" ? instantChange : 0) * (isFlippedByX ? -1 : 1);
|
||||||
|
const changeInY =
|
||||||
|
(property === "y" ? instantChange : 0) * (isFlippedByY ? -1 : 1);
|
||||||
|
|
||||||
|
nextCrop = {
|
||||||
|
...crop,
|
||||||
|
x: clamp(crop.x + changeInX, 0, crop.naturalWidth - crop.width),
|
||||||
|
y: clamp(crop.y + changeInY, 0, crop.naturalHeight - crop.height),
|
||||||
|
};
|
||||||
|
|
||||||
|
scene.mutateElement(element, {
|
||||||
|
crop: nextCrop,
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextValue !== undefined) {
|
||||||
|
const newTopLeftX = property === "x" ? nextValue : topLeftX;
|
||||||
|
const newTopLeftY = property === "y" ? nextValue : topLeftY;
|
||||||
|
moveElement(
|
||||||
|
newTopLeftX,
|
||||||
|
newTopLeftY,
|
||||||
|
origElement,
|
||||||
|
scene,
|
||||||
|
originalElementsMap,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeInTopX = property === "x" ? accumulatedChange : 0;
|
||||||
|
const changeInTopY = property === "y" ? accumulatedChange : 0;
|
||||||
|
|
||||||
|
const newTopLeftX =
|
||||||
|
property === "x"
|
||||||
|
? Math.round(
|
||||||
|
shouldChangeByStepSize
|
||||||
|
? getStepSizedValue(origElement.x + changeInTopX, STEP_SIZE)
|
||||||
|
: topLeftX + changeInTopX,
|
||||||
|
)
|
||||||
|
: topLeftX;
|
||||||
|
|
||||||
|
const newTopLeftY =
|
||||||
|
property === "y"
|
||||||
|
? Math.round(
|
||||||
|
shouldChangeByStepSize
|
||||||
|
? getStepSizedValue(origElement.y + changeInTopY, STEP_SIZE)
|
||||||
|
: topLeftY + changeInTopY,
|
||||||
|
)
|
||||||
|
: topLeftY;
|
||||||
|
|
||||||
|
moveElement(
|
||||||
|
newTopLeftX,
|
||||||
|
newTopLeftY,
|
||||||
|
origElement,
|
||||||
|
scene,
|
||||||
|
originalElementsMap,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Position = ({
|
const Position = ({
|
||||||
property,
|
property,
|
||||||
element,
|
element,
|
||||||
|
|
|
@ -31,7 +31,6 @@ import type {
|
||||||
import type Scene from "@excalidraw/element/Scene";
|
import type Scene from "@excalidraw/element/Scene";
|
||||||
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
|
||||||
|
|
||||||
export type StatsInputProperty =
|
export type StatsInputProperty =
|
||||||
| "x"
|
| "x"
|
||||||
|
@ -43,6 +42,7 @@ export type StatsInputProperty =
|
||||||
| "gridStep";
|
| "gridStep";
|
||||||
|
|
||||||
export const SMALLEST_DELTA = 0.01;
|
export const SMALLEST_DELTA = 0.01;
|
||||||
|
export const STEP_SIZE = 10;
|
||||||
|
|
||||||
export const isPropertyEditable = (
|
export const isPropertyEditable = (
|
||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
|
@ -274,7 +274,7 @@ export const moveElements = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const moveGroup = (
|
export const moveGroupTo = (
|
||||||
nextX: number,
|
nextX: number,
|
||||||
nextY: number,
|
nextY: number,
|
||||||
originalElements: ExcalidrawElement[],
|
originalElements: ExcalidrawElement[],
|
||||||
|
@ -355,97 +355,3 @@ export const updateBindings = (
|
||||||
updateBoundElements(latestElement, scene, options);
|
updateBoundElements(latestElement, scene, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
|
||||||
accumulatedChange,
|
|
||||||
originalElements,
|
|
||||||
originalElementsMap,
|
|
||||||
shouldChangeByStepSize,
|
|
||||||
nextValue,
|
|
||||||
property,
|
|
||||||
scene,
|
|
||||||
originalAppState,
|
|
||||||
}) => {
|
|
||||||
const STEP_SIZE = 10;
|
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
|
||||||
|
|
||||||
if (nextValue !== undefined) {
|
|
||||||
for (const atomicUnit of getAtomicUnits(
|
|
||||||
originalElements,
|
|
||||||
originalAppState,
|
|
||||||
)) {
|
|
||||||
const elementsInUnit = getElementsInAtomicUnit(
|
|
||||||
atomicUnit,
|
|
||||||
elementsMap,
|
|
||||||
originalElementsMap,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (elementsInUnit.length > 1) {
|
|
||||||
const [x1, y1, ,] = getCommonBounds(
|
|
||||||
elementsInUnit.map((el) => el.latest!),
|
|
||||||
);
|
|
||||||
const newTopLeftX = property === "x" ? nextValue : x1;
|
|
||||||
const newTopLeftY = property === "y" ? nextValue : y1;
|
|
||||||
|
|
||||||
moveGroup(
|
|
||||||
newTopLeftX,
|
|
||||||
newTopLeftY,
|
|
||||||
elementsInUnit.map((el) => el.original),
|
|
||||||
originalElementsMap,
|
|
||||||
scene,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const origElement = elementsInUnit[0]?.original;
|
|
||||||
const latestElement = elementsInUnit[0]?.latest;
|
|
||||||
if (
|
|
||||||
origElement &&
|
|
||||||
latestElement &&
|
|
||||||
isPropertyEditable(latestElement, property)
|
|
||||||
) {
|
|
||||||
const [cx, cy] = [
|
|
||||||
origElement.x + origElement.width / 2,
|
|
||||||
origElement.y + origElement.height / 2,
|
|
||||||
];
|
|
||||||
const [topLeftX, topLeftY] = pointRotateRads(
|
|
||||||
pointFrom(origElement.x, origElement.y),
|
|
||||||
pointFrom(cx, cy),
|
|
||||||
origElement.angle,
|
|
||||||
);
|
|
||||||
|
|
||||||
const newTopLeftX = property === "x" ? nextValue : topLeftX;
|
|
||||||
const newTopLeftY = property === "y" ? nextValue : topLeftY;
|
|
||||||
|
|
||||||
moveElement(
|
|
||||||
newTopLeftX,
|
|
||||||
newTopLeftY,
|
|
||||||
origElement,
|
|
||||||
scene,
|
|
||||||
originalElementsMap,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scene.triggerUpdate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const change = shouldChangeByStepSize
|
|
||||||
? getStepSizedValue(accumulatedChange, STEP_SIZE)
|
|
||||||
: accumulatedChange;
|
|
||||||
|
|
||||||
const changeInTopX = property === "x" ? change : 0;
|
|
||||||
const changeInTopY = property === "y" ? change : 0;
|
|
||||||
|
|
||||||
moveElements(
|
|
||||||
property,
|
|
||||||
changeInTopX,
|
|
||||||
changeInTopY,
|
|
||||||
originalElements,
|
|
||||||
originalElementsMap,
|
|
||||||
scene,
|
|
||||||
);
|
|
||||||
|
|
||||||
scene.triggerUpdate();
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue