From b3d5ba056771c0c2da26fd88e73b66486cc700c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20Tolm=C3=A1cs?= Date: Sun, 6 Apr 2025 13:41:11 +0200 Subject: [PATCH] fix: Linear element is not normalized (#9347) * Fix #9292 --- packages/element/src/linearElementEditor.ts | 1 + .../data/__snapshots__/transform.test.ts.snap | 78 +++++++++---------- packages/excalidraw/data/transform.test.ts | 6 +- packages/excalidraw/data/transform.ts | 10 ++- .../tests/linearElementEditor.test.tsx | 22 +++++- 5 files changed, 73 insertions(+), 44 deletions(-) diff --git a/packages/element/src/linearElementEditor.ts b/packages/element/src/linearElementEditor.ts index bd4e740b2..8a9117bf8 100644 --- a/packages/element/src/linearElementEditor.ts +++ b/packages/element/src/linearElementEditor.ts @@ -133,6 +133,7 @@ export class LinearElementEditor { }; if (!pointsEqual(element.points[0], pointFrom(0, 0))) { console.error("Linear element is not normalized", Error().stack); + LinearElementEditor.normalizePoints(element); } this.selectedPointsIndices = null; diff --git a/packages/excalidraw/data/__snapshots__/transform.test.ts.snap b/packages/excalidraw/data/__snapshots__/transform.test.ts.snap index 917f3d95e..70f8daa31 100644 --- a/packages/excalidraw/data/__snapshots__/transform.test.ts.snap +++ b/packages/excalidraw/data/__snapshots__/transform.test.ts.snap @@ -104,12 +104,12 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "opacity": 100, "points": [ [ - 0.5, - 0.5, + 0, + 0, ], [ - 394.5, - 34.5, + 394, + 34, ], ], "roughness": 1, @@ -129,8 +129,8 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "version": 4, "versionNonce": Any, "width": 395, - "x": 247, - "y": 420, + "x": 247.5, + "y": 420.5, } `; @@ -160,11 +160,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 399.5, + 399, 0, ], ], @@ -185,7 +185,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "version": 4, "versionNonce": Any, "width": 400, - "x": 227, + "x": 227.5, "y": 450, } `; @@ -350,11 +350,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -375,7 +375,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t "version": 4, "versionNonce": Any, "width": 100, - "x": 255, + "x": 255.5, "y": 239, } `; @@ -452,11 +452,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -477,7 +477,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe "version": 4, "versionNonce": Any, "width": 100, - "x": 255, + "x": 255.5, "y": 239, } `; @@ -628,11 +628,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -653,7 +653,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when "version": 4, "versionNonce": Any, "width": 100, - "x": 255, + "x": 255.5, "y": 239, } `; @@ -845,11 +845,11 @@ exports[`Test Transform > should transform linear elements 1`] = ` "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -866,7 +866,7 @@ exports[`Test Transform > should transform linear elements 1`] = ` "version": 2, "versionNonce": Any, "width": 100, - "x": 100, + "x": 100.5, "y": 20, } `; @@ -893,11 +893,11 @@ exports[`Test Transform > should transform linear elements 2`] = ` "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -914,7 +914,7 @@ exports[`Test Transform > should transform linear elements 2`] = ` "version": 2, "versionNonce": Any, "width": 100, - "x": 450, + "x": 450.5, "y": 20, } `; @@ -1490,11 +1490,11 @@ exports[`Test Transform > should transform the elements correctly when linear el "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 272.485, + 271.985, 0, ], ], @@ -1517,7 +1517,7 @@ exports[`Test Transform > should transform the elements correctly when linear el "version": 4, "versionNonce": Any, "width": 272.985, - "x": 111.262, + "x": 111.762, "y": 57, } `; @@ -1862,11 +1862,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -1883,7 +1883,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide "version": 2, "versionNonce": Any, "width": 100, - "x": 100, + "x": 100.5, "y": 100, } `; @@ -1915,11 +1915,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -1936,7 +1936,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide "version": 2, "versionNonce": Any, "width": 100, - "x": 100, + "x": 100.5, "y": 200, } `; @@ -1968,11 +1968,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -1989,7 +1989,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide "version": 2, "versionNonce": Any, "width": 100, - "x": 100, + "x": 100.5, "y": 300, } `; @@ -2021,11 +2021,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide "opacity": 100, "points": [ [ - 0.5, + 0, 0, ], [ - 99.5, + 99, 0, ], ], @@ -2042,7 +2042,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide "version": 2, "versionNonce": Any, "width": 100, - "x": 100, + "x": 100.5, "y": 400, } `; diff --git a/packages/excalidraw/data/transform.test.ts b/packages/excalidraw/data/transform.test.ts index 27643e7e1..0b0718e8e 100644 --- a/packages/excalidraw/data/transform.test.ts +++ b/packages/excalidraw/data/transform.test.ts @@ -427,7 +427,7 @@ describe("Test Transform", () => { const [arrow, text, rectangle, ellipse] = excalidrawElements; expect(arrow).toMatchObject({ type: "arrow", - x: 255, + x: 255.5, y: 239, boundElements: [{ id: text.id, type: "text" }], startBinding: { @@ -512,7 +512,7 @@ describe("Test Transform", () => { expect(arrow).toMatchObject({ type: "arrow", - x: 255, + x: 255.5, y: 239, boundElements: [{ id: text1.id, type: "text" }], startBinding: { @@ -730,7 +730,7 @@ describe("Test Transform", () => { const [, , arrow, text] = excalidrawElements; expect(arrow).toMatchObject({ type: "arrow", - x: 255, + x: 255.5, y: 239, boundElements: [ { diff --git a/packages/excalidraw/data/transform.ts b/packages/excalidraw/data/transform.ts index 9def9f5fc..15ad1ffde 100644 --- a/packages/excalidraw/data/transform.ts +++ b/packages/excalidraw/data/transform.ts @@ -36,6 +36,8 @@ import { syncInvalidIndices } from "@excalidraw/element/fractionalIndex"; import { redrawTextBoundingBox } from "@excalidraw/element/textElement"; +import { LinearElementEditor } from "@excalidraw/element/linearElementEditor"; + import type { ElementConstructorOpts } from "@excalidraw/element/newElement"; import type { @@ -463,7 +465,13 @@ const bindLinearElementToElement = ( newPoints[endPointIndex][1] += delta; } - Object.assign(linearElement, { points: newPoints }); + Object.assign( + linearElement, + LinearElementEditor.getNormalizedPoints({ + ...linearElement, + points: newPoints, + }), + ); return { linearElement, diff --git a/packages/excalidraw/tests/linearElementEditor.test.tsx b/packages/excalidraw/tests/linearElementEditor.test.tsx index 741799d3b..861998584 100644 --- a/packages/excalidraw/tests/linearElementEditor.test.tsx +++ b/packages/excalidraw/tests/linearElementEditor.test.tsx @@ -1,3 +1,5 @@ +import { newArrowElement } from "@excalidraw/element/newElement"; + import { pointCenter, pointFrom } from "@excalidraw/math"; import { act, queryByTestId, queryByText } from "@testing-library/react"; import React from "react"; @@ -19,7 +21,7 @@ import { import * as textElementUtils from "@excalidraw/element/textElement"; import { wrapText } from "@excalidraw/element/textWrapping"; -import type { GlobalPoint } from "@excalidraw/math"; +import type { GlobalPoint, LocalPoint } from "@excalidraw/math"; import type { ExcalidrawElement, @@ -164,6 +166,24 @@ describe("Test Linear Elements", () => { Keyboard.keyPress(KEYS.DELETE); }; + it("should normalize the element points at creation", () => { + const element = newArrowElement({ + type: "arrow", + points: [pointFrom(0.5, 0), pointFrom(100, 100)], + x: 0, + y: 0, + }); + expect(element.points).toEqual([ + pointFrom(0.5, 0), + pointFrom(100, 100), + ]); + new LinearElementEditor(element); + expect(element.points).toEqual([ + pointFrom(0, 0), + pointFrom(99.5, 100), + ]); + }); + it("should not drag line and add midpoint until dragged beyond a threshold", () => { createTwoPointerLinearElement("line"); const line = h.elements[0] as ExcalidrawLinearElement;