fix: #8475 Arrow updated on both sides (#8593)

This commit is contained in:
Ritobroto Kalita 2025-03-04 21:54:39 +05:30 committed by GitHub
parent d21c6a1bc6
commit c5d3bb0b6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 77 additions and 38 deletions

View File

@ -17,7 +17,11 @@ import type {
} from "./types"; } from "./types";
import type { Bounds } from "./bounds"; import type { Bounds } from "./bounds";
import { getCenterForBounds } from "./bounds"; import {
getCenterForBounds,
getElementBounds,
doBoundsIntersect,
} from "./bounds";
import type { AppState } from "../types"; import type { AppState } from "../types";
import { isPointOnShape } from "@excalidraw/utils/collision"; import { isPointOnShape } from "@excalidraw/utils/collision";
import { import {
@ -743,6 +747,21 @@ export const updateBoundElements = (
return; return;
} }
// Check for intersections before updating bound elements incase connected elements overlap
const startBindingElement = element.startBinding
? elementsMap.get(element.startBinding.elementId)
: null;
const endBindingElement = element.endBinding
? elementsMap.get(element.endBinding.elementId)
: null;
let startBounds: Bounds | null = null;
let endBounds: Bounds | null = null;
if (startBindingElement && endBindingElement) {
startBounds = getElementBounds(startBindingElement, elementsMap);
endBounds = getElementBounds(endBindingElement, elementsMap);
}
const bindings = { const bindings = {
startBinding: maybeCalculateNewGapWhenScaling( startBinding: maybeCalculateNewGapWhenScaling(
changedElement, changedElement,
@ -770,7 +789,12 @@ export const updateBoundElements = (
bindableElement && bindableElement &&
isBindableElement(bindableElement) && isBindableElement(bindableElement) &&
(bindingProp === "startBinding" || bindingProp === "endBinding") && (bindingProp === "startBinding" || bindingProp === "endBinding") &&
changedElement.id === element[bindingProp]?.elementId (changedElement.id === element[bindingProp]?.elementId ||
(changedElement.id ===
element[
bindingProp === "startBinding" ? "endBinding" : "startBinding"
]?.elementId &&
!doBoundsIntersect(startBounds, endBounds)))
) { ) {
const point = updateBoundPoint( const point = updateBoundPoint(
element, element,

View File

@ -1013,3 +1013,17 @@ export const getCenterForBounds = (bounds: Bounds): GlobalPoint =>
bounds[0] + (bounds[2] - bounds[0]) / 2, bounds[0] + (bounds[2] - bounds[0]) / 2,
bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[1] + (bounds[3] - bounds[1]) / 2,
); );
export const doBoundsIntersect = (
bounds1: Bounds | null,
bounds2: Bounds | null,
): boolean => {
if (bounds1 == null || bounds2 == null) {
return false;
}
const [minX1, minY1, maxX1, maxY1] = bounds1;
const [minX2, minY2, maxX2, maxY2] = bounds2;
return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2;
};

View File

@ -219,7 +219,9 @@ export class LinearElementEditor {
}); });
} }
/** @returns whether point was dragged */ /**
* @returns whether point was dragged
*/
static handlePointDragging( static handlePointDragging(
event: PointerEvent, event: PointerEvent,
app: AppClassProperties, app: AppClassProperties,

View File

@ -297,7 +297,7 @@ History {
"focus": "0.00990", "focus": "0.00990",
"gap": 1, "gap": 1,
}, },
"height": "0.98597", "height": "0.98586",
"points": [ "points": [
[ [
0, 0,
@ -305,7 +305,7 @@ History {
], ],
[ [
"98.58579", "98.58579",
"-0.98597", "-0.98586",
], ],
], ],
"startBinding": { "startBinding": {
@ -320,7 +320,7 @@ History {
"focus": "-0.02000", "focus": "-0.02000",
"gap": 1, "gap": 1,
}, },
"height": "0.00119", "height": "0.00000",
"points": [ "points": [
[ [
0, 0,
@ -328,7 +328,7 @@ History {
], ],
[ [
"98.58579", "98.58579",
"0.00119", "0.00000",
], ],
], ],
"startBinding": { "startBinding": {
@ -409,7 +409,7 @@ History {
"focus": "0.00990", "focus": "0.00990",
"gap": 1, "gap": 1,
}, },
"height": "0.98700", "height": "0.98586",
"points": [ "points": [
[ [
0, 0,
@ -417,7 +417,7 @@ History {
], ],
[ [
"98.58579", "98.58579",
"-0.98700", "-0.98586",
], ],
], ],
"startBinding": { "startBinding": {
@ -425,7 +425,7 @@ History {
"focus": "0.02970", "focus": "0.02970",
"gap": 1, "gap": 1,
}, },
"y": "0.99465", "y": "0.99364",
}, },
}, },
"id175" => Delta { "id175" => Delta {
@ -1238,7 +1238,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": "2.52823", "height": "1.30038",
"id": "id178", "id": "id178",
"index": "Zz", "index": "Zz",
"isDeleted": false, "isDeleted": false,
@ -1253,7 +1253,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
], ],
[ [
"98.58579", "98.58579",
"-2.52823", "1.30038",
], ],
], ],
"roughness": 1, "roughness": 1,
@ -1278,7 +1278,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"version": 11, "version": 11,
"width": "98.58579", "width": "98.58579",
"x": "0.70711", "x": "0.70711",
"y": "3.82861", "y": 0,
} }
`; `;
@ -1609,7 +1609,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": "2.52823", "height": "1.30038",
"id": "id181", "id": "id181",
"index": "a0", "index": "a0",
"isDeleted": false, "isDeleted": false,
@ -1624,7 +1624,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
], ],
[ [
"98.58579", "98.58579",
"-2.52823", "1.30038",
], ],
], ],
"roughness": 1, "roughness": 1,
@ -1649,7 +1649,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"version": 11, "version": 11,
"width": "98.58579", "width": "98.58579",
"x": "0.70711", "x": "0.70711",
"y": "3.82861", "y": 0,
} }
`; `;
@ -1767,7 +1767,7 @@ History {
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": "22.07000", "height": "11.27227",
"index": "a0", "index": "a0",
"isDeleted": false, "isDeleted": false,
"lastCommittedPoint": null, "lastCommittedPoint": null,
@ -1780,8 +1780,8 @@ History {
0, 0,
], ],
[ [
"99.27949", "98.58579",
"-22.07000", "11.27227",
], ],
], ],
"roughness": 1, "roughness": 1,
@ -1802,9 +1802,9 @@ History {
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 2, "strokeWidth": 2,
"type": "arrow", "type": "arrow",
"width": "99.27949", "width": "98.58579",
"x": "0.01341", "x": "0.70711",
"y": "33.34227", "y": 0,
}, },
"inserted": { "inserted": {
"isDeleted": true, "isDeleted": true,
@ -2320,7 +2320,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": "410.63965", "height": "374.05754",
"id": "id186", "id": "id186",
"index": "a2", "index": "a2",
"isDeleted": false, "isDeleted": false,
@ -2334,8 +2334,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0, 0,
], ],
[ [
"501.24760", "502.78936",
"-410.63965", "-374.05754",
], ],
], ],
"roughness": 1, "roughness": 1,
@ -2354,9 +2354,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"type": "arrow", "type": "arrow",
"updated": 1, "updated": 1,
"version": 10, "version": 10,
"width": "501.24760", "width": "502.78936",
"x": "0.70711", "x": "-0.83465",
"y": 0, "y": "-36.58211",
} }
`; `;

View File

@ -196,7 +196,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": "84.41974", "height": "87.29887",
"id": "id2", "id": "id2",
"index": "a2", "index": "a2",
"isDeleted": false, "isDeleted": false,
@ -210,8 +210,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
0, 0,
], ],
[ [
"83.92893", "86.85786",
"84.41974", "87.29887",
], ],
], ],
"roughness": 1, "roughness": 1,
@ -232,8 +232,8 @@ exports[`move element > rectangles with binding arrow 7`] = `
"updated": 1, "updated": 1,
"version": 11, "version": 11,
"versionNonce": 1051383431, "versionNonce": 1051383431,
"width": "83.92893", "width": "86.85786",
"x": 110, "x": "107.07107",
"y": 50, "y": "47.07107",
} }
`; `;

View File

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import "../../utils/test-utils";
import { render, fireEvent, act, unmountComponent } from "./test-utils"; import { render, fireEvent, act, unmountComponent } from "./test-utils";
import { Excalidraw } from "../index"; import { Excalidraw } from "../index";
import * as StaticScene from "../renderer/staticScene"; import * as StaticScene from "../renderer/staticScene";
@ -121,10 +122,8 @@ describe("move element", () => {
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy(); expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
expect([rectA.x, rectA.y]).toEqual([0, 0]); expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([201, 2]); expect([rectB.x, rectB.y]).toEqual([201, 2]);
expect([Math.round(arrow.x), Math.round(arrow.y)]).toEqual([110, 50]); expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[107.07, 47.07]]);
expect([Math.round(arrow.width), Math.round(arrow.height)]).toEqual([ expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[86.86, 87.3]]);
84, 84,
]);
h.elements.forEach((element) => expect(element).toMatchSnapshot()); h.elements.forEach((element) => expect(element).toMatchSnapshot());
}); });