mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-08-15 06:19:41 +02:00
Compare commits
4 Commits
98702ace88
...
54159b2309
Author | SHA1 | Date | |
---|---|---|---|
![]() |
54159b2309 | ||
![]() |
0983416eff | ||
![]() |
77f728333e | ||
![]() |
e59681e237 |
@@ -145,6 +145,7 @@ export const bindOrUnbindBindingElement = (
|
||||
...opts,
|
||||
},
|
||||
);
|
||||
|
||||
bindOrUnbindBindingElementEdge(arrow, start, "start", scene);
|
||||
bindOrUnbindBindingElementEdge(arrow, end, "end", scene);
|
||||
if (!isElbowArrow(arrow) && (start.focusPoint || end.focusPoint)) {
|
||||
|
@@ -45,6 +45,7 @@ import {
|
||||
import { wrapText } from "./textWrapping";
|
||||
import {
|
||||
isArrowElement,
|
||||
isBindingElement,
|
||||
isBoundToContainer,
|
||||
isElbowArrow,
|
||||
isFrameLikeElement,
|
||||
@@ -73,7 +74,9 @@ import type {
|
||||
ExcalidrawImageElement,
|
||||
ElementsMap,
|
||||
ExcalidrawElbowArrowElement,
|
||||
ExcalidrawArrowElement,
|
||||
} from "./types";
|
||||
import type { ElementUpdate } from "./mutateElement";
|
||||
|
||||
// Returns true when transform (resizing/rotation) happened
|
||||
export const transformElements = (
|
||||
@@ -819,13 +822,29 @@ export const resizeSingleElement = (
|
||||
Number.isFinite(newOrigin.x) &&
|
||||
Number.isFinite(newOrigin.y)
|
||||
) {
|
||||
const updates = {
|
||||
let updates: ElementUpdate<ExcalidrawElement> = {
|
||||
...newOrigin,
|
||||
width: Math.abs(nextWidth),
|
||||
height: Math.abs(nextHeight),
|
||||
...rescaledPoints,
|
||||
};
|
||||
|
||||
if (isBindingElement(latestElement)) {
|
||||
if (latestElement.startBinding) {
|
||||
updates = {
|
||||
...updates,
|
||||
startBinding: null,
|
||||
} as ElementUpdate<ExcalidrawArrowElement>;
|
||||
}
|
||||
|
||||
if (latestElement.endBinding) {
|
||||
updates = {
|
||||
...updates,
|
||||
endBinding: null,
|
||||
} as ElementUpdate<ExcalidrawArrowElement>;
|
||||
}
|
||||
}
|
||||
|
||||
scene.mutateElement(latestElement, updates, {
|
||||
informMutation: shouldInformMutation,
|
||||
isDragging: false,
|
||||
|
@@ -49,3 +49,9 @@ exports[`Test Linear Elements > Test bound text element > should wrap the bound
|
||||
"Online whiteboard
|
||||
collaboration made easy"
|
||||
`;
|
||||
|
||||
exports[`Test Linear Elements > Test bound text element > should wrap the bound text when arrow bound container moves 2`] = `
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`;
|
||||
|
@@ -33,77 +33,6 @@ describe("element binding", () => {
|
||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||
});
|
||||
|
||||
it("should create valid binding if duplicate start/end points", async () => {
|
||||
const rect = API.createElement({
|
||||
type: "rectangle",
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 50,
|
||||
height: 50,
|
||||
});
|
||||
const arrow = API.createElement({
|
||||
type: "arrow",
|
||||
x: 100,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 1,
|
||||
points: [
|
||||
pointFrom(0, 0),
|
||||
pointFrom(0, 0),
|
||||
pointFrom(100, 0),
|
||||
pointFrom(100, 0),
|
||||
],
|
||||
});
|
||||
API.setElements([rect, arrow]);
|
||||
expect(arrow.startBinding).toBe(null);
|
||||
|
||||
// select arrow
|
||||
mouse.clickAt(150, 0);
|
||||
|
||||
// move arrow start to potential binding position
|
||||
mouse.downAt(100, 0);
|
||||
mouse.moveTo(55, 0);
|
||||
mouse.up(0, 0);
|
||||
|
||||
// Point selection is evaluated like the points are rendered,
|
||||
// from right to left. So clicking on the first point should move the joint,
|
||||
// not the start point.
|
||||
expect(arrow.startBinding).toBe(null);
|
||||
|
||||
// Now that the start point is free, move it into overlapping position
|
||||
mouse.downAt(100, 0);
|
||||
mouse.moveTo(55, 0);
|
||||
mouse.up(0, 0);
|
||||
|
||||
expect(API.getSelectedElements()).toEqual([arrow]);
|
||||
|
||||
expect(arrow.startBinding).toEqual({
|
||||
elementId: rect.id,
|
||||
focus: 0,
|
||||
gap: 0,
|
||||
fixedPoint: expect.arrayContaining([1.1, 0]),
|
||||
});
|
||||
|
||||
// Move the end point to the overlapping binding position
|
||||
mouse.downAt(200, 0);
|
||||
mouse.moveTo(55, 0);
|
||||
mouse.up(0, 0);
|
||||
|
||||
// Both the start and the end points should be bound
|
||||
expect(arrow.startBinding).toEqual({
|
||||
elementId: rect.id,
|
||||
focus: 0,
|
||||
gap: 0,
|
||||
fixedPoint: expect.arrayContaining([1.1, 0]),
|
||||
});
|
||||
expect(arrow.endBinding).toEqual({
|
||||
elementId: rect.id,
|
||||
focus: 0,
|
||||
gap: 0,
|
||||
fixedPoint: expect.arrayContaining([1.1, 0]),
|
||||
});
|
||||
});
|
||||
|
||||
//@TODO fix the test with rotation
|
||||
it.skip("rotation of arrow should rebind both ends", () => {
|
||||
const rectLeft = UI.createElement("rectangle", {
|
||||
@@ -399,7 +328,7 @@ describe("element binding", () => {
|
||||
});
|
||||
|
||||
// #6459
|
||||
it("should unbind arrow only from the latest element", () => {
|
||||
it("should unbind arrow when arrow is resized", () => {
|
||||
const rectLeft = UI.createElement("rectangle", {
|
||||
x: 0,
|
||||
width: 200,
|
||||
@@ -427,14 +356,13 @@ describe("element binding", () => {
|
||||
"mouse",
|
||||
).se!;
|
||||
|
||||
Keyboard.keyDown(KEYS.CTRL_OR_CMD);
|
||||
const elX = handles[0] + handles[2] / 2;
|
||||
const elY = handles[1] + handles[3] / 2;
|
||||
mouse.downAt(elX, elY);
|
||||
mouse.moveTo(300, 400);
|
||||
mouse.up();
|
||||
|
||||
expect(arrow.startBinding).not.toBe(null);
|
||||
expect(arrow.startBinding).toBe(null);
|
||||
expect(arrow.endBinding).toBe(null);
|
||||
});
|
||||
|
||||
@@ -538,7 +466,7 @@ describe("Fixed-point arrow binding", () => {
|
||||
expect(arrow.y).toBe(110);
|
||||
});
|
||||
|
||||
it("should create fixed-point binding when one of the arrow endpoint is inside rectangle", () => {
|
||||
it("should create orbit binding when one of the arrow endpoint is inside rectangle", () => {
|
||||
// Create a filled solid rectangle
|
||||
UI.clickTool("rectangle");
|
||||
mouse.downAt(100, 100);
|
||||
@@ -558,8 +486,8 @@ describe("Fixed-point arrow binding", () => {
|
||||
const arrow = API.getSelectedElement() as ExcalidrawLinearElement;
|
||||
expect(arrow.x).toBe(10);
|
||||
expect(arrow.y).toBe(10);
|
||||
expect(arrow.width).toBe(150);
|
||||
expect(arrow.height).toBe(150);
|
||||
expect(arrow.width).toBeCloseTo(86.4669660940663);
|
||||
expect(arrow.height).toBeCloseTo(86.46696609406821);
|
||||
|
||||
// Should bind to the rectangle since endpoint is inside
|
||||
expect(arrow.startBinding).toBe(null);
|
||||
@@ -581,8 +509,8 @@ describe("Fixed-point arrow binding", () => {
|
||||
// Check if the arrow moved
|
||||
expect(arrow.x).toBe(10);
|
||||
expect(arrow.y).toBe(10);
|
||||
expect(arrow.width).toBe(300);
|
||||
expect(arrow.height).toBe(150);
|
||||
expect(arrow.width).toBeCloseTo(235);
|
||||
expect(arrow.height).toBeCloseTo(117.5);
|
||||
});
|
||||
|
||||
it("should maintain relative position when arrow start point is dragged outside and rectangle is moved", () => {
|
||||
@@ -759,7 +687,7 @@ describe("line segment extension binding", () => {
|
||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||
});
|
||||
|
||||
it("should use point binding when extended segment intersects element", () => {
|
||||
it("should bind when extended segment intersects element", () => {
|
||||
// Create a rectangle that will be intersected by the extended arrow segment
|
||||
const rect = API.createElement({
|
||||
type: "rectangle",
|
||||
@@ -779,14 +707,14 @@ describe("line segment extension binding", () => {
|
||||
|
||||
const arrow = API.getSelectedElement() as ExcalidrawLinearElement;
|
||||
|
||||
// Should create a normal point binding since the extended line segment
|
||||
// Should create a binding since the extended line segment
|
||||
// from the last arrow segment intersects the rectangle
|
||||
expect(arrow.endBinding?.elementId).toBe(rect.id);
|
||||
expect(arrow.endBinding).toHaveProperty("focus");
|
||||
expect(arrow.endBinding).toHaveProperty("gap");
|
||||
expect(arrow.endBinding).toHaveProperty("mode");
|
||||
expect(arrow.endBinding).toHaveProperty("fixedPoint");
|
||||
});
|
||||
|
||||
it("should use fixed point binding when extended segment misses element", () => {
|
||||
it("should bind even if the arrow is not pointing at the element", () => {
|
||||
// Create a rectangle positioned so the extended arrow segment will miss it
|
||||
const rect = API.createElement({
|
||||
type: "rectangle",
|
||||
|
@@ -155,8 +155,8 @@ describe("elbow arrow routing", () => {
|
||||
expect(arrow.width).toEqual(90);
|
||||
expect(arrow.height).toEqual(200);
|
||||
});
|
||||
|
||||
it("can generate proper points for bound elbow arrow", () => {
|
||||
const scene = new Scene();
|
||||
const rectangle1 = API.createElement({
|
||||
type: "rectangle",
|
||||
x: -150,
|
||||
@@ -180,17 +180,15 @@ describe("elbow arrow routing", () => {
|
||||
height: 200,
|
||||
points: [pointFrom(0, 0), pointFrom(90, 200)],
|
||||
}) as ExcalidrawElbowArrowElement;
|
||||
scene.insertElement(rectangle1);
|
||||
scene.insertElement(rectangle2);
|
||||
scene.insertElement(arrow);
|
||||
API.setElements([rectangle1, rectangle2, arrow]);
|
||||
|
||||
bindBindingElement(arrow, rectangle1, "orbit", "start", scene);
|
||||
bindBindingElement(arrow, rectangle2, "orbit", "end", scene);
|
||||
bindBindingElement(arrow, rectangle1, "orbit", "start", h.scene);
|
||||
bindBindingElement(arrow, rectangle2, "orbit", "end", h.scene);
|
||||
|
||||
expect(arrow.startBinding).not.toBe(null);
|
||||
expect(arrow.endBinding).not.toBe(null);
|
||||
|
||||
h.app.scene.mutateElement(arrow, {
|
||||
h.scene.mutateElement(arrow, {
|
||||
points: [pointFrom<LocalPoint>(0, 0), pointFrom<LocalPoint>(90, 200)],
|
||||
});
|
||||
|
||||
|
@@ -379,7 +379,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`11`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
|
||||
expect(line.points.length).toEqual(3);
|
||||
expect(line.points).toMatchInlineSnapshot(`
|
||||
@@ -549,7 +549,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`14`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||
|
||||
expect(line.points.length).toEqual(5);
|
||||
|
||||
@@ -600,7 +600,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`11`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
|
||||
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
|
||||
line,
|
||||
@@ -641,7 +641,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`11`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
|
||||
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
|
||||
line,
|
||||
@@ -689,7 +689,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`17`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`10`);
|
||||
|
||||
const newMidPoints = LinearElementEditor.getEditorMidPoints(
|
||||
line,
|
||||
@@ -747,7 +747,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`14`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||
expect(line.points.length).toEqual(5);
|
||||
|
||||
expect((h.elements[0] as ExcalidrawLinearElement).points)
|
||||
@@ -845,7 +845,7 @@ describe("Test Linear Elements", () => {
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`11`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
|
||||
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
|
||||
line,
|
||||
@@ -1316,7 +1316,7 @@ describe("Test Linear Elements", () => {
|
||||
const textElement = h.elements[2] as ExcalidrawTextElementWithContainer;
|
||||
|
||||
expect(arrow.endBinding?.elementId).toBe(rect.id);
|
||||
expect(arrow.width).toBe(400);
|
||||
expect(arrow.width).toBeCloseTo(405);
|
||||
expect(rect.x).toBe(400);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(
|
||||
@@ -1335,7 +1335,7 @@ describe("Test Linear Elements", () => {
|
||||
mouse.downAt(rect.x, rect.y);
|
||||
mouse.moveTo(200, 0);
|
||||
mouse.upAt(200, 0);
|
||||
expect(arrow.width).toBeCloseTo(200, 0);
|
||||
expect(arrow.width).toBeCloseTo(205);
|
||||
expect(rect.x).toBe(200);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(handleBindTextResizeSpy).toHaveBeenCalledWith(
|
||||
|
@@ -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(-60 * scaleX);
|
||||
expect(boundArrow.points[1][1]).toBeCloseTo(-80 * scaleY);
|
||||
expect(boundArrow.points[1][0]).toBeCloseTo(64.1246);
|
||||
expect(boundArrow.points[1][1]).toBeCloseTo(-85.4995);
|
||||
|
||||
expect(arrowLabelPos.x + arrowLabel.width / 2).toBeCloseTo(
|
||||
boundArrow.x + boundArrow.points[1][0] / 2,
|
||||
|
@@ -3,6 +3,7 @@ import { pointFrom } from "@excalidraw/math";
|
||||
import { bindOrUnbindBindingElement } from "@excalidraw/element/binding";
|
||||
import {
|
||||
getHoveredElementForBinding,
|
||||
isSimpleArrow,
|
||||
isValidPolygon,
|
||||
LinearElementEditor,
|
||||
} from "@excalidraw/element";
|
||||
@@ -82,28 +83,30 @@ export const actionFinalize = register<FormData>({
|
||||
app.scene,
|
||||
);
|
||||
|
||||
const newArrow = !appState.selectedLinearElement?.selectedPointsIndices;
|
||||
if (isSimpleArrow(element)) {
|
||||
const newArrow = !appState.selectedLinearElement?.selectedPointsIndices;
|
||||
|
||||
const selectedPointsIndices = newArrow
|
||||
? [element.points.length - 1] // New arrow creation
|
||||
: appState.selectedLinearElement.selectedPointsIndices;
|
||||
const selectedPointsIndices = newArrow
|
||||
? [element.points.length - 1] // New arrow creation
|
||||
: appState.selectedLinearElement.selectedPointsIndices;
|
||||
|
||||
const draggedPoints: PointsPositionUpdates =
|
||||
selectedPointsIndices.reduce((map, index) => {
|
||||
map.set(index, {
|
||||
point: LinearElementEditor.pointFromAbsoluteCoords(
|
||||
element,
|
||||
pointFrom<GlobalPoint>(sceneCoords.x, sceneCoords.y),
|
||||
elementsMap,
|
||||
),
|
||||
});
|
||||
const draggedPoints: PointsPositionUpdates =
|
||||
selectedPointsIndices.reduce((map, index) => {
|
||||
map.set(index, {
|
||||
point: LinearElementEditor.pointFromAbsoluteCoords(
|
||||
element,
|
||||
pointFrom<GlobalPoint>(sceneCoords.x, sceneCoords.y),
|
||||
elementsMap,
|
||||
),
|
||||
});
|
||||
|
||||
return map;
|
||||
}, new Map()) ?? new Map();
|
||||
return map;
|
||||
}, new Map()) ?? new Map();
|
||||
|
||||
bindOrUnbindBindingElement(element, draggedPoints, scene, appState, {
|
||||
newArrow,
|
||||
});
|
||||
bindOrUnbindBindingElement(element, draggedPoints, scene, appState, {
|
||||
newArrow,
|
||||
});
|
||||
}
|
||||
|
||||
if (linearElementEditor !== appState.selectedLinearElement) {
|
||||
// `handlePointerUp()` updated the linear element instance,
|
||||
|
@@ -759,6 +759,27 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.actionManager.registerAction(createRedoAction(this.history));
|
||||
}
|
||||
|
||||
// setState: React.Component<AppProps, AppState>["setState"] = (
|
||||
// state,
|
||||
// callback?,
|
||||
// ) => {
|
||||
// let newState: Parameters<typeof this.setState>[0] = null;
|
||||
// if (typeof state === "function") {
|
||||
// newState = state(this.state, this.props) as Pick<
|
||||
// AppState,
|
||||
// keyof AppState
|
||||
// >;
|
||||
// } else {
|
||||
// newState = state as Pick<AppState, keyof AppState>;
|
||||
// }
|
||||
|
||||
// if (newState && Object.hasOwn(newState, "selectedLinearElement")) {
|
||||
// console.trace(!!newState.selectedLinearElement);
|
||||
// }
|
||||
|
||||
// super.setState(newState, callback);
|
||||
// };
|
||||
|
||||
updateEditorAtom = <Value, Args extends unknown[], Result>(
|
||||
atom: WritableAtom<Value, Args, Result>,
|
||||
...args: Args
|
||||
@@ -2489,47 +2510,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
return this.setState(...args);
|
||||
},
|
||||
},
|
||||
watchState: {
|
||||
configurable: true,
|
||||
value: (
|
||||
callback:
|
||||
| ((
|
||||
prevState: Parameters<typeof setState>,
|
||||
nextState: Parameters<typeof setState> | null,
|
||||
) => void)
|
||||
| undefined,
|
||||
) => {
|
||||
if (callback) {
|
||||
(window as any).__originalSetState = this.setState;
|
||||
this.setState = new Proxy(this.setState, {
|
||||
apply: (target, thisArg, [state, cb]) => {
|
||||
const prevState = thisArg.state;
|
||||
let newState: Parameters<typeof setState> | null = null;
|
||||
|
||||
// Log state change for debugging
|
||||
if (typeof state === "function") {
|
||||
newState = state(prevState, this.props);
|
||||
} else if (state) {
|
||||
newState = state;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(prevState, newState);
|
||||
} catch (error) {
|
||||
console.warn("Error in watchState callback:", error);
|
||||
}
|
||||
|
||||
if (newState) {
|
||||
target.bind(thisArg)(newState as any, cb);
|
||||
}
|
||||
},
|
||||
});
|
||||
} else if ((window as any).__originalSetState) {
|
||||
this.setState = (window as any).__originalSetState;
|
||||
delete (window as any).__originalSetState;
|
||||
}
|
||||
},
|
||||
},
|
||||
app: {
|
||||
configurable: true,
|
||||
value: this,
|
||||
@@ -7974,7 +7954,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
});
|
||||
this.actionManager.executeAction(actionFinalize);
|
||||
this.actionManager.executeAction(actionFinalize, "ui", {
|
||||
event: event.nativeEvent,
|
||||
sceneCoords: {
|
||||
x: pointerDownState.origin.x,
|
||||
y: pointerDownState.origin.y,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8161,7 +8147,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.setState((prevState) => {
|
||||
let linearElementEditor = null;
|
||||
let nextSelectedElementIds = prevState.selectedElementIds;
|
||||
if (isSimpleArrow(element)) {
|
||||
if (isBindingElement(element)) {
|
||||
const linearElement = new LinearElementEditor(
|
||||
element,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
|
@@ -4,9 +4,9 @@ import throttle from "lodash.throttle";
|
||||
import { useEffect, useMemo, useState, memo } from "react";
|
||||
|
||||
import { STATS_PANELS } from "@excalidraw/common";
|
||||
import { getCommonBounds } from "@excalidraw/element";
|
||||
import { getCommonBounds, isBindingElement } from "@excalidraw/element";
|
||||
import { getUncroppedWidthAndHeight } from "@excalidraw/element";
|
||||
import { isElbowArrow, isImageElement } from "@excalidraw/element";
|
||||
import { isImageElement } from "@excalidraw/element";
|
||||
|
||||
import { frameAndChildrenSelectedTogether } from "@excalidraw/element";
|
||||
|
||||
@@ -333,7 +333,7 @@ export const StatsInner = memo(
|
||||
appState={appState}
|
||||
/>
|
||||
</StatsRow>
|
||||
{!isElbowArrow(singleElement) && (
|
||||
{!isBindingElement(singleElement) && (
|
||||
<StatsRow>
|
||||
<Angle
|
||||
property="angle"
|
||||
|
@@ -135,18 +135,7 @@ describe("binding with linear elements", () => {
|
||||
) as HTMLInputElement;
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
expect(inputX).not.toBeNull();
|
||||
UI.updateInput(inputX, String("204"));
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
});
|
||||
|
||||
it("should remain bound to linear element on small angle change", async () => {
|
||||
const linear = h.elements[1] as ExcalidrawLinearElement;
|
||||
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
|
||||
".drag-input",
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
UI.updateInput(inputAngle, String("1"));
|
||||
UI.updateInput(inputX, String("186"));
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
});
|
||||
|
||||
@@ -161,17 +150,6 @@ describe("binding with linear elements", () => {
|
||||
UI.updateInput(inputX, String("254"));
|
||||
expect(linear.startBinding).toBe(null);
|
||||
});
|
||||
|
||||
it("should remain bound to linear element on small angle change", async () => {
|
||||
const linear = h.elements[1] as ExcalidrawLinearElement;
|
||||
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
|
||||
".drag-input",
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
UI.updateInput(inputAngle, String("45"));
|
||||
expect(linear.startBinding).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
// single element
|
||||
|
@@ -439,6 +439,388 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 1`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id40",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"elbowed": false,
|
||||
"endArrowhead": "arrow",
|
||||
"endBinding": {
|
||||
"elementId": "id42",
|
||||
"fixedPoint": [
|
||||
0,
|
||||
0.5001,
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
99,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"startArrowhead": null,
|
||||
"startBinding": {
|
||||
"elementId": "id41",
|
||||
"fixedPoint": [
|
||||
1,
|
||||
0.5001,
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 255.5,
|
||||
"y": 239,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 2`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"autoResize": true,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": null,
|
||||
"containerId": "id39",
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"fontFamily": 5,
|
||||
"fontSize": 20,
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"originalText": "HELLO WORLD!!",
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"text": "HELLO WORLD!!",
|
||||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
"x": 240,
|
||||
"y": 226.5,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 3`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id39",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 155,
|
||||
"y": 189,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 4`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id39",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 355,
|
||||
"y": 189,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 1`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id44",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"elbowed": false,
|
||||
"endArrowhead": "arrow",
|
||||
"endBinding": {
|
||||
"elementId": "id46",
|
||||
"fixedPoint": [
|
||||
0,
|
||||
0.5001,
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
99,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"startArrowhead": null,
|
||||
"startBinding": {
|
||||
"elementId": "id45",
|
||||
"fixedPoint": [
|
||||
1,
|
||||
0.5001,
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 255.5,
|
||||
"y": 239,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 2`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"autoResize": true,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": null,
|
||||
"containerId": "id43",
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"fontFamily": 5,
|
||||
"fontSize": 20,
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"originalText": "HELLO WORLD!!",
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"text": "HELLO WORLD!!",
|
||||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
"x": 240,
|
||||
"y": 226.5,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 3`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"autoResize": true,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id43",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"containerId": null,
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"fontFamily": 5,
|
||||
"fontSize": 20,
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"originalText": "HEYYYYY",
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"text": "HEYYYYY",
|
||||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 70,
|
||||
"x": 185,
|
||||
"y": 226.5,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 4`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"autoResize": true,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id43",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"containerId": null,
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"fontFamily": 5,
|
||||
"fontSize": 20,
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"originalText": "WHATS UP ?",
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": Any<Number>,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"text": "WHATS UP ?",
|
||||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 100,
|
||||
"x": 355,
|
||||
"y": 226.5,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test Transform > should not allow duplicate ids 1`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
|
@@ -432,12 +432,9 @@ describe("Test Transform", () => {
|
||||
boundElements: [{ id: text.id, type: "text" }],
|
||||
startBinding: {
|
||||
elementId: rectangle.id,
|
||||
focus: 0,
|
||||
gap: 0,
|
||||
},
|
||||
endBinding: {
|
||||
elementId: ellipse.id,
|
||||
focus: 0,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -517,12 +514,9 @@ describe("Test Transform", () => {
|
||||
boundElements: [{ id: text1.id, type: "text" }],
|
||||
startBinding: {
|
||||
elementId: text2.id,
|
||||
focus: 0,
|
||||
gap: 0,
|
||||
},
|
||||
endBinding: {
|
||||
elementId: text3.id,
|
||||
focus: 0,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -780,8 +774,8 @@ describe("Test Transform", () => {
|
||||
const [arrow, rect] = excalidrawElements;
|
||||
expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({
|
||||
elementId: "rect-1",
|
||||
focus: -0,
|
||||
gap: 25,
|
||||
fixedPoint: [-2.05, 0.5001],
|
||||
mode: "orbit",
|
||||
});
|
||||
expect(rect.boundElements).toStrictEqual([
|
||||
{
|
||||
|
5
packages/excalidraw/global.d.ts
vendored
5
packages/excalidraw/global.d.ts
vendored
@@ -101,7 +101,10 @@ declare module "image-blob-reduce" {
|
||||
|
||||
interface CustomMatchers {
|
||||
toBeNonNaNNumber(): void;
|
||||
toCloselyEqualPoints(points: readonly [number, number][]): void;
|
||||
toCloselyEqualPoints(
|
||||
points: readonly [number, number][],
|
||||
precision?: number,
|
||||
): void;
|
||||
}
|
||||
|
||||
declare namespace jest {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -95,3 +95,142 @@ exports[`move element > rectangle 5`] = `
|
||||
"y": 40,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`move element > rectangles with binding arrow 5`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id6",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": 1278240551,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 4,
|
||||
"versionNonce": 760410951,
|
||||
"width": 100,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`move element > rectangles with binding arrow 6`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id6",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 300,
|
||||
"id": "id3",
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": 1116226695,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 7,
|
||||
"versionNonce": 271613161,
|
||||
"width": 300,
|
||||
"x": 201,
|
||||
"y": 2,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`move element > rectangles with binding arrow 7`] = `
|
||||
{
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": null,
|
||||
"customData": undefined,
|
||||
"elbowed": false,
|
||||
"endArrowhead": "arrow",
|
||||
"endBinding": {
|
||||
"elementId": "id3",
|
||||
"fixedPoint": [
|
||||
"-0.01667",
|
||||
"0.45000",
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "91.98875",
|
||||
"id": "id6",
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"moveMidPointsWithElement": false,
|
||||
"opacity": 100,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
91,
|
||||
"91.98875",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
"roundness": {
|
||||
"type": 2,
|
||||
},
|
||||
"seed": 23633383,
|
||||
"startArrowhead": null,
|
||||
"startBinding": {
|
||||
"elementId": "id0",
|
||||
"fixedPoint": [
|
||||
"1.05000",
|
||||
"0.45011",
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 14,
|
||||
"versionNonce": 651223591,
|
||||
"width": 91,
|
||||
"x": 105,
|
||||
"y": "45.01062",
|
||||
}
|
||||
`;
|
||||
|
@@ -49,8 +49,8 @@ exports[`multi point mode in linear elements > arrow 3`] = `
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 8,
|
||||
"versionNonce": 1604849351,
|
||||
"version": 7,
|
||||
"versionNonce": 400692809,
|
||||
"width": 70,
|
||||
"x": 30,
|
||||
"y": 30,
|
||||
@@ -104,8 +104,8 @@ exports[`multi point mode in linear elements > line 3`] = `
|
||||
"strokeWidth": 2,
|
||||
"type": "line",
|
||||
"updated": 1,
|
||||
"version": 8,
|
||||
"versionNonce": 1604849351,
|
||||
"version": 7,
|
||||
"versionNonce": 400692809,
|
||||
"width": 70,
|
||||
"x": 30,
|
||||
"y": 30,
|
||||
|
@@ -6161,7 +6161,6 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
||||
"defaultSidebarDockedPreference": false,
|
||||
"editingFrame": null,
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"editingTextElement": null,
|
||||
"elementsToHighlight": null,
|
||||
"errorMessage": null,
|
||||
@@ -6571,7 +6570,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"selectedElementIds": {
|
||||
"id15": true,
|
||||
},
|
||||
"selectedLinearElement": null,
|
||||
"selectedLinearElement": {
|
||||
"elementId": "id15",
|
||||
"isEditing": false,
|
||||
},
|
||||
},
|
||||
"inserted": {
|
||||
"selectedElementIds": {
|
||||
@@ -6599,13 +6601,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 10,
|
||||
"height": 0,
|
||||
"index": "a5",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@@ -6615,8 +6614,8 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
0,
|
||||
],
|
||||
[
|
||||
50,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -6629,14 +6628,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 6,
|
||||
"width": 50,
|
||||
"version": 3,
|
||||
"width": 0,
|
||||
"x": 310,
|
||||
"y": -10,
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 5,
|
||||
"version": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -6644,6 +6643,58 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
},
|
||||
"id": "id17",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {},
|
||||
"inserted": {},
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {},
|
||||
"updated": {
|
||||
"id15": {
|
||||
"deleted": {
|
||||
"height": 10,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
50,
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 5,
|
||||
"width": 50,
|
||||
},
|
||||
"inserted": {
|
||||
"height": 0,
|
||||
"lastCommittedPoint": null,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"version": 3,
|
||||
"width": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": "id19",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
@@ -6676,7 +6727,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 8,
|
||||
"version": 7,
|
||||
"width": 80,
|
||||
},
|
||||
"inserted": {
|
||||
@@ -6695,42 +6746,19 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 6,
|
||||
"version": 5,
|
||||
"width": 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": "id19",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {
|
||||
"selectedLinearElement": {
|
||||
"elementId": "id15",
|
||||
"isEditing": false,
|
||||
},
|
||||
},
|
||||
"inserted": {
|
||||
"selectedLinearElement": null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id21",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {
|
||||
"selectedElementIds": {
|
||||
"id22": true,
|
||||
},
|
||||
"selectedElementIds": {},
|
||||
"selectedLinearElement": null,
|
||||
},
|
||||
"inserted": {
|
||||
@@ -6758,13 +6786,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 10,
|
||||
"height": 0,
|
||||
"index": "a6",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@@ -6774,8 +6799,8 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
0,
|
||||
],
|
||||
[
|
||||
50,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"polygon": false,
|
||||
@@ -6787,14 +6812,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "line",
|
||||
"version": 6,
|
||||
"width": 50,
|
||||
"version": 3,
|
||||
"width": 0,
|
||||
"x": 430,
|
||||
"y": -10,
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 5,
|
||||
"version": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -6802,6 +6827,64 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
},
|
||||
"id": "id24",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {
|
||||
"selectedElementIds": {
|
||||
"id22": true,
|
||||
},
|
||||
},
|
||||
"inserted": {
|
||||
"selectedElementIds": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {},
|
||||
"updated": {
|
||||
"id22": {
|
||||
"deleted": {
|
||||
"height": 10,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
50,
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 5,
|
||||
"width": 50,
|
||||
},
|
||||
"inserted": {
|
||||
"height": 0,
|
||||
"lastCommittedPoint": null,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"version": 3,
|
||||
"width": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": "id26",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
@@ -6834,7 +6917,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 8,
|
||||
"version": 7,
|
||||
"width": 80,
|
||||
},
|
||||
"inserted": {
|
||||
@@ -6853,13 +6936,13 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 6,
|
||||
"version": 5,
|
||||
"width": 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": "id26",
|
||||
"id": "id28",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
@@ -6880,7 +6963,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"removed": {},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id28",
|
||||
"id": "id30",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
@@ -6900,7 +6983,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"removed": {},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id30",
|
||||
"id": "id32",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
@@ -6919,7 +7002,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {
|
||||
"id31": {
|
||||
"id33": {
|
||||
"deleted": {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
@@ -6977,7 +7060,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id33",
|
||||
"id": "id35",
|
||||
},
|
||||
]
|
||||
`;
|
||||
@@ -8634,41 +8717,10 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
"currentItemStrokeStyle": "solid",
|
||||
"currentItemStrokeWidth": 2,
|
||||
"currentItemTextAlign": "left",
|
||||
"cursorButton": "up",
|
||||
"cursorButton": "down",
|
||||
"defaultSidebarDockedPreference": false,
|
||||
"editingFrame": null,
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": {
|
||||
"customLineAngle": null,
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowOriginalStartPoint": [
|
||||
10,
|
||||
10,
|
||||
],
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
"segmentMidpoint": {
|
||||
"added": false,
|
||||
"index": null,
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"segmentMidPointHoveredCoords": null,
|
||||
"selectedPointsIndices": null,
|
||||
"startBindingElement": null,
|
||||
},
|
||||
"editingTextElement": null,
|
||||
"elementsToHighlight": null,
|
||||
"errorMessage": null,
|
||||
@@ -8734,6 +8786,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
@@ -8896,7 +8949,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
"defaultSidebarDockedPreference": false,
|
||||
"editingFrame": null,
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"editingTextElement": null,
|
||||
"elementsToHighlight": null,
|
||||
"errorMessage": null,
|
||||
@@ -8962,6 +9014,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
@@ -9313,41 +9366,10 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
"currentItemStrokeStyle": "solid",
|
||||
"currentItemStrokeWidth": 2,
|
||||
"currentItemTextAlign": "left",
|
||||
"cursorButton": "up",
|
||||
"cursorButton": "down",
|
||||
"defaultSidebarDockedPreference": false,
|
||||
"editingFrame": null,
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": {
|
||||
"customLineAngle": null,
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowOriginalStartPoint": [
|
||||
10,
|
||||
10,
|
||||
],
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
"segmentMidpoint": {
|
||||
"added": false,
|
||||
"index": null,
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"segmentMidPointHoveredCoords": null,
|
||||
"selectedPointsIndices": null,
|
||||
"startBindingElement": null,
|
||||
},
|
||||
"editingTextElement": null,
|
||||
"elementsToHighlight": null,
|
||||
"errorMessage": null,
|
||||
@@ -9413,6 +9435,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
@@ -9754,7 +9777,6 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
"defaultSidebarDockedPreference": false,
|
||||
"editingFrame": null,
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"editingTextElement": null,
|
||||
"elementsToHighlight": null,
|
||||
"errorMessage": null,
|
||||
@@ -9820,6 +9842,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
@@ -14526,37 +14549,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
||||
"defaultSidebarDockedPreference": false,
|
||||
"editingFrame": null,
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": {
|
||||
"customLineAngle": null,
|
||||
"elbowed": false,
|
||||
"elementId": "id6",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"arrowOriginalStartPoint": [
|
||||
130,
|
||||
10,
|
||||
],
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
"segmentMidpoint": {
|
||||
"added": false,
|
||||
"index": null,
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"segmentMidPointHoveredCoords": null,
|
||||
"selectedPointsIndices": null,
|
||||
"startBindingElement": null,
|
||||
},
|
||||
"editingTextElement": null,
|
||||
"elementsToHighlight": null,
|
||||
"errorMessage": null,
|
||||
@@ -14644,27 +14636,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] number
|
||||
|
||||
exports[`regression tests > undo/redo drawing an element > [end of test] redo stack 1`] = `
|
||||
[
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {
|
||||
"selectedLinearElement": null,
|
||||
},
|
||||
"inserted": {
|
||||
"selectedLinearElement": {
|
||||
"elementId": "id6",
|
||||
"isEditing": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id13",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
@@ -14693,7 +14664,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 9,
|
||||
"version": 8,
|
||||
"width": 60,
|
||||
},
|
||||
"inserted": {
|
||||
@@ -14716,12 +14687,64 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 8,
|
||||
"version": 7,
|
||||
"width": 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": "id13",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {},
|
||||
"inserted": {},
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {},
|
||||
"updated": {
|
||||
"id6": {
|
||||
"deleted": {
|
||||
"height": 0,
|
||||
"lastCommittedPoint": null,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"version": 9,
|
||||
"width": 0,
|
||||
},
|
||||
"inserted": {
|
||||
"height": 10,
|
||||
"lastCommittedPoint": [
|
||||
60,
|
||||
10,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
60,
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 8,
|
||||
"width": 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": "id14",
|
||||
},
|
||||
{
|
||||
@@ -14731,11 +14754,16 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"selectedElementIds": {
|
||||
"id3": true,
|
||||
},
|
||||
"selectedLinearElement": null,
|
||||
},
|
||||
"inserted": {
|
||||
"selectedElementIds": {
|
||||
"id6": true,
|
||||
},
|
||||
"selectedLinearElement": {
|
||||
"elementId": "id6",
|
||||
"isEditing": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -14757,13 +14785,10 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 10,
|
||||
"height": 0,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
60,
|
||||
10,
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@@ -14773,8 +14798,8 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
0,
|
||||
],
|
||||
[
|
||||
60,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
@@ -14788,7 +14813,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 9,
|
||||
"width": 60,
|
||||
"width": 0,
|
||||
"x": 130,
|
||||
"y": 10,
|
||||
},
|
||||
|
@@ -79,6 +79,7 @@ describe("move element", () => {
|
||||
const rectA = UI.createElement("rectangle", { size: 100 });
|
||||
const rectB = UI.createElement("rectangle", { x: 200, y: 0, size: 300 });
|
||||
const arrow = UI.createElement("arrow", { x: 110, y: 50, size: 80 });
|
||||
|
||||
act(() => {
|
||||
// bind line to two rectangles
|
||||
bindBindingElement(
|
||||
@@ -92,7 +93,7 @@ describe("move element", () => {
|
||||
arrow.get() as NonDeleted<ExcalidrawArrowElement>,
|
||||
rectB.get(),
|
||||
"orbit",
|
||||
"start",
|
||||
"end",
|
||||
h.app.scene,
|
||||
);
|
||||
});
|
||||
@@ -109,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]).toEqual([110, 50]);
|
||||
expect([arrow.width, arrow.height]).toEqual([80, 80]);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[105, 45]], 0);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[90, 90]], 0);
|
||||
|
||||
renderInteractiveScene.mockClear();
|
||||
renderStaticScene.mockClear();
|
||||
@@ -128,10 +129,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([201, 2]);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[50, 50]]);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([
|
||||
[301.02, 102.02],
|
||||
]);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[105, 45]], 0);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[91, 91]], 0);
|
||||
|
||||
h.elements.forEach((element) => expect(element).toMatchSnapshot());
|
||||
});
|
||||
|
@@ -35,8 +35,8 @@ test("unselected bound arrow updates when rotating its target element", async ()
|
||||
expect(arrow.endBinding?.elementId).toEqual(rectangle.id);
|
||||
expect(arrow.x).toBeCloseTo(-80);
|
||||
expect(arrow.y).toBeCloseTo(50);
|
||||
expect(arrow.width).toBeCloseTo(110.7, 1);
|
||||
expect(arrow.height).toBeCloseTo(0);
|
||||
expect(arrow.width).toBeCloseTo(81.75, 1);
|
||||
expect(arrow.height).toBeCloseTo(62.3, 1);
|
||||
});
|
||||
|
||||
test("unselected bound arrows update when rotating their target elements", async () => {
|
||||
@@ -72,13 +72,13 @@ test("unselected bound arrows update when rotating their target elements", async
|
||||
expect(ellipseArrow.x).toEqual(0);
|
||||
expect(ellipseArrow.y).toEqual(0);
|
||||
expect(ellipseArrow.points[0]).toEqual([0, 0]);
|
||||
expect(ellipseArrow.points[1][0]).toBeCloseTo(48.98, 1);
|
||||
expect(ellipseArrow.points[1][1]).toBeCloseTo(125.79, 1);
|
||||
expect(ellipseArrow.points[1][0]).toBeCloseTo(16.52, 1);
|
||||
expect(ellipseArrow.points[1][1]).toBeCloseTo(216.57, 1);
|
||||
|
||||
expect(textArrow.endBinding?.elementId).toEqual(text.id);
|
||||
expect(textArrow.x).toEqual(360);
|
||||
expect(textArrow.y).toEqual(300);
|
||||
expect(textArrow.points[0]).toEqual([0, 0]);
|
||||
expect(textArrow.points[1][0]).toBeCloseTo(-94, 0);
|
||||
expect(textArrow.points[1][1]).toBeCloseTo(-116.1, 0);
|
||||
expect(textArrow.points[1][0]).toBeCloseTo(-63, 0);
|
||||
expect(textArrow.points[1][1]).toBeCloseTo(-146, 0);
|
||||
});
|
||||
|
@@ -6,11 +6,11 @@ expect.extend({
|
||||
throw new Error("expected and received are not point arrays");
|
||||
}
|
||||
|
||||
const COMPARE = 1 / Math.pow(10, precision || 2);
|
||||
const COMPARE = 1 / precision === 0 ? 1 : Math.pow(10, precision ?? 2);
|
||||
const pass = expected.every(
|
||||
(point, idx) =>
|
||||
Math.abs(received[idx]?.[0] - point[0]) < COMPARE &&
|
||||
Math.abs(received[idx]?.[1] - point[1]) < COMPARE,
|
||||
Math.abs(received[idx][0] - point[0]) < COMPARE &&
|
||||
Math.abs(received[idx][1] - point[1]) < COMPARE,
|
||||
);
|
||||
|
||||
if (!pass) {
|
||||
|
Reference in New Issue
Block a user