Fix arrows

This commit is contained in:
Mark Tolmacs 2025-07-31 20:23:26 +02:00
parent 452be6e5ea
commit a846ebb6e7
No known key found for this signature in database
2 changed files with 94 additions and 81 deletions

View File

@ -422,6 +422,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
}; };
let current: BindingStrategy; let current: BindingStrategy;
// We are hovering another element with the end point
if (hovered) { if (hovered) {
const isInsideBinding = const isInsideBinding =
globalBindMode === "inside" || isAlwaysInsideBinding(hovered); globalBindMode === "inside" || isAlwaysInsideBinding(hovered);
@ -447,9 +448,18 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
// No start binding // No start binding
if (!arrow.startBinding) { if (!arrow.startBinding) {
end = hovered if (hovered) {
? { element: hovered, mode: "orbit", focusPoint: point } const isInsideBinding =
: { mode: null }; globalBindMode === "inside" || isAlwaysInsideBinding(hovered);
end = {
mode: isInsideBinding ? "inside" : "orbit",
element: hovered,
focusPoint: point,
};
} else {
end = { mode: null };
}
return { start, end }; return { start, end };
} }
@ -500,33 +510,6 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
return { current, other }; return { current, other };
} }
// Update the start point on new arrows
if (
opts?.newArrow &&
opts?.appState?.selectedLinearElement &&
oppositeBinding
) {
const oppositeBindingElement = elementsMap.get(
oppositeBinding?.elementId,
) as ExcalidrawBindableElement;
if (oppositeBinding.elementId !== hovered?.id) {
other = {
element: oppositeBindingElement,
mode: "orbit",
focusPoint: elementCenterPoint(oppositeBindingElement, elementsMap),
};
} else {
other = {
element: oppositeBindingElement,
mode: "inside",
focusPoint:
opts.appState.selectedLinearElement.pointerDownState
.arrowOriginalStartPoint ?? point,
};
}
}
// Dragged point is outside of any bindable element // Dragged point is outside of any bindable element
// so we break any existing binding // so we break any existing binding
if (!hovered) { if (!hovered) {
@ -1378,10 +1361,10 @@ export const snapToCenter = (
element: ExcalidrawBindableElement, element: ExcalidrawBindableElement,
elementsMap: ElementsMap, elementsMap: ElementsMap,
p: GlobalPoint, p: GlobalPoint,
tolerance: number = 0.05,
) => { ) => {
const extent = Math.min(element.width, element.height);
const center = elementCenterPoint(element, elementsMap); const center = elementCenterPoint(element, elementsMap);
if (pointDistance(p, center) < tolerance) { if (pointDistance(p, center) < extent * 0.05) {
return pointFrom<GlobalPoint>(center[0], center[1]); return pointFrom<GlobalPoint>(center[0], center[1]);
} }
return p; return p;

View File

@ -8584,63 +8584,93 @@ class App extends React.Component<AppProps, AppState> {
return; return;
} }
const hoveredElement = getHoveredElementForBinding( const element = LinearElementEditor.getElement(
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y), linearElementEditor.elementId,
this.scene.getNonDeletedElements(),
elementsMap, elementsMap,
this.state.zoom,
); );
let [x, y] = [pointerCoords.x, pointerCoords.y];
// Timed bind mode handler for arrow elements if (isBindingElement(element)) {
if (this.state.bindMode === "orbit") { const hoveredElement = getHoveredElementForBinding(
if (this.bindModeHandler && !hoveredElement) { pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
clearTimeout(this.bindModeHandler); this.scene.getNonDeletedElements(),
this.bindModeHandler = null; elementsMap,
} else if (!this.bindModeHandler && hoveredElement) { this.state.zoom,
this.bindModeHandler = setTimeout(() => { );
if (hoveredElement) {
flushSync(() => { // Timed bind mode handler for arrow elements
this.setState({ if (this.state.bindMode === "orbit") {
bindMode: "inside", if (this.bindModeHandler && !hoveredElement) {
clearTimeout(this.bindModeHandler);
this.bindModeHandler = null;
} else if (!this.bindModeHandler && hoveredElement) {
this.bindModeHandler = setTimeout(() => {
if (hoveredElement) {
flushSync(() => {
this.setState({
bindMode: "inside",
});
}); });
});
const newState = LinearElementEditor.handlePointDragging(
event,
this,
this.lastPointerMoveCoords?.x ?? pointerDownState.origin.x,
this.lastPointerMoveCoords?.y ?? pointerDownState.origin.y,
linearElementEditor,
);
if (newState) {
pointerDownState.lastCoords.x =
this.lastPointerMoveCoords?.x ?? pointerDownState.origin.x;
pointerDownState.lastCoords.y =
this.lastPointerMoveCoords?.y ?? pointerDownState.origin.y;
pointerDownState.drag.hasOccurred = true;
this.setState(newState); const [lastX, lastY] =
hoveredElement && element.startBinding?.mode !== "inside"
? snapToCenter(
hoveredElement,
elementsMap,
pointFrom<GlobalPoint>(
this.lastPointerMoveCoords?.x ??
pointerDownState.origin.x,
this.lastPointerMoveCoords?.y ??
pointerDownState.origin.y,
),
)
: [
this.lastPointerMoveCoords?.x ??
pointerDownState.origin.x,
this.lastPointerMoveCoords?.y ??
pointerDownState.origin.y,
];
const newState = LinearElementEditor.handlePointDragging(
event,
this,
lastX,
lastY,
linearElementEditor,
);
if (newState) {
pointerDownState.lastCoords.x =
this.lastPointerMoveCoords?.x ??
pointerDownState.origin.x;
pointerDownState.lastCoords.y =
this.lastPointerMoveCoords?.y ??
pointerDownState.origin.y;
pointerDownState.drag.hasOccurred = true;
this.setState(newState);
}
} else {
this.bindModeHandler = null;
} }
} else { }, BIND_MODE_TIMEOUT);
this.bindModeHandler = null; }
} } else if (!hoveredElement) {
}, BIND_MODE_TIMEOUT); flushSync(() => {
} this.setState({
} else if (!hoveredElement) { bindMode: "orbit",
flushSync(() => { });
this.setState({
bindMode: "orbit",
}); });
}); }
}
const [x, y] = hoveredElement [x, y] =
? snapToCenter( hoveredElement && element.startBinding?.mode !== "inside"
hoveredElement, ? snapToCenter(
elementsMap, hoveredElement,
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y), elementsMap,
10, pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
) )
: [pointerCoords.x, pointerCoords.y]; : [pointerCoords.x, pointerCoords.y];
}
const newState = LinearElementEditor.handlePointDragging( const newState = LinearElementEditor.handlePointDragging(
event, event,