feat(editor): reduce binding gap (#10739)

* feat(editor): reduce binding gap to 7px

* feat(editor): reduce binding gap to 5px

* feat(editor): reduce binding gap to 3px

* go back to 5px

* update tests
This commit is contained in:
David Luzar
2026-02-05 12:00:56 +01:00
committed by GitHub
parent f39ac4a653
commit 83d3943cd0
8 changed files with 161 additions and 161 deletions
+1 -1
View File
@@ -114,7 +114,7 @@ export type BindingStrategy =
*
* IMPORTANT: currently must be > 0 (this also applies to the computed gap)
*/
export const BASE_BINDING_GAP = 10;
export const BASE_BINDING_GAP = 5;
export const BASE_BINDING_GAP_ELBOW = 5;
export const FOCUS_POINT_SIZE = 10 / 1.5;
@@ -1317,7 +1317,7 @@ describe("Test Linear Elements", () => {
const textElement = h.elements[2] as ExcalidrawTextElementWithContainer;
expect(arrow.endBinding?.elementId).toBe(rect.id);
expect(arrow.width).toBeCloseTo(399);
expect(arrow.width).toBeCloseTo(404);
expect(rect.x).toBe(400);
expect(rect.y).toBe(0);
expect(
@@ -1336,7 +1336,7 @@ describe("Test Linear Elements", () => {
mouse.downAt(rect.x, rect.y);
mouse.moveTo(200, 0);
mouse.upAt(200, 0);
expect(arrow.width).toBeCloseTo(199);
expect(arrow.width).toBeCloseTo(204);
expect(rect.x).toBe(200);
expect(rect.y).toBe(0);
expect(handleBindTextResizeSpy).toHaveBeenCalledWith(
+2 -2
View File
@@ -1350,8 +1350,8 @@ describe("multiple selection", () => {
expect(boundArrow.x).toBeCloseTo(380 * scaleX);
expect(boundArrow.y).toBeCloseTo(240 * scaleY);
expect(boundArrow.points[1][0]).toBeCloseTo(59.7979);
expect(boundArrow.points[1][1]).toBeCloseTo(-79.7305);
expect(boundArrow.points[1][0]).toBeCloseTo(63.4035);
expect(boundArrow.points[1][1]).toBeCloseTo(-84.538);
expect(arrowLabelPos.x + arrowLabel.width / 2).toBeCloseTo(
boundArrow.x + boundArrow.points[1][0] / 2,
@@ -198,7 +198,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "106.79573",
"height": "112.79549",
"id": "id4",
"index": "a2",
"isDeleted": false,
@@ -212,8 +212,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"89.00000",
"106.79573",
"94.00000",
"112.79549",
],
],
"roughness": 1,
@@ -227,8 +227,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 33,
"width": "89.00000",
"version": 34,
"width": "94.00000",
"x": 0,
"y": 0,
}
@@ -334,15 +334,15 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"height": "65.91078",
"height": "74.35962",
"points": [
[
0,
0,
],
[
78,
"65.91078",
88,
"74.35962",
],
],
"startBinding": {
@@ -353,27 +353,27 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"version": 32,
"width": 78,
"version": 33,
"width": 88,
},
"inserted": {
"endBinding": {
"elementId": "id1",
"fixedPoint": [
"0.39512",
"0.60488",
"0.39746",
"0.60254",
],
"mode": "orbit",
},
"height": "1.30876",
"height": "1.66245",
"points": [
[
0,
0,
],
[
78,
"-1.30876",
88,
"-1.66245",
],
],
"startBinding": {
@@ -384,8 +384,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"version": 29,
"width": 78,
"version": 30,
"width": 88,
},
},
},
@@ -428,33 +428,33 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
},
"id4": {
"deleted": {
"height": "106.79573",
"height": "112.79549",
"points": [
[
0,
0,
],
[
"89.00000",
"106.79573",
"94.00000",
"112.79549",
],
],
"startBinding": null,
"version": 33,
"width": "89.00000",
"version": 34,
"width": "94.00000",
"x": 0,
"y": 0,
},
"inserted": {
"height": "65.91078",
"height": "74.35962",
"points": [
[
0,
0,
],
[
78,
"65.91078",
88,
"74.35962",
],
],
"startBinding": {
@@ -465,10 +465,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"version": 32,
"width": 78,
"x": 11,
"y": "49.49137",
"version": 33,
"width": 88,
"x": 6,
"y": "46.67801",
},
},
},
@@ -854,7 +854,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 28,
"version": 26,
"width": 100,
"x": 150,
"y": 0,
@@ -904,15 +904,15 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"id4": {
"deleted": {
"endBinding": null,
"height": "4.68000",
"height": "5.28000",
"points": [
[
0,
0,
],
[
-39,
"-4.68000",
-44,
"-5.28000",
],
],
"startBinding": {
@@ -923,28 +923,28 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"version": 27,
"width": 39,
"y": "4.68000",
"version": 25,
"width": 44,
"y": "5.28000",
},
"inserted": {
"endBinding": {
"elementId": "id1",
"fixedPoint": [
"0.41019",
"0.58981",
"0.41067",
"0.58933",
],
"mode": "orbit",
},
"height": "10.70742",
"height": "9.80848",
"points": [
[
0,
0,
],
[
"52.01909",
"10.70742",
"47.06697",
"9.80848",
],
],
"startBinding": {
@@ -955,9 +955,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"version": 26,
"width": "52.01909",
"y": "-1.72651",
"version": 24,
"width": "47.06697",
"y": "-0.87545",
},
},
},
@@ -1004,21 +1004,21 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
],
"startBinding": null,
"version": 28,
"version": 26,
"width": 100,
"x": 150,
"y": 0,
},
"inserted": {
"height": "4.68000",
"height": "5.28000",
"points": [
[
0,
0,
],
[
-39,
"-4.68000",
-44,
"-5.28000",
],
],
"startBinding": {
@@ -1029,10 +1029,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
"mode": "orbit",
},
"version": 27,
"width": 39,
"x": 139,
"y": "4.68000",
"version": 25,
"width": 44,
"x": 144,
"y": "5.28000",
},
},
},
@@ -1335,7 +1335,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "26.16768",
"height": "29.36414",
"id": "id4",
"index": "Zz",
"isDeleted": false,
@@ -1349,8 +1349,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"78.00000",
"26.16768",
88,
"29.36414",
],
],
"roughness": 1,
@@ -1370,9 +1370,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"type": "arrow",
"updated": 1,
"version": 10,
"width": "78.00000",
"x": 11,
"y": "3.67566",
"width": 88,
"x": 6,
"y": "2.00946",
}
`;
@@ -1698,7 +1698,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "10.76674",
"height": "14.91372",
"id": "id5",
"index": "a0",
"isDeleted": false,
@@ -1712,8 +1712,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"78.00000",
"-10.76674",
"88.00000",
"-14.91372",
],
],
"roughness": 1,
@@ -1733,9 +1733,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"type": "arrow",
"updated": 1,
"version": 11,
"width": "78.00000",
"x": 11,
"y": "35.29320",
"width": "88.00000",
"x": 6,
"y": "37.05219",
}
`;
@@ -1846,7 +1846,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "10.76674",
"height": "14.91372",
"index": "a0",
"isDeleted": false,
"link": null,
@@ -1858,8 +1858,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"78.00000",
"-10.76674",
"88.00000",
"-14.91372",
],
],
"roughness": 1,
@@ -1878,9 +1878,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2,
"type": "arrow",
"version": 11,
"width": "78.00000",
"x": 11,
"y": "35.29320",
"width": "88.00000",
"x": 6,
"y": "37.05219",
},
"inserted": {
"isDeleted": true,
@@ -2398,7 +2398,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "390.11932",
"height": "398.76619",
"id": "id4",
"index": "a2",
"isDeleted": false,
@@ -2412,8 +2412,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"478.03878",
"-390.11932",
488,
"-398.76619",
],
],
"roughness": 1,
@@ -2435,9 +2435,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"type": "arrow",
"updated": 1,
"version": 12,
"width": "478.03878",
"x": 11,
"y": "-8.96692",
"width": 488,
"x": 6,
"y": "-4.89286",
}
`;
@@ -2566,7 +2566,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "390.11932",
"height": "398.76619",
"index": "a2",
"isDeleted": false,
"link": null,
@@ -2578,8 +2578,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
"478.03878",
"-390.11932",
488,
"-398.76619",
],
],
"roughness": 1,
@@ -2600,9 +2600,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"strokeWidth": 2,
"type": "arrow",
"version": 12,
"width": "478.03878",
"x": 11,
"y": "-8.96692",
"width": 488,
"x": 6,
"y": "-4.89286",
},
"inserted": {
"isDeleted": true,
@@ -16383,7 +16383,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -16397,8 +16397,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -16420,9 +16420,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"type": "arrow",
"updated": 1,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
}
`;
@@ -16801,7 +16801,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00561",
"height": "0.00611",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -16813,8 +16813,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00561",
88,
"0.00611",
],
],
"roughness": 1,
@@ -16835,8 +16835,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"version": 8,
"width": "78.00000",
"x": 11,
"width": 88,
"x": 6,
"y": 0,
},
"inserted": {
@@ -17134,7 +17134,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -17148,8 +17148,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -17171,9 +17171,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"type": "arrow",
"updated": 1,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
}
`;
@@ -17442,7 +17442,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -17454,8 +17454,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -17476,9 +17476,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"version": 12,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
},
"inserted": {
"isDeleted": true,
@@ -17783,7 +17783,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -17797,8 +17797,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -17820,9 +17820,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"type": "arrow",
"updated": 1,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
}
`;
@@ -18091,7 +18091,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -18103,8 +18103,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -18125,9 +18125,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"version": 12,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
},
"inserted": {
"isDeleted": true,
@@ -18430,7 +18430,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -18444,8 +18444,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -18467,9 +18467,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"type": "arrow",
"updated": 1,
"version": 12,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
}
`;
@@ -18824,7 +18824,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00561",
"height": "0.00611",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -18836,8 +18836,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00561",
88,
"0.00611",
],
],
"roughness": 1,
@@ -18858,8 +18858,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"version": 8,
"width": "78.00000",
"x": 11,
"width": 88,
"x": 6,
"y": 0,
},
"inserted": {
@@ -19185,7 +19185,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00108",
"height": "0.00092",
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -19199,8 +19199,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00108",
"88.00000",
"0.00092",
],
],
"roughness": 1,
@@ -19222,9 +19222,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"type": "arrow",
"updated": 1,
"version": 13,
"width": "78.00000",
"x": 11,
"y": "0.00807",
"width": "88.00000",
"x": 6,
"y": "0.00849",
}
`;
@@ -19575,7 +19575,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00561",
"height": "0.00611",
"index": "a3",
"isDeleted": false,
"link": null,
@@ -19587,8 +19587,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
0,
],
[
"78.00000",
"0.00561",
88,
"0.00611",
],
],
"roughness": 1,
@@ -19609,8 +19609,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"strokeWidth": 2,
"type": "arrow",
"version": 8,
"width": "78.00000",
"x": 11,
"width": 88,
"x": 6,
"y": 0,
},
"inserted": {
@@ -181,15 +181,15 @@ exports[`move element > rectangles with binding arrow 7`] = `
"endBinding": {
"elementId": "id3",
"fixedPoint": [
"-0.03667",
"0.43000",
"-0.02000",
"0.44667",
],
"mode": "orbit",
},
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "80.00000",
"height": "90.00000",
"id": "id6",
"index": "a2",
"isDeleted": false,
@@ -203,8 +203,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
0,
],
[
"79.00000",
"80.00000",
89,
"90.00000",
],
],
"roughness": 1,
@@ -216,8 +216,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"1.11000",
"0.51000",
"1.06000",
"0.46000",
],
"mode": "orbit",
},
@@ -228,8 +228,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
"updated": 1,
"version": 13,
"versionNonce": 271613161,
"width": "79.00000",
"x": "111.00000",
"y": "51.00000",
"width": 89,
"x": 106,
"y": "46.00000",
}
`;
+2 -2
View File
@@ -4628,7 +4628,7 @@ describe("history", () => {
}),
endBinding: expect.objectContaining({
elementId: rect2.id,
fixedPoint: [0.41019091151895054, 0.5898090884810495],
fixedPoint: [0.4106696643494564, 0.5893303356505437],
mode: "orbit",
}),
}),
@@ -4772,7 +4772,7 @@ describe("history", () => {
// rebound with previous rectangle
endBinding: expect.objectContaining({
elementId: rect2.id,
fixedPoint: [0.39511653718091, 0.6048834628190899],
fixedPoint: [0.39746300211416496, 0.6025369978858351],
mode: "orbit",
}),
}),
+3 -3
View File
@@ -110,8 +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([[111, 51]], 0);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[78, 78]], 0);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[106, 46]], 0);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[88, 88]], 0);
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
@@ -129,7 +129,7 @@ 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, 51]], 0);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[106, 46]], 0);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints(
[[79, 124.1678]],
2,
+2 -2
View File
@@ -80,6 +80,6 @@ test("unselected bound arrows update when rotating their target elements", async
expect(textArrow.x).toEqual(360);
expect(textArrow.y).toEqual(300);
expect(textArrow.points[0]).toEqual([0, 0]);
expect(textArrow.points[1][0]).toBeCloseTo(-95.74, 0);
expect(textArrow.points[1][1]).toBeCloseTo(-119.7354, 0);
expect(textArrow.points[1][0]).toBeCloseTo(-98.87, 0);
expect(textArrow.points[1][1]).toBeCloseTo(-123.65, 0);
});