Fix microjump on drag binding, no keyboard move if bound arrow

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2025-04-04 18:33:36 +02:00
parent c3924a8f8c
commit 06b3750a2f
8 changed files with 80 additions and 69 deletions

View file

@ -6,6 +6,7 @@ import {
invariant,
isDevEnv,
isTestEnv,
toLocalPoint,
} from "@excalidraw/common";
import {
@ -523,8 +524,19 @@ export const bindLinearElement = (
),
};
}
const points = Array.from(linearElement.points);
points[edgePointIndex] = toLocalPoint(
bindPointToSnapToElementOutline(
linearElement,
hoveredElement,
startOrEnd,
elementsMap,
),
linearElement,
);
mutateElement(linearElement, {
points,
[startOrEnd === "start" ? "startBinding" : "endBinding"]: binding,
});

View file

@ -356,16 +356,17 @@ export class LinearElementEditor {
elementsMap,
true,
);
const newGlobalPointPosition = pointRotateRads(
pointFrom<GlobalPoint>(
element.x + newPointPosition[0],
element.y + newPointPosition[1],
),
pointFrom<GlobalPoint>(cx, cy),
element.angle,
);
const avoidancePoint = getOutlineAvoidingPoint(
element,
pointRotateRads(
pointFrom<GlobalPoint>(
element.x + newPointPosition[0],
element.y + newPointPosition[1],
),
pointFrom<GlobalPoint>(cx, cy),
element.angle,
),
newGlobalPointPosition,
pointIndex,
app.scene,
app.state.zoom,
@ -373,8 +374,14 @@ export class LinearElementEditor {
newPointPosition = LinearElementEditor.createPointAt(
element,
elementsMap,
avoidancePoint[0] - linearElementEditor.pointerOffset.x,
avoidancePoint[1] - linearElementEditor.pointerOffset.y,
avoidancePoint[0] === newGlobalPointPosition[0]
? newGlobalPointPosition[0] -
linearElementEditor.pointerOffset.x
: avoidancePoint[0],
avoidancePoint[1] === newGlobalPointPosition[1]
? newGlobalPointPosition[1] -
linearElementEditor.pointerOffset.y
: avoidancePoint[1],
null,
);
}

View file

@ -173,7 +173,7 @@ describe("element binding", () => {
},
);
it("should unbind arrow when moving it with keyboard", () => {
it("should not move bound arrows when moving it with keyboard", () => {
const rectangle = UI.createElement("rectangle", {
x: 75,
y: 0,
@ -208,16 +208,10 @@ describe("element binding", () => {
Keyboard.keyPress(KEYS.ARROW_LEFT);
});
});
expect(arrow.endBinding).toBe(null);
Keyboard.withModifierKeys({ shift: true }, () => {
// We have to move a significant distance to return to the binding
Array.from({ length: 10 }).forEach(() => {
Keyboard.keyPress(KEYS.ARROW_RIGHT);
});
});
// We are back in the binding zone but we shouldn't rebind
expect(arrow.endBinding).toBe(null);
expect(arrow.endBinding?.elementId).toBe(rectangle.id);
expect(arrow.x).toBe(0);
expect(arrow.y).toBe(0);
});
it("should unbind on bound element deletion", () => {

View file

@ -1052,7 +1052,7 @@ describe("multiple selection", () => {
0,
);
//console.log(JSON.stringify(h.elements));
expect(rightBoundArrow.width).toBeCloseTo(100 * scale + 1, 0);
expect(rightBoundArrow.width).toBeCloseTo(100 * scale, 0);
expect(rightBoundArrow.height).toBeCloseTo(0);
expect(rightBoundArrow.angle).toEqual(0);
expect(rightBoundArrow.startBinding).toBeNull();