fix: Multipoint arrow opposite point movement

This commit is contained in:
Mark Tolmacs 2025-09-02 16:39:38 +02:00
parent 4f43399951
commit 62d7740c94
No known key found for this signature in database
2 changed files with 28 additions and 20 deletions

View File

@ -253,6 +253,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
let start: BindingStrategy = { mode: undefined }; let start: BindingStrategy = { mode: undefined };
let end: BindingStrategy = { mode: undefined }; let end: BindingStrategy = { mode: undefined };
const isMultiPoint = arrow.points.length > 2;
const point = LinearElementEditor.getPointGlobalCoordinates( const point = LinearElementEditor.getPointGlobalCoordinates(
arrow, arrow,
draggingPoints.get(startDragged ? startIdx : endIdx)!.point, draggingPoints.get(startDragged ? startIdx : endIdx)!.point,
@ -287,11 +288,13 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
); );
return { return {
start: { start: isMultiPoint
mode: "inside", ? { mode: undefined }
element: hit, : {
focusPoint: origin ?? center, mode: "inside",
}, element: hit,
focusPoint: origin ?? center,
},
end: { mode: "inside", element: hit, focusPoint: point }, end: { mode: "inside", element: hit, focusPoint: point },
}; };
} }
@ -335,7 +338,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
} }
return { return {
start: other, start: isMultiPoint ? { mode: undefined } : other,
end: current, end: current,
}; };
} }
@ -362,8 +365,6 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
} }
invariant(false, "New arrow creation should not reach here"); invariant(false, "New arrow creation should not reach here");
return { start, end };
}; };
const bindingStrategyForSimpleArrowEndpointDragging = ( const bindingStrategyForSimpleArrowEndpointDragging = (
@ -371,14 +372,13 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
oppositeBinding: FixedPointBinding | null, oppositeBinding: FixedPointBinding | null,
elementsMap: NonDeletedSceneElementsMap, elementsMap: NonDeletedSceneElementsMap,
elements: readonly Ordered<NonDeletedExcalidrawElement>[], elements: readonly Ordered<NonDeletedExcalidrawElement>[],
globalBindMode?: AppState["bindMode"], globalBindMode: AppState["bindMode"],
opts?: { arrow: NonDeleted<ExcalidrawArrowElement>,
appState?: AppState;
},
): { current: BindingStrategy; other: BindingStrategy } => { ): { current: BindingStrategy; other: BindingStrategy } => {
let current: BindingStrategy = { mode: undefined }; let current: BindingStrategy = { mode: undefined };
let other: BindingStrategy = { mode: undefined }; let other: BindingStrategy = { mode: undefined };
const isMultiPoint = arrow.points.length > 2;
const hit = getHoveredElementForBinding(point, elements, elementsMap); const hit = getHoveredElementForBinding(point, elements, elementsMap);
// If the global bind mode is in free binding mode, just bind // If the global bind mode is in free binding mode, just bind
@ -416,14 +416,14 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
current = { element: hit, mode: "orbit", focusPoint: point }; current = { element: hit, mode: "orbit", focusPoint: point };
other = { mode: null }; other = { mode: null };
return { current, other }; return { current, other: isMultiPoint ? { mode: undefined } : other };
} }
// The opposite binding is inside the same element // The opposite binding is inside the same element
// eslint-disable-next-line no-else-return // eslint-disable-next-line no-else-return
else { else {
current = { element: hit, mode: "inside", focusPoint: point }; current = { element: hit, mode: "inside", focusPoint: point };
return { current, other }; return { current, other: isMultiPoint ? { mode: undefined } : other };
} }
} }
// The opposite binding is on a different element // The opposite binding is on a different element
@ -435,7 +435,7 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
focusPoint: snapToCenter(hit, elementsMap, point), focusPoint: snapToCenter(hit, elementsMap, point),
}; };
return { current, other }; return { current, other: isMultiPoint ? { mode: undefined } : other };
} }
} }
// The opposite binding is on a different element or no binding // The opposite binding is on a different element or no binding
@ -449,7 +449,7 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
// Must return as only one endpoint is dragged, therefore // Must return as only one endpoint is dragged, therefore
// the end binding strategy might accidentally gets overriden // the end binding strategy might accidentally gets overriden
return { current, other }; return { current, other: isMultiPoint ? { mode: undefined } : other };
}; };
export const getBindingStrategyForDraggingBindingElementEndpoints = ( export const getBindingStrategyForDraggingBindingElementEndpoints = (
@ -540,7 +540,7 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
elementsMap, elementsMap,
elements, elements,
globalBindMode, globalBindMode,
{ appState }, arrow,
); );
return { start: current, end: other }; return { start: current, end: other };
@ -561,7 +561,7 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
elementsMap, elementsMap,
elements, elements,
globalBindMode, globalBindMode,
{ appState }, arrow,
); );
return { start: other, end: current }; return { start: other, end: current };

View File

@ -2217,11 +2217,19 @@ const pointDraggingUpdates = (
) || nextArrow.points[0] ) || nextArrow.points[0]
: nextArrow.points[0]; : nextArrow.points[0];
const endChanged =
pointDistance(
endLocalPoint,
nextArrow.points[nextArrow.points.length - 1],
) !== 0;
const startChanged =
pointDistance(startLocalPoint, nextArrow.points[0]) !== 0;
const indicesSet = new Set(selectedPointsIndices); const indicesSet = new Set(selectedPointsIndices);
if (startBindable) { if (startBindable && startChanged) {
indicesSet.add(0); indicesSet.add(0);
} }
if (endBindable) { if (endBindable && endChanged) {
indicesSet.add(element.points.length - 1); indicesSet.add(element.points.length - 1);
} }
const indices = Array.from(indicesSet); const indices = Array.from(indicesSet);