fix: Overlap behavior

This commit is contained in:
Mark Tolmacs
2025-09-05 16:03:24 +02:00
parent 109ff756f5
commit b01eea9eb4
2 changed files with 36 additions and 35 deletions

View File

@@ -3,6 +3,7 @@ import {
arrayToMap,
invariant,
isAlwaysInsideBinding,
isTransparent,
} from "@excalidraw/common";
import {
@@ -303,49 +304,31 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
}
// Check and handle nested shapes
if (arrow.startBinding) {
if (hit && arrow.startBinding) {
const otherElement = elementsMap.get(
arrow.startBinding.elementId,
) as ExcalidrawBindableElement;
invariant(otherElement, "Other element must be in the elements map");
const startFocusElements = getAllHoveredElementAtPoint(
getGlobalFixedPointForBindableElement(
arrow.startBinding.fixedPoint,
otherElement,
elementsMap,
),
elements,
elementsMap,
);
const startHoverElements = getAllHoveredElementAtPoint(
LinearElementEditor.getPointAtIndexGlobalCoordinates(
arrow,
0,
elementsMap,
),
elements,
elementsMap,
);
if (
hit &&
otherElement.id !== hit.id &&
(startHoverElements.find((el) => el.id === hit.id) ||
startFocusElements.find((el) => el.id === hit.id))
) {
invariant(otherElement, "Other element must be in the elements map");
const allHits = getAllHoveredElementAtPoint(point, elements, elementsMap);
if (allHits.find((el) => el.id === otherElement.id)) {
const otherIsTransparent = isTransparent(otherElement.backgroundColor);
return {
start: isMultiPoint
? { mode: undefined }
: {
mode: "orbit",
mode: "inside",
element: otherElement,
focusPoint: snapToCenter(
otherElement,
elementsMap,
origin ?? pointFrom<GlobalPoint>(arrow.x, arrow.y),
),
focusPoint: origin ?? pointFrom<GlobalPoint>(arrow.x, arrow.y),
},
end: { mode: "inside", element: hit, focusPoint: point },
end: {
mode: "inside",
element: otherIsTransparent ? hit : otherElement,
focusPoint: point,
},
};
}
}

View File

@@ -117,6 +117,7 @@ type PointMoveOtherUpdates = {
startBinding?: FixedPointBinding | null;
endBinding?: FixedPointBinding | null;
moveMidPointsWithElement?: boolean | null;
suggestedBinding?: AppState["suggestedBinding"] | null;
};
export class LinearElementEditor {
@@ -484,6 +485,7 @@ export class LinearElementEditor {
}
// Apply the point movement if needed
let suggestedBinding: AppState["suggestedBinding"] = null;
if (deltaX || deltaY) {
const { positions, updates } = pointDraggingUpdates(
selectedPointsIndices,
@@ -497,6 +499,13 @@ export class LinearElementEditor {
LinearElementEditor.movePoints(element, app.scene, positions, updates);
// Set the suggested binding from the updates if available
if (isBindingElement(element, false)) {
if (isBindingEnabled(app.state) && (startIsSelected || endIsSelected)) {
suggestedBinding = updates?.suggestedBinding ?? null;
}
}
// Move the arrow over the bindable object in terms of z-index
if (isBindingElement(element) && startIsSelected !== endIsSelected) {
moveArrowAboveBindable(
@@ -522,7 +531,6 @@ export class LinearElementEditor {
}
// Suggest bindings for first and last point if selected
let suggestedBinding: AppState["suggestedBinding"] = null;
if (isBindingElement(element, false)) {
if (isBindingEnabled(app.state) && (startIsSelected || endIsSelected)) {
suggestedBinding = maybeSuggestBindingsForBindingElementAtCoords(
@@ -2086,7 +2094,9 @@ const pointDraggingUpdates = (
);
// Generate the next bindings for the arrow
const updates: PointMoveOtherUpdates = {};
const updates: PointMoveOtherUpdates = {
suggestedBinding: null,
};
if (start.mode === null) {
updates.startBinding = null;
} else if (start.mode) {
@@ -2101,6 +2111,10 @@ const pointDraggingUpdates = (
start.focusPoint,
),
};
if (startIsDragged) {
updates.suggestedBinding = start.element;
}
}
if (end.mode === null) {
updates.endBinding = null;
@@ -2116,6 +2130,10 @@ const pointDraggingUpdates = (
end.focusPoint,
),
};
if (endIsDragged) {
updates.suggestedBinding = end.element;
}
}
// Simulate the updated arrow for the bind point calculation