Fix incorrect elbow arrow geometry

This commit is contained in:
Mark Tolmacs 2025-03-19 13:49:28 +01:00
parent 37531769d1
commit 0fe736cd3f
3 changed files with 49 additions and 18 deletions

View file

@ -839,14 +839,19 @@ export const updateBoundElements = (
}> => update !== null, }> => update !== null,
); );
LinearElementEditor.movePoints(element, updates, { LinearElementEditor.movePoints(
element,
updates,
{
...(changedElement.id === element.startBinding?.elementId ...(changedElement.id === element.startBinding?.elementId
? { startBinding: bindings.startBinding } ? { startBinding: bindings.startBinding }
: {}), : {}),
...(changedElement.id === element.endBinding?.elementId ...(changedElement.id === element.endBinding?.elementId
? { endBinding: bindings.endBinding } ? { endBinding: bindings.endBinding }
: {}), : {}),
}); },
elementsMap as NonDeletedSceneElementsMap,
);
const boundText = getBoundTextElement(element, elementsMap); const boundText = getBoundTextElement(element, elementsMap);
if (boundText && !boundText.isDeleted) { if (boundText && !boundText.isDeleted) {

View file

@ -984,7 +984,7 @@ export const updateElbowArrowPoints = (
: updates.points.slice() : updates.points.slice()
: arrow.points.slice(); : arrow.points.slice();
// 0. During all element replacement in the scene, we just need to renormalize // During all element replacement in the scene, we just need to renormalize
// the arrow // the arrow
// TODO (dwelle,mtolmacs): Remove this once Scene.getScene() is removed // TODO (dwelle,mtolmacs): Remove this once Scene.getScene() is removed
const { const {
@ -1005,11 +1005,12 @@ export const updateElbowArrowPoints = (
getBindableElementForId(startBinding.elementId, elementsMap); getBindableElementForId(startBinding.elementId, elementsMap);
const endElement = const endElement =
endBinding && getBindableElementForId(endBinding.elementId, elementsMap); endBinding && getBindableElementForId(endBinding.elementId, elementsMap);
const areUpdatedPointsValid = validateElbowPoints(updatedPoints);
if ( if (
(startBinding && !startElement) || (startBinding && !startElement && areUpdatedPointsValid) ||
(endBinding && !endElement) || (endBinding && !endElement && areUpdatedPointsValid) ||
(elementsMap.size === 0 && validateElbowPoints(updatedPoints)) || (elementsMap.size === 0 && areUpdatedPointsValid) ||
(Object.keys(restOfTheUpdates).length === 0 && (Object.keys(restOfTheUpdates).length === 0 &&
(startElement?.id !== startBinding?.elementId || (startElement?.id !== startBinding?.elementId ||
endElement?.id !== endBinding?.elementId)) endElement?.id !== endBinding?.elementId))
@ -1050,7 +1051,7 @@ export const updateElbowArrowPoints = (
// 0. During all element replacement in the scene, we just need to renormalize // 0. During all element replacement in the scene, we just need to renormalize
// the arrow // the arrow
// TODO (dwelle,mtolmacs): Remove this once Scene.getScene() is removed // TODO (dwelle,mtolmacs): Remove this once Scene.getScene() is removed
if (elementsMap.size === 0 && validateElbowPoints(updatedPoints)) { if (elementsMap.size === 0 && areUpdatedPointsValid) {
return normalizeArrowElementUpdate( return normalizeArrowElementUpdate(
updatedPoints.map((p) => updatedPoints.map((p) =>
pointFrom<GlobalPoint>(arrow.x + p[0], arrow.y + p[1]), pointFrom<GlobalPoint>(arrow.x + p[0], arrow.y + p[1]),
@ -1083,7 +1084,7 @@ export const updateElbowArrowPoints = (
arrow.points[i] ?? pointFrom<LocalPoint>(Infinity, Infinity), arrow.points[i] ?? pointFrom<LocalPoint>(Infinity, Infinity),
), ),
) && ) &&
validateElbowPoints(updatedPoints) areUpdatedPointsValid
) { ) {
return {}; return {};
} }

View file

@ -25,11 +25,16 @@ import {
import { getGridPoint } from "../snapping"; import { getGridPoint } from "../snapping";
import { invariant, tupleToCoors } from "../utils"; import { invariant, tupleToCoors } from "../utils";
import Scene from "../scene/Scene";
import { import {
bindOrUnbindLinearElement, bindOrUnbindLinearElement,
getHoveredElementForBinding, getHoveredElementForBinding,
isBindingEnabled, isBindingEnabled,
} from "./binding"; } from "./binding";
import { updateElbowArrowPoints } from "./elbowArrow";
import { getElementPointsCoords, getMinMaxXYFromCurvePathOps } from "./bounds"; import { getElementPointsCoords, getMinMaxXYFromCurvePathOps } from "./bounds";
import { headingIsHorizontal, vectorToHeading } from "./heading"; import { headingIsHorizontal, vectorToHeading } from "./heading";
import { mutateElement } from "./mutateElement"; import { mutateElement } from "./mutateElement";
@ -57,7 +62,6 @@ import type {
FixedSegment, FixedSegment,
ExcalidrawElbowArrowElement, ExcalidrawElbowArrowElement,
} from "./types"; } from "./types";
import type Scene from "../scene/Scene";
import type { Store } from "../store"; import type { Store } from "../store";
import type { import type {
AppState, AppState,
@ -67,6 +71,7 @@ import type {
NullableGridSize, NullableGridSize,
Zoom, Zoom,
} from "../types"; } from "../types";
import type { Mutable } from "../utility-types"; import type { Mutable } from "../utility-types";
const editorMidPointsCache: { const editorMidPointsCache: {
@ -1274,6 +1279,7 @@ export class LinearElementEditor {
startBinding?: PointBinding | null; startBinding?: PointBinding | null;
endBinding?: PointBinding | null; endBinding?: PointBinding | null;
}, },
sceneElementsMap?: NonDeletedSceneElementsMap,
) { ) {
const { points } = element; const { points } = element;
@ -1317,6 +1323,7 @@ export class LinearElementEditor {
dragging || targetPoint.isDragging === true, dragging || targetPoint.isDragging === true,
false, false,
), ),
sceneElementsMap,
}, },
); );
} }
@ -1430,6 +1437,7 @@ export class LinearElementEditor {
options?: { options?: {
isDragging?: boolean; isDragging?: boolean;
zoom?: AppState["zoom"]; zoom?: AppState["zoom"];
sceneElementsMap?: NonDeletedSceneElementsMap;
}, },
) { ) {
if (isElbowArrow(element)) { if (isElbowArrow(element)) {
@ -1455,9 +1463,26 @@ export class LinearElementEditor {
updates.points = Array.from(nextPoints); updates.points = Array.from(nextPoints);
if (!options?.sceneElementsMap || Scene.getScene(element)) {
mutateElement(element, updates, true, { mutateElement(element, updates, true, {
isDragging: options?.isDragging, isDragging: options?.isDragging,
}); });
} else {
// The element is not in the scene, so we need to use the provided
// scene map.
Object.assign(element, {
...updates,
angle: 0 as Radians,
...updateElbowArrowPoints(
element,
options.sceneElementsMap,
updates,
{
isDragging: options?.isDragging,
},
),
});
}
} else { } else {
const nextCoords = getElementPointsCoords(element, nextPoints); const nextCoords = getElementPointsCoords(element, nextPoints);
const prevCoords = getElementPointsCoords(element, element.points); const prevCoords = getElementPointsCoords(element, element.points);