fix: Arrow drag start in bindable area jumps across bindable (#10676)

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Márk Tolmács
2026-01-20 12:38:40 +01:00
committed by GitHub
parent 60ab14c2f6
commit 9ba0f5dbc9
5 changed files with 137 additions and 146 deletions
+7 -1
View File
@@ -15,6 +15,7 @@ import {
pointFrom,
pointFromVector,
pointRotateRads,
pointsEqual,
vectorFromPoint,
vectorNormalize,
vectorScale,
@@ -1602,7 +1603,12 @@ export const updateBoundPoint = (
if (
binding == null ||
// We only need to update the other end if this is a 2 point line element
(binding.elementId !== bindableElement.id && arrow.points.length > 2)
(binding.elementId !== bindableElement.id && arrow.points.length > 2) ||
// Initial arrow created on pointer down needs to not update the points
pointsEqual(
arrow.points[arrow.points.length - 1],
pointFrom<LocalPoint>(0, 0),
)
) {
return null;
}
@@ -2398,7 +2398,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "361.17383",
"height": "353.93938",
"id": "id4",
"index": "a2",
"isDeleted": false,
@@ -2412,8 +2412,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"478.06757",
"-361.17383",
"478.03877",
"-353.93938",
],
],
"roughness": 1,
@@ -2424,8 +2424,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.54844",
"0.54844",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -2434,10 +2434,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 14,
"width": "478.06757",
"version": 12,
"width": "478.03877",
"x": 11,
"y": "-37.61782",
"y": "-45.14705",
}
`;
@@ -2566,7 +2566,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "361.17383",
"height": "353.93938",
"index": "a2",
"isDeleted": false,
"link": null,
@@ -2578,8 +2578,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"478.06757",
"-361.17383",
"478.03877",
"-353.93938",
],
],
"roughness": 1,
@@ -2590,8 +2590,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.54844",
"0.54844",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -2599,14 +2599,14 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"version": 14,
"width": "478.06757",
"version": 12,
"width": "478.03877",
"x": 11,
"y": "-37.61782",
"y": "-45.14705",
},
"inserted": {
"isDeleted": true,
"version": 11,
"version": 9,
},
},
},
@@ -16383,7 +16383,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -16397,8 +16397,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -16409,8 +16409,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -16419,10 +16419,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 14,
"width": 78,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
}
`;
@@ -16467,12 +16467,12 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
"version": 14,
"version": 12,
},
"inserted": {
"endBinding": {
@@ -16487,12 +16487,12 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
"version": 11,
"version": 9,
},
},
},
@@ -16801,7 +16801,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00096",
"height": "0.00561",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -16814,7 +16814,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"78.00000",
"0.00096",
"0.00561",
],
],
"roughness": 1,
@@ -16825,8 +16825,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -16834,14 +16834,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"version": 10,
"version": 8,
"width": "78.00000",
"x": 11,
"y": "0.00830",
"y": 0,
},
"inserted": {
"isDeleted": true,
"version": 9,
"version": 7,
},
},
},
@@ -17134,7 +17134,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -17148,8 +17148,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -17160,8 +17160,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -17170,10 +17170,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 14,
"width": 78,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
}
`;
@@ -17442,7 +17442,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -17454,8 +17454,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -17466,8 +17466,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -17475,14 +17475,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"version": 14,
"width": 78,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
},
"inserted": {
"isDeleted": true,
"version": 11,
"version": 9,
},
},
},
@@ -17783,7 +17783,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -17797,8 +17797,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -17809,8 +17809,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -17819,10 +17819,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 14,
"width": 78,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
}
`;
@@ -18091,7 +18091,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -18103,8 +18103,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -18115,8 +18115,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -18124,14 +18124,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"version": 14,
"width": 78,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
},
"inserted": {
"isDeleted": true,
"version": 11,
"version": 9,
},
},
},
@@ -18430,7 +18430,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -18444,8 +18444,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -18456,8 +18456,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -18466,10 +18466,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 14,
"width": 78,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
}
`;
@@ -18530,12 +18530,12 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
"version": 14,
"version": 12,
},
"inserted": {
"endBinding": {
@@ -18547,7 +18547,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"mode": "orbit",
},
"startBinding": null,
"version": 11,
"version": 9,
},
},
"id2": {
@@ -18824,7 +18824,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00096",
"height": "0.00561",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -18837,7 +18837,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"78.00000",
"0.00096",
"0.00561",
],
],
"roughness": 1,
@@ -18848,8 +18848,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -18857,14 +18857,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"version": 10,
"version": 8,
"width": "78.00000",
"x": 11,
"y": "0.00830",
"y": 0,
},
"inserted": {
"isDeleted": true,
"version": 9,
"version": 7,
},
},
},
@@ -19185,7 +19185,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "1.22525",
"height": "0.00108",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -19199,8 +19199,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
78,
"-1.22525",
"78.00000",
"0.00108",
],
],
"roughness": 1,
@@ -19211,8 +19211,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -19221,10 +19221,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 15,
"width": 78,
"version": 13,
"width": "78.00000",
"x": 11,
"y": "2.19362",
"y": "0.00807",
}
`;
@@ -19296,17 +19296,17 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
"version": 15,
"version": 13,
},
"inserted": {
"endBinding": null,
"startBinding": null,
"version": 12,
"version": 10,
},
},
},
@@ -19575,7 +19575,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00096",
"height": "0.00561",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -19588,7 +19588,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"78.00000",
"0.00096",
"0.00561",
],
],
"roughness": 1,
@@ -19599,8 +19599,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.53796",
"0.53796",
"0.50010",
"0.50010",
],
"mode": "orbit",
},
@@ -19608,14 +19608,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"version": 10,
"version": 8,
"width": "78.00000",
"x": 11,
"y": "0.00830",
"y": 0,
},
"inserted": {
"isDeleted": true,
"version": 9,
"version": 7,
},
},
},
@@ -163,7 +163,7 @@ exports[`move element > rectangles with binding arrow 6`] = `
"type": "rectangle",
"updated": 1,
"version": 7,
"versionNonce": 888958951,
"versionNonce": 735304455,
"width": 300,
"x": 201,
"y": 2,
@@ -182,14 +182,14 @@ exports[`move element > rectangles with binding arrow 7`] = `
"elementId": "id3",
"fixedPoint": [
"-0.03667",
"0.42773",
"0.43000",
],
"mode": "orbit",
},
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "124.16785",
"height": "80.00000",
"id": "id6",
"index": "a2",
"isDeleted": false,
@@ -204,7 +204,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
],
[
"79.00000",
"124.16785",
"80.00000",
],
],
"roughness": 1,
@@ -216,8 +216,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"1.10000",
"-0.04577",
"1.11000",
"0.51000",
],
"mode": "orbit",
},
@@ -226,10 +226,10 @@ exports[`move element > rectangles with binding arrow 7`] = `
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 12,
"versionNonce": 2066753033,
"version": 13,
"versionNonce": 271613161,
"width": "79.00000",
"x": 111,
"y": "6.14995",
"x": "111.00000",
"y": "51.00000",
}
`;
+6 -18
View File
@@ -1590,9 +1590,7 @@ describe("history", () => {
expect(API.getUndoStack().length).toBe(5);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5379561888991137, 0.5379561888991137,
]),
fixedPoint: expect.arrayContaining([0.5001, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1615,9 +1613,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(1);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5379561888991137, 0.5379561888991137,
]),
fixedPoint: expect.arrayContaining([0.5001, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1640,9 +1636,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(0);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5379561888991137, 0.5379561888991137,
]),
fixedPoint: expect.arrayContaining([0.5001, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1673,9 +1667,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(0);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5379561888991137, 0.5379561888991137,
]),
fixedPoint: expect.arrayContaining([0.5001, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1698,9 +1690,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(1);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5379561888991137, 0.5379561888991137,
]),
fixedPoint: expect.arrayContaining([0.5001, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -5061,9 +5051,7 @@ describe("history", () => {
id: arrowId,
startBinding: expect.objectContaining({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.548442798411514, 0.548442798411514,
]),
fixedPoint: expect.arrayContaining([0.5001, 0.5001]),
}),
endBinding: expect.objectContaining({
elementId: rect2.id,
+4 -7
View File
@@ -110,11 +110,8 @@ describe("move element", () => {
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([200, 0]);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[110, -4.576537]], 0);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints(
[[79, 132.89433]],
0,
);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[111, 51]], 0);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[78, 78]], 0);
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
@@ -132,10 +129,10 @@ describe("move element", () => {
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([201, 2]);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[111, 6.1499]], 0);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[111, 51]], 0);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints(
[[79, 124.1678]],
0,
2,
);
h.elements.forEach((element) => expect(element).toMatchSnapshot());