mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Stats: Angle setting now works properly and resets on unconnected bindings
This commit is contained in:
parent
4efa6f69e5
commit
88d4c4fe8d
6 changed files with 155 additions and 61 deletions
|
@ -3,20 +3,36 @@ import { degreesToRadians, radiansToDegrees } from "@excalidraw/math";
|
||||||
import { mutateElement } from "@excalidraw/element/mutateElement";
|
import { mutateElement } from "@excalidraw/element/mutateElement";
|
||||||
|
|
||||||
import { getBoundTextElement } from "@excalidraw/element/textElement";
|
import { getBoundTextElement } from "@excalidraw/element/textElement";
|
||||||
import { isArrowElement, isElbowArrow } from "@excalidraw/element/typeChecks";
|
import {
|
||||||
|
isArrowElement,
|
||||||
|
isBindableElement,
|
||||||
|
isElbowArrow,
|
||||||
|
} from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
import type { Degrees } from "@excalidraw/math";
|
import {
|
||||||
|
getSuggestedBindingsForArrows,
|
||||||
|
updateBoundElements,
|
||||||
|
} from "@excalidraw/element/binding";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
|
import type { Degrees, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ExcalidrawElement,
|
||||||
|
NonDeletedExcalidrawElement,
|
||||||
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
import { angleIcon } from "../icons";
|
import { angleIcon } from "../icons";
|
||||||
|
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import { getStepSizedValue, isPropertyEditable, updateBindings } from "./utils";
|
import { getStepSizedValue, isPropertyEditable, updateBindings } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type {
|
||||||
|
DragFinishedCallbackType,
|
||||||
|
DragInputCallbackType,
|
||||||
|
} from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
import type Scene from "../../scene/Scene";
|
||||||
import type { AppState } from "../../types";
|
|
||||||
|
|
||||||
interface AngleProps {
|
interface AngleProps {
|
||||||
element: ExcalidrawElement;
|
element: ExcalidrawElement;
|
||||||
|
@ -33,6 +49,8 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
|
||||||
shouldChangeByStepSize,
|
shouldChangeByStepSize,
|
||||||
nextValue,
|
nextValue,
|
||||||
scene,
|
scene,
|
||||||
|
setAppState,
|
||||||
|
originalAppState,
|
||||||
}) => {
|
}) => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const origElement = originalElements[0];
|
const origElement = originalElements[0];
|
||||||
|
@ -47,13 +65,24 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
|
||||||
mutateElement(latestElement, {
|
mutateElement(latestElement, {
|
||||||
angle: nextAngle,
|
angle: nextAngle,
|
||||||
});
|
});
|
||||||
updateBindings(latestElement, elementsMap);
|
|
||||||
|
if (isBindableElement(latestElement)) {
|
||||||
|
updateBoundElements(latestElement, elementsMap);
|
||||||
|
}
|
||||||
|
|
||||||
const boundTextElement = getBoundTextElement(latestElement, elementsMap);
|
const boundTextElement = getBoundTextElement(latestElement, elementsMap);
|
||||||
if (boundTextElement && !isArrowElement(latestElement)) {
|
if (boundTextElement && !isArrowElement(latestElement)) {
|
||||||
mutateElement(boundTextElement, { angle: nextAngle });
|
mutateElement(boundTextElement, { angle: nextAngle });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAppState({
|
||||||
|
suggestedBindings: getSuggestedBindingsForArrows(
|
||||||
|
[latestElement] as NonDeletedExcalidrawElement[],
|
||||||
|
elementsMap,
|
||||||
|
originalAppState.zoom,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,12 +102,62 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
|
||||||
mutateElement(latestElement, {
|
mutateElement(latestElement, {
|
||||||
angle: nextAngle,
|
angle: nextAngle,
|
||||||
});
|
});
|
||||||
updateBindings(latestElement, elementsMap);
|
|
||||||
|
if (isBindableElement(latestElement)) {
|
||||||
|
updateBoundElements(latestElement, elementsMap);
|
||||||
|
}
|
||||||
|
|
||||||
const boundTextElement = getBoundTextElement(latestElement, elementsMap);
|
const boundTextElement = getBoundTextElement(latestElement, elementsMap);
|
||||||
if (boundTextElement && !isArrowElement(latestElement)) {
|
if (boundTextElement && !isArrowElement(latestElement)) {
|
||||||
mutateElement(boundTextElement, { angle: nextAngle });
|
mutateElement(boundTextElement, { angle: nextAngle });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAppState({
|
||||||
|
suggestedBindings: getSuggestedBindingsForArrows(
|
||||||
|
[latestElement] as NonDeletedExcalidrawElement[],
|
||||||
|
elementsMap,
|
||||||
|
originalAppState.zoom,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFinished: DragFinishedCallbackType = ({
|
||||||
|
originalElements,
|
||||||
|
originalAppState,
|
||||||
|
scene,
|
||||||
|
accumulatedChange,
|
||||||
|
setAppState,
|
||||||
|
}) => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
const origElement = originalElements[0];
|
||||||
|
|
||||||
|
if (origElement) {
|
||||||
|
const latestElement = elementsMap.get(origElement.id);
|
||||||
|
|
||||||
|
if (latestElement) {
|
||||||
|
updateBindings(latestElement, elementsMap, originalAppState.zoom, () => {
|
||||||
|
const revertAngle = (latestElement.angle -
|
||||||
|
degreesToRadians(accumulatedChange as Degrees)) as Radians;
|
||||||
|
|
||||||
|
mutateElement(latestElement, {
|
||||||
|
angle: revertAngle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const boundTextElement = getBoundTextElement(
|
||||||
|
latestElement,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (boundTextElement && !isArrowElement(latestElement)) {
|
||||||
|
mutateElement(boundTextElement, { angle: revertAngle });
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppState({
|
||||||
|
suggestedBindings: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,6 +169,7 @@ const Angle = ({ element, scene, appState, property }: AngleProps) => {
|
||||||
value={Math.round((radiansToDegrees(element.angle) % 360) * 100) / 100}
|
value={Math.round((radiansToDegrees(element.angle) % 360) * 100) / 100}
|
||||||
elements={[element]}
|
elements={[element]}
|
||||||
dragInputCallback={handleDegreeChange}
|
dragInputCallback={handleDegreeChange}
|
||||||
|
dragFinishedCallback={handleFinished}
|
||||||
editable={isPropertyEditable(element, "angle")}
|
editable={isPropertyEditable(element, "angle")}
|
||||||
scene={scene}
|
scene={scene}
|
||||||
appState={appState}
|
appState={appState}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { deepCopyElement } from "@excalidraw/element/duplicate";
|
||||||
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import { CaptureUpdateAction } from "../../store";
|
import { CaptureUpdateAction } from "../../store";
|
||||||
import { useApp } from "../App";
|
import { useApp, useExcalidrawSetAppState } from "../App";
|
||||||
import { InlineIcon } from "../InlineIcon";
|
import { InlineIcon } from "../InlineIcon";
|
||||||
|
|
||||||
import { SMALLEST_DELTA } from "./utils";
|
import { SMALLEST_DELTA } from "./utils";
|
||||||
|
@ -34,6 +34,16 @@ export type DragInputCallbackType<
|
||||||
property: P;
|
property: P;
|
||||||
originalAppState: AppState;
|
originalAppState: AppState;
|
||||||
setInputValue: (value: number) => void;
|
setInputValue: (value: number) => void;
|
||||||
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
|
}) => void;
|
||||||
|
|
||||||
|
export type DragFinishedCallbackType<E = ExcalidrawElement> = (props: {
|
||||||
|
originalElements: readonly E[];
|
||||||
|
originalElementsMap: ElementsMap;
|
||||||
|
scene: Scene;
|
||||||
|
originalAppState: AppState;
|
||||||
|
accumulatedChange: number;
|
||||||
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
interface StatsDragInputProps<
|
interface StatsDragInputProps<
|
||||||
|
@ -47,6 +57,7 @@ interface StatsDragInputProps<
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
shouldKeepAspectRatio?: boolean;
|
shouldKeepAspectRatio?: boolean;
|
||||||
dragInputCallback: DragInputCallbackType<T, E>;
|
dragInputCallback: DragInputCallbackType<T, E>;
|
||||||
|
dragFinishedCallback?: DragFinishedCallbackType<E>;
|
||||||
property: T;
|
property: T;
|
||||||
scene: Scene;
|
scene: Scene;
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
|
@ -61,6 +72,7 @@ const StatsDragInput = <
|
||||||
label,
|
label,
|
||||||
icon,
|
icon,
|
||||||
dragInputCallback,
|
dragInputCallback,
|
||||||
|
dragFinishedCallback,
|
||||||
value,
|
value,
|
||||||
elements,
|
elements,
|
||||||
editable = true,
|
editable = true,
|
||||||
|
@ -71,6 +83,7 @@ const StatsDragInput = <
|
||||||
sensitivity = 1,
|
sensitivity = 1,
|
||||||
}: StatsDragInputProps<T, E>) => {
|
}: StatsDragInputProps<T, E>) => {
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
|
const setAppState = useExcalidrawSetAppState();
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const labelRef = useRef<HTMLDivElement>(null);
|
const labelRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
@ -135,6 +148,7 @@ const StatsDragInput = <
|
||||||
property,
|
property,
|
||||||
originalAppState: appState,
|
originalAppState: appState,
|
||||||
setInputValue: (value) => setInputValue(String(value)),
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
|
setAppState,
|
||||||
});
|
});
|
||||||
app.syncActionResult({
|
app.syncActionResult({
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
|
@ -262,6 +276,7 @@ const StatsDragInput = <
|
||||||
scene,
|
scene,
|
||||||
originalAppState,
|
originalAppState,
|
||||||
setInputValue: (value) => setInputValue(String(value)),
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
|
setAppState,
|
||||||
});
|
});
|
||||||
|
|
||||||
stepChange = 0;
|
stepChange = 0;
|
||||||
|
@ -282,6 +297,17 @@ const StatsDragInput = <
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (originalElements !== null && originalElementsMap !== null) {
|
||||||
|
dragFinishedCallback?.({
|
||||||
|
originalElements,
|
||||||
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
|
originalAppState,
|
||||||
|
accumulatedChange,
|
||||||
|
setAppState,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.syncActionResult({
|
app.syncActionResult({
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { getCommonBounds } from "@excalidraw/element/bounds";
|
||||||
import type {
|
import type {
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
NonDeletedExcalidrawElement,
|
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
|
@ -40,7 +39,6 @@ const moveElements = (
|
||||||
originalElements: readonly ExcalidrawElement[],
|
originalElements: readonly ExcalidrawElement[],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
originalElementsMap: ElementsMap,
|
originalElementsMap: ElementsMap,
|
||||||
scene: Scene,
|
|
||||||
) => {
|
) => {
|
||||||
for (let i = 0; i < elements.length; i++) {
|
for (let i = 0; i < elements.length; i++) {
|
||||||
const origElement = originalElements[i];
|
const origElement = originalElements[i];
|
||||||
|
@ -66,8 +64,6 @@ const moveElements = (
|
||||||
newTopLeftY,
|
newTopLeftY,
|
||||||
origElement,
|
origElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
|
||||||
scene,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -79,9 +75,7 @@ const moveGroupTo = (
|
||||||
nextY: number,
|
nextY: number,
|
||||||
originalElements: ExcalidrawElement[],
|
originalElements: ExcalidrawElement[],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
|
||||||
originalElementsMap: ElementsMap,
|
originalElementsMap: ElementsMap,
|
||||||
scene: Scene,
|
|
||||||
) => {
|
) => {
|
||||||
const [x1, y1, ,] = getCommonBounds(originalElements);
|
const [x1, y1, ,] = getCommonBounds(originalElements);
|
||||||
const offsetX = nextX - x1;
|
const offsetX = nextX - x1;
|
||||||
|
@ -113,8 +107,6 @@ const moveGroupTo = (
|
||||||
topLeftY + offsetY,
|
topLeftY + offsetY,
|
||||||
origElement,
|
origElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
|
||||||
scene,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -135,7 +127,6 @@ const handlePositionChange: DragInputCallbackType<
|
||||||
originalAppState,
|
originalAppState,
|
||||||
}) => {
|
}) => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const elements = scene.getNonDeletedElements();
|
|
||||||
|
|
||||||
if (nextValue !== undefined) {
|
if (nextValue !== undefined) {
|
||||||
for (const atomicUnit of getAtomicUnits(
|
for (const atomicUnit of getAtomicUnits(
|
||||||
|
@ -160,9 +151,7 @@ const handlePositionChange: DragInputCallbackType<
|
||||||
newTopLeftY,
|
newTopLeftY,
|
||||||
elementsInUnit.map((el) => el.original),
|
elementsInUnit.map((el) => el.original),
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
scene,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const origElement = elementsInUnit[0]?.original;
|
const origElement = elementsInUnit[0]?.original;
|
||||||
|
@ -189,8 +178,6 @@ const handlePositionChange: DragInputCallbackType<
|
||||||
newTopLeftY,
|
newTopLeftY,
|
||||||
origElement,
|
origElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
|
||||||
scene,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -217,7 +204,6 @@ const handlePositionChange: DragInputCallbackType<
|
||||||
originalElements,
|
originalElements,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
scene,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
scene.triggerUpdate();
|
scene.triggerUpdate();
|
||||||
|
|
|
@ -38,7 +38,6 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
originalAppState,
|
originalAppState,
|
||||||
}) => {
|
}) => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const elements = scene.getNonDeletedElements();
|
|
||||||
const origElement = originalElements[0];
|
const origElement = originalElements[0];
|
||||||
const [cx, cy] = [
|
const [cx, cy] = [
|
||||||
origElement.x + origElement.width / 2,
|
origElement.x + origElement.width / 2,
|
||||||
|
@ -134,8 +133,6 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
newTopLeftY,
|
newTopLeftY,
|
||||||
origElement,
|
origElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
|
||||||
scene,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -167,8 +164,6 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
newTopLeftY,
|
newTopLeftY,
|
||||||
origElement,
|
origElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
|
||||||
scene,
|
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -128,27 +128,19 @@ describe("binding with linear elements", () => {
|
||||||
restoreOriginalGetBoundingClientRect();
|
restoreOriginalGetBoundingClientRect();
|
||||||
});
|
});
|
||||||
|
|
||||||
// UX RATIONALE: Since we force a fixed distance from elements angle changes
|
it("should remain bound to linear element even on small position change", async () => {
|
||||||
// would result in a "jump" the moment the bound object is moved
|
const linear = h.elements[1] as ExcalidrawLinearElement;
|
||||||
it(
|
const inputX = UI.queryStatsProperty("X")?.querySelector(
|
||||||
"should not remain bound to linear element even" +
|
".drag-input",
|
||||||
" on small position change",
|
) as HTMLInputElement;
|
||||||
async () => {
|
|
||||||
const linear = h.elements[1] as ExcalidrawLinearElement;
|
|
||||||
const inputX = UI.queryStatsProperty("X")?.querySelector(
|
|
||||||
".drag-input",
|
|
||||||
) as HTMLInputElement;
|
|
||||||
|
|
||||||
expect(linear.startBinding).not.toBe(null);
|
expect(linear.startBinding).not.toBe(null);
|
||||||
expect(inputX).not.toBeNull();
|
expect(inputX).not.toBeNull();
|
||||||
UI.updateInput(inputX, String("204"));
|
UI.updateInput(inputX, String("204"));
|
||||||
expect(linear.startBinding).toBe(null);
|
expect(linear.startBinding).not.toBe(null);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// UX RATIONALE: Since we force a fixed distance from elements angle changes
|
it("should remain bound to linear element on any angle change", async () => {
|
||||||
// would result in a "jump" the moment the bound object is moved
|
|
||||||
it("should not remain bound to linear element on any angle change", async () => {
|
|
||||||
const linear = h.elements[1] as ExcalidrawLinearElement;
|
const linear = h.elements[1] as ExcalidrawLinearElement;
|
||||||
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
|
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
|
||||||
".drag-input",
|
".drag-input",
|
||||||
|
@ -156,7 +148,7 @@ describe("binding with linear elements", () => {
|
||||||
|
|
||||||
expect(linear.startBinding).not.toBe(null);
|
expect(linear.startBinding).not.toBe(null);
|
||||||
UI.updateInput(inputAngle, String("1"));
|
UI.updateInput(inputAngle, String("1"));
|
||||||
expect(linear.startBinding).toBe(null);
|
expect(linear.startBinding).not.toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should unbind linear element on large position change", async () => {
|
it("should unbind linear element on large position change", async () => {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
} from "@excalidraw/element/groups";
|
} from "@excalidraw/element/groups";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
getOriginalBindingsIfStillCloseToArrowEnds,
|
||||||
unbindLinearElement,
|
unbindLinearElement,
|
||||||
updateBoundElements,
|
updateBoundElements,
|
||||||
} from "@excalidraw/element/binding";
|
} from "@excalidraw/element/binding";
|
||||||
|
@ -29,7 +30,6 @@ import type {
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
} from "@excalidraw/element/types";
|
} from "@excalidraw/element/types";
|
||||||
|
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
export type StatsInputProperty =
|
export type StatsInputProperty =
|
||||||
|
@ -122,8 +122,6 @@ export const moveElement = (
|
||||||
newTopLeftY: number,
|
newTopLeftY: number,
|
||||||
originalElement: ExcalidrawElement,
|
originalElement: ExcalidrawElement,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
|
||||||
scene: Scene,
|
|
||||||
originalElementsMap: ElementsMap,
|
originalElementsMap: ElementsMap,
|
||||||
shouldInformMutation = true,
|
shouldInformMutation = true,
|
||||||
) => {
|
) => {
|
||||||
|
@ -159,7 +157,9 @@ export const moveElement = (
|
||||||
shouldInformMutation,
|
shouldInformMutation,
|
||||||
);
|
);
|
||||||
|
|
||||||
updateBindings(latestElement, elementsMap);
|
if (isBindableElement(latestElement)) {
|
||||||
|
updateBoundElements(latestElement, elementsMap);
|
||||||
|
}
|
||||||
|
|
||||||
const boundTextElement = getBoundTextElement(
|
const boundTextElement = getBoundTextElement(
|
||||||
originalElement,
|
originalElement,
|
||||||
|
@ -203,18 +203,33 @@ export const getAtomicUnits = (
|
||||||
export const updateBindings = (
|
export const updateBindings = (
|
||||||
latestElement: ExcalidrawElement,
|
latestElement: ExcalidrawElement,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
options?: {
|
zoom?: AppState["zoom"],
|
||||||
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
remainedBound?: () => void,
|
||||||
},
|
|
||||||
) => {
|
) => {
|
||||||
if (isBindingElement(latestElement)) {
|
if (isBindingElement(latestElement)) {
|
||||||
if (latestElement.startBinding) {
|
const [start, end] = getOriginalBindingsIfStillCloseToArrowEnds(
|
||||||
unbindLinearElement(latestElement, "start");
|
latestElement,
|
||||||
|
elementsMap,
|
||||||
|
zoom,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(latestElement.startBinding && start) ||
|
||||||
|
(latestElement.endBinding && end)
|
||||||
|
) {
|
||||||
|
remainedBound?.();
|
||||||
|
} else {
|
||||||
|
if (latestElement.startBinding && !start) {
|
||||||
|
unbindLinearElement(latestElement, "start");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latestElement.endBinding && !end) {
|
||||||
|
unbindLinearElement(latestElement, "end");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (latestElement.endBinding) {
|
|
||||||
unbindLinearElement(latestElement, "end");
|
// else if (end) {
|
||||||
}
|
// updateBoundElements(end, elementsMap);
|
||||||
} else if (isBindableElement(latestElement)) {
|
// }
|
||||||
updateBoundElements(latestElement, elementsMap, options);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue