diff --git a/packages/element/src/binding.ts b/packages/element/src/binding.ts index c94d5e7e3f..b0fa7762c3 100644 --- a/packages/element/src/binding.ts +++ b/packages/element/src/binding.ts @@ -35,7 +35,6 @@ import { import { getAllHoveredElementAtPoint, getHoveredElementForBinding, - hitElementItself, intersectElementWithLineSegment, isPointInElement, } from "./collision"; @@ -644,68 +643,6 @@ export const bindOrUnbindBindingElements = ( }); }; -export const maybeSuggestBindingsForBindingElementAtCoords = ( - linearElement: NonDeleted, - startOrEndOrBoth: "start" | "end" | "both", - scene: Scene, - pointerCoords: GlobalPoint, -): AppState["suggestedBinding"] => { - const startCoords = - startOrEndOrBoth === "start" - ? pointerCoords - : LinearElementEditor.getPointAtIndexGlobalCoordinates( - linearElement, - 0, - scene.getNonDeletedElementsMap(), - ); - const endCoords = - startOrEndOrBoth === "end" - ? pointerCoords - : LinearElementEditor.getPointAtIndexGlobalCoordinates( - linearElement, - -1, - scene.getNonDeletedElementsMap(), - ); - const startHovered = getHoveredElementForBinding( - startCoords, - scene.getNonDeletedElements(), - scene.getNonDeletedElementsMap(), - ); - const endHovered = getHoveredElementForBinding( - endCoords, - scene.getNonDeletedElements(), - scene.getNonDeletedElementsMap(), - ); - - let suggestedBinding: AppState["suggestedBinding"] = null; - - if (startHovered != null && startHovered.id === endHovered?.id) { - const hitStart = hitElementItself({ - element: startHovered, - elementsMap: scene.getNonDeletedElementsMap(), - point: pointFrom(startCoords[0], startCoords[1]), - threshold: 0, - overrideShouldTestInside: true, - }); - const hitEnd = hitElementItself({ - element: endHovered, - elementsMap: scene.getNonDeletedElementsMap(), - point: pointFrom(endCoords[0], endCoords[1]), - threshold: 0, - overrideShouldTestInside: true, - }); - if (hitStart && hitEnd) { - suggestedBinding = startHovered; - } - } else if (startOrEndOrBoth === "start" && startHovered != null) { - suggestedBinding = startHovered; - } else if (startOrEndOrBoth === "end" && endHovered != null) { - suggestedBinding = endHovered; - } - - return suggestedBinding; -}; - export const bindBindingElement = ( arrow: NonDeleted, hoveredElement: ExcalidrawBindableElement, diff --git a/packages/element/src/linearElementEditor.ts b/packages/element/src/linearElementEditor.ts index 913d66e5eb..0b51a9af0c 100644 --- a/packages/element/src/linearElementEditor.ts +++ b/packages/element/src/linearElementEditor.ts @@ -45,7 +45,6 @@ import { calculateFixedPointForNonElbowArrowBinding, getBindingStrategyForDraggingBindingElementEndpoints, isBindingEnabled, - maybeSuggestBindingsForBindingElementAtCoords, updateBoundPoint, } from "./binding"; import { @@ -335,6 +334,7 @@ export class LinearElementEditor { } // Apply the point movement if needed + let suggestedBinding: AppState["suggestedBinding"] = null; if (deltaX || deltaY) { const { positions, updates } = pointDraggingUpdates( [idx], @@ -347,6 +347,12 @@ 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)) { + suggestedBinding = updates?.suggestedBinding ?? null; + } + } // Move the arrow over the bindable object in terms of z-index if (isBindingElement(element)) { @@ -364,17 +370,6 @@ export class LinearElementEditor { } } - // Suggest bindings for first and last point if selected - let suggestedBinding: AppState["suggestedBinding"] = null; - if (isBindingElement(element, false)) { - suggestedBinding = maybeSuggestBindingsForBindingElementAtCoords( - element, - "end", - app.scene, - pointFrom(scenePointerX, scenePointerY), - ); - } - // PERF: Avoid state updates if not absolutely necessary if ( app.state.selectedLinearElement?.customLineAngle === customLineAngle && @@ -530,22 +525,6 @@ export class LinearElementEditor { handleBindTextResize(element, app.scene, false); } - // Suggest bindings for first and last point if selected - if (isBindingElement(element, false)) { - if (isBindingEnabled(app.state) && (startIsSelected || endIsSelected)) { - suggestedBinding = maybeSuggestBindingsForBindingElementAtCoords( - element, - startIsSelected && endIsSelected - ? "both" - : startIsSelected - ? "start" - : "end", - app.scene, - pointFrom(scenePointerX, scenePointerY), - ); - } - } - // Update selected points for elbow arrows because elbow arrows add and // remove points as they route const newSelectedPointsIndices = elbowed @@ -2115,7 +2094,10 @@ const pointDraggingUpdates = ( if (startIsDragged) { updates.suggestedBinding = start.element; } + } else if (startIsDragged) { + updates.suggestedBinding = app.state.suggestedBinding; } + if (end.mode === null) { updates.endBinding = null; } else if (end.mode) { @@ -2134,6 +2116,8 @@ const pointDraggingUpdates = ( if (endIsDragged) { updates.suggestedBinding = end.element; } + } else if (endIsDragged) { + updates.suggestedBinding = app.state.suggestedBinding; } // Simulate the updated arrow for the bind point calculation @@ -2258,11 +2242,13 @@ const pointDraggingUpdates = ( const indices = Array.from(indicesSet); return { - updates: updates.startBinding - ? { - startBinding: updates.startBinding, - } - : undefined, + updates: + updates.startBinding || updates.suggestedBinding + ? { + startBinding: updates.startBinding, + suggestedBinding: updates.suggestedBinding, + } + : undefined, positions: new Map( indices.map((idx) => { return [ diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index c4b68a0411..232bc570f0 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -110,7 +110,6 @@ import { import { getObservedAppState, getCommonBounds, - maybeSuggestBindingsForBindingElementAtCoords, getElementAbsoluteCoords, bindOrUnbindBindingElements, fixBindingsAfterDeletion, @@ -6246,15 +6245,17 @@ class App extends React.Component { // Hovering with a selected tool or creating new linear element via click // and point const { newElement } = this.state; - if (isBindingElement(newElement, false) && isBindingEnabled(this.state)) { - this.setState({ - suggestedBinding: maybeSuggestBindingsForBindingElementAtCoords( - newElement, - "end", - this.scene, - pointFrom(scenePointerX, scenePointerY), - ), - }); + if (!newElement && isBindingEnabled(this.state)) { + const hoveredElement = getHoveredElementForBinding( + pointFrom(scenePointerX, scenePointerY), + this.scene.getNonDeletedElements(), + this.scene.getNonDeletedElementsMap(), + ); + if (hoveredElement) { + this.setState({ + suggestedBinding: hoveredElement, + }); + } } }