mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: Elbow arrow segment fixing & positioning (#8952)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com> Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
parent
8551823da9
commit
91ebf8b0ea
33 changed files with 3282 additions and 1716 deletions
|
@ -10983,7 +10983,9 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
|||
"focus": "-0.00161",
|
||||
"gap": "3.53708",
|
||||
},
|
||||
"endIsSpecial": null,
|
||||
"fillStyle": "solid",
|
||||
"fixedSegments": null,
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "448.10100",
|
||||
|
@ -11000,9 +11002,13 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
|||
0,
|
||||
],
|
||||
[
|
||||
"451.90000",
|
||||
"225.95000",
|
||||
0,
|
||||
],
|
||||
[
|
||||
"225.95000",
|
||||
"448.10100",
|
||||
],
|
||||
[
|
||||
"451.90000",
|
||||
"448.10100",
|
||||
|
@ -11022,6 +11028,7 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
|||
"focus": "-0.00159",
|
||||
"gap": 5,
|
||||
},
|
||||
"startIsSpecial": null,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
|
@ -11147,7 +11154,9 @@ History {
|
|||
"focus": "-0.00161",
|
||||
"gap": "3.53708",
|
||||
},
|
||||
"endIsSpecial": false,
|
||||
"fillStyle": "solid",
|
||||
"fixedSegments": [],
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "236.10000",
|
||||
|
@ -11185,6 +11194,7 @@ History {
|
|||
"focus": "-0.00159",
|
||||
"gap": 5,
|
||||
},
|
||||
"startIsSpecial": false,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
|
|
|
@ -171,8 +171,8 @@ describe("Crop an image", () => {
|
|||
// test corner handle aspect ratio preserving
|
||||
UI.crop(image, "se", naturalWidth, naturalHeight, [initialWidth, 0], true);
|
||||
expect(image.width / image.height).toBe(resizedWidth / resizedHeight);
|
||||
expect(image.width).toBeLessThanOrEqual(initialWidth);
|
||||
expect(image.height).toBeLessThanOrEqual(initialHeight);
|
||||
expect(image.width).toBeLessThanOrEqual(initialWidth + 0.0001);
|
||||
expect(image.height).toBeLessThanOrEqual(initialHeight + 0.0001);
|
||||
|
||||
// reset
|
||||
image = API.createElement({ type: "image", width: 200, height: 100 });
|
||||
|
@ -194,7 +194,7 @@ describe("Crop an image", () => {
|
|||
expect(image.width).toBeCloseTo(image.height);
|
||||
// max height should be reached
|
||||
expect(image.height).toBeCloseTo(initialHeight);
|
||||
expect(image.width).toBe(initialHeight);
|
||||
expect(image.width).toBeCloseTo(initialHeight);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import type {
|
|||
ExcalidrawMagicFrameElement,
|
||||
ExcalidrawElbowArrowElement,
|
||||
ExcalidrawArrowElement,
|
||||
FixedSegment,
|
||||
} from "../../element/types";
|
||||
import { newElement, newTextElement, newLinearElement } from "../../element";
|
||||
import { DEFAULT_VERTICAL_ALIGN, ROUNDNESS } from "../../constants";
|
||||
|
@ -197,6 +198,7 @@ export class API {
|
|||
? ExcalidrawArrowElement["endArrowhead"] | ExcalidrawElbowArrowElement["endArrowhead"]
|
||||
: never;
|
||||
elbowed?: boolean;
|
||||
fixedSegments?: FixedSegment[] | null;
|
||||
}): T extends "arrow" | "line"
|
||||
? ExcalidrawLinearElement
|
||||
: T extends "freedraw"
|
||||
|
|
|
@ -2084,7 +2084,8 @@ describe("history", () => {
|
|||
)[0] as ExcalidrawElbowArrowElement;
|
||||
expect(modifiedArrow.points).toEqual([
|
||||
[0, 0],
|
||||
[451.9000000000001, 0],
|
||||
[225.95000000000005, 0],
|
||||
[225.95000000000005, 448.10100010002003],
|
||||
[451.9000000000001, 448.10100010002003],
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -5,7 +5,6 @@ import type {
|
|||
ExcalidrawLinearElement,
|
||||
ExcalidrawTextElementWithContainer,
|
||||
FontString,
|
||||
SceneElementsMap,
|
||||
} from "../element/types";
|
||||
import { Excalidraw, mutateElement } from "../index";
|
||||
import { reseed } from "../random";
|
||||
|
@ -1353,23 +1352,19 @@ describe("Test Linear Elements", () => {
|
|||
const [origStartX, origStartY] = [line.x, line.y];
|
||||
|
||||
act(() => {
|
||||
LinearElementEditor.movePoints(
|
||||
line,
|
||||
[
|
||||
{
|
||||
index: 0,
|
||||
point: pointFrom(line.points[0][0] + 10, line.points[0][1] + 10),
|
||||
},
|
||||
{
|
||||
index: line.points.length - 1,
|
||||
point: pointFrom(
|
||||
line.points[line.points.length - 1][0] - 10,
|
||||
line.points[line.points.length - 1][1] - 10,
|
||||
),
|
||||
},
|
||||
],
|
||||
new Map() as SceneElementsMap,
|
||||
);
|
||||
LinearElementEditor.movePoints(line, [
|
||||
{
|
||||
index: 0,
|
||||
point: pointFrom(line.points[0][0] + 10, line.points[0][1] + 10),
|
||||
},
|
||||
{
|
||||
index: line.points.length - 1,
|
||||
point: pointFrom(
|
||||
line.points[line.points.length - 1][0] - 10,
|
||||
line.points[line.points.length - 1][1] - 10,
|
||||
),
|
||||
},
|
||||
]);
|
||||
});
|
||||
expect(line.x).toBe(origStartX + 10);
|
||||
expect(line.y).toBe(origStartY + 10);
|
||||
|
|
|
@ -535,7 +535,7 @@ describe("arrow element", () => {
|
|||
|
||||
UI.resize([rectangle, arrow], "nw", [300, 350]);
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(-0.144, 2);
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(-0.144);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.25);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import { STORAGE_KEYS } from "../../../excalidraw-app/app_constants";
|
|||
import { getSelectedElements } from "../scene/selection";
|
||||
import type { ExcalidrawElement } from "../element/types";
|
||||
import { UI } from "./helpers/ui";
|
||||
import { diffStringsUnified } from "jest-diff";
|
||||
|
||||
const customQueries = {
|
||||
...queries,
|
||||
|
@ -246,6 +247,36 @@ expect.extend({
|
|||
pass: false,
|
||||
};
|
||||
},
|
||||
|
||||
toCloselyEqualPoints(received, expected, precision) {
|
||||
if (!Array.isArray(received) || !Array.isArray(expected)) {
|
||||
throw new Error("expected and received are not point arrays");
|
||||
}
|
||||
|
||||
const COMPARE = 1 / Math.pow(10, precision || 2);
|
||||
const pass = received.every(
|
||||
(point, idx) =>
|
||||
Math.abs(expected[idx]?.[0] - point[0]) < COMPARE &&
|
||||
Math.abs(expected[idx]?.[1] - point[1]) < COMPARE,
|
||||
);
|
||||
|
||||
if (!pass) {
|
||||
return {
|
||||
message: () => ` The provided array of points are not close enough.
|
||||
|
||||
${diffStringsUnified(
|
||||
JSON.stringify(expected, undefined, 2),
|
||||
JSON.stringify(received, undefined, 2),
|
||||
)}`,
|
||||
pass: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
message: () => `expected ${received} to not be close to ${expected}`,
|
||||
pass: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue