mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-11 13:56:34 -04:00
fix: Multi-point arrows and linears
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
parent
bcf3127fe5
commit
8a3ba853ab
@ -16,7 +16,6 @@ import {
|
||||
DEFAULT_SIDEBAR,
|
||||
debounce,
|
||||
} from "@excalidraw/common";
|
||||
import { clearElementsForLocalStorage } from "@excalidraw/element";
|
||||
import {
|
||||
createStore,
|
||||
entries,
|
||||
@ -81,7 +80,7 @@ const saveDataStateToLocalStorage = (
|
||||
|
||||
localStorage.setItem(
|
||||
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
|
||||
JSON.stringify(clearElementsForLocalStorage(elements)),
|
||||
JSON.stringify(elements),
|
||||
);
|
||||
localStorage.setItem(
|
||||
STORAGE_KEYS.LOCAL_STORAGE_APP_STATE,
|
||||
|
@ -2,7 +2,6 @@ import {
|
||||
clearAppStateForLocalStorage,
|
||||
getDefaultAppState,
|
||||
} from "@excalidraw/excalidraw/appState";
|
||||
import { clearElementsForLocalStorage } from "@excalidraw/element";
|
||||
|
||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||
@ -50,7 +49,7 @@ export const importFromLocalStorage = () => {
|
||||
let elements: ExcalidrawElement[] = [];
|
||||
if (savedElements) {
|
||||
try {
|
||||
elements = clearElementsForLocalStorage(JSON.parse(savedElements));
|
||||
elements = JSON.parse(savedElements);
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
// Do nothing because elements array is already empty
|
||||
|
@ -278,7 +278,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
|
||||
// With new arrows it represents the continuous dragging of the end point
|
||||
if (endDragged) {
|
||||
const origin = appState?.selectedLinearElement?.pointerDownState.origin;
|
||||
const origin = appState?.selectedLinearElement?.initialState.origin;
|
||||
|
||||
// Inside -> inside binding
|
||||
if (hit && arrow.startBinding?.elementId === hit.id) {
|
||||
@ -309,7 +309,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
invariant(otherElement, "Other element must be in the elements map");
|
||||
|
||||
const otherIsInsideBinding =
|
||||
!!appState.selectedLinearElement?.pointerDownState.arrowStartIsInside;
|
||||
!!appState.selectedLinearElement?.initialState.arrowStartIsInside;
|
||||
|
||||
const other: BindingStrategy = {
|
||||
mode: otherIsInsideBinding ? "inside" : "orbit",
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { toIterable } from "@excalidraw/common";
|
||||
|
||||
import { isInvisiblySmallElement } from "./sizeHelpers";
|
||||
import { isLinearElementType } from "./typeChecks";
|
||||
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
@ -52,27 +51,6 @@ export const isNonDeletedElement = <T extends ExcalidrawElement>(
|
||||
element: T,
|
||||
): element is NonDeleted<T> => !element.isDeleted;
|
||||
|
||||
const _clearElements = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
): ExcalidrawElement[] =>
|
||||
getNonDeletedElements(elements).map((element) =>
|
||||
isLinearElementType(element.type)
|
||||
? { ...element, lastCommittedPoint: null }
|
||||
: element,
|
||||
);
|
||||
|
||||
export const clearElementsForDatabase = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
) => _clearElements(elements);
|
||||
|
||||
export const clearElementsForExport = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
) => _clearElements(elements);
|
||||
|
||||
export const clearElementsForLocalStorage = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
) => _clearElements(elements);
|
||||
|
||||
export * from "./align";
|
||||
export * from "./binding";
|
||||
export * from "./bounds";
|
||||
|
@ -126,7 +126,7 @@ export class LinearElementEditor {
|
||||
/** indices */
|
||||
public readonly selectedPointsIndices: readonly number[] | null;
|
||||
|
||||
public readonly pointerDownState: Readonly<{
|
||||
public readonly initialState: Readonly<{
|
||||
prevSelectedPointsIndices: readonly number[] | null;
|
||||
/** index */
|
||||
lastClickedPoint: number;
|
||||
@ -142,6 +142,7 @@ export class LinearElementEditor {
|
||||
/** whether you're dragging a point */
|
||||
public readonly isDragging: boolean;
|
||||
public readonly lastUncommittedPoint: LocalPoint | null;
|
||||
public readonly lastCommittedPoint: LocalPoint | null;
|
||||
public readonly pointerOffset: Readonly<{ x: number; y: number }>;
|
||||
public readonly hoverPointIndex: number;
|
||||
public readonly segmentMidPointHoveredCoords: GlobalPoint | null;
|
||||
@ -149,6 +150,11 @@ export class LinearElementEditor {
|
||||
public readonly customLineAngle: number | null;
|
||||
public readonly isEditing: boolean;
|
||||
|
||||
// @deprecated renamed to initialState because the data is used during linear
|
||||
// element click creation as well (with multiple pointer down events)
|
||||
// @ts-ignore
|
||||
public readonly pointerDownState: never;
|
||||
|
||||
constructor(
|
||||
element: NonDeleted<ExcalidrawLinearElement>,
|
||||
elementsMap: ElementsMap,
|
||||
@ -167,9 +173,10 @@ export class LinearElementEditor {
|
||||
}
|
||||
this.selectedPointsIndices = null;
|
||||
this.lastUncommittedPoint = null;
|
||||
this.lastCommittedPoint = null;
|
||||
this.isDragging = false;
|
||||
this.pointerOffset = { x: 0, y: 0 };
|
||||
this.pointerDownState = {
|
||||
this.initialState = {
|
||||
prevSelectedPointsIndices: null,
|
||||
lastClickedPoint: -1,
|
||||
origin: null,
|
||||
@ -396,25 +403,31 @@ export class LinearElementEditor {
|
||||
): Pick<AppState, "suggestedBinding" | "selectedLinearElement"> | null {
|
||||
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||
const elements = app.scene.getNonDeletedElements();
|
||||
const { elbowed, elementId, pointerDownState, selectedPointsIndices } =
|
||||
const { elbowed, elementId, initialState, selectedPointsIndices } =
|
||||
linearElementEditor;
|
||||
const { lastClickedPoint } = pointerDownState;
|
||||
const { lastClickedPoint } = initialState;
|
||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||
|
||||
invariant(element, "Element being dragged must exist in the scene");
|
||||
|
||||
invariant(element.points.length > 1, "Element must have at least 2 points");
|
||||
|
||||
invariant(
|
||||
selectedPointsIndices,
|
||||
"There must be selected points in order to drag them",
|
||||
);
|
||||
|
||||
invariant(
|
||||
lastClickedPoint > -1 && selectedPointsIndices.includes(lastClickedPoint),
|
||||
"There must be a valid lastClickedPoint in order to drag it",
|
||||
lastClickedPoint > -1 &&
|
||||
selectedPointsIndices.includes(lastClickedPoint) &&
|
||||
element.points[lastClickedPoint],
|
||||
`There must be a valid lastClickedPoint in order to drag it. selectedPointsIndices(${JSON.stringify(
|
||||
selectedPointsIndices,
|
||||
)}) points(0..${
|
||||
element.points.length - 1
|
||||
}) lastClickedPoint(${lastClickedPoint})`,
|
||||
);
|
||||
|
||||
invariant(element.points.length > 1, "Element must have at least 2 points");
|
||||
|
||||
invariant(
|
||||
!elbowed ||
|
||||
selectedPointsIndices?.filter(
|
||||
@ -551,8 +564,8 @@ export class LinearElementEditor {
|
||||
const newLinearElementEditor = {
|
||||
...linearElementEditor,
|
||||
selectedPointsIndices: newSelectedPointsIndices,
|
||||
pointerDownState: {
|
||||
...linearElementEditor.pointerDownState,
|
||||
initialState: {
|
||||
...linearElementEditor.initialState,
|
||||
lastClickedPoint: newLastClickedPoint,
|
||||
},
|
||||
segmentMidPointHoveredCoords: newSelectedMidPointHoveredCoords,
|
||||
@ -575,8 +588,12 @@ export class LinearElementEditor {
|
||||
): LinearElementEditor {
|
||||
const elementsMap = scene.getNonDeletedElementsMap();
|
||||
|
||||
const { elementId, selectedPointsIndices, isDragging, pointerDownState } =
|
||||
editingLinearElement;
|
||||
const {
|
||||
elementId,
|
||||
selectedPointsIndices,
|
||||
isDragging,
|
||||
initialState: pointerDownState,
|
||||
} = editingLinearElement;
|
||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||
if (!element) {
|
||||
return editingLinearElement;
|
||||
@ -647,8 +664,8 @@ export class LinearElementEditor {
|
||||
isDragging: false,
|
||||
pointerOffset: { x: 0, y: 0 },
|
||||
customLineAngle: null,
|
||||
pointerDownState: {
|
||||
...editingLinearElement.pointerDownState,
|
||||
initialState: {
|
||||
...editingLinearElement.initialState,
|
||||
origin: null,
|
||||
arrowStartIsInside: false,
|
||||
},
|
||||
@ -948,7 +965,7 @@ export class LinearElementEditor {
|
||||
store.scheduleCapture();
|
||||
ret.linearElementEditor = {
|
||||
...linearElementEditor,
|
||||
pointerDownState: {
|
||||
initialState: {
|
||||
prevSelectedPointsIndices: linearElementEditor.selectedPointsIndices,
|
||||
lastClickedPoint: -1,
|
||||
origin: pointFrom<GlobalPoint>(scenePointer.x, scenePointer.y),
|
||||
@ -1009,7 +1026,7 @@ export class LinearElementEditor {
|
||||
: null;
|
||||
ret.linearElementEditor = {
|
||||
...linearElementEditor,
|
||||
pointerDownState: {
|
||||
initialState: {
|
||||
prevSelectedPointsIndices: linearElementEditor.selectedPointsIndices,
|
||||
lastClickedPoint: clickedPointIndex,
|
||||
origin: pointFrom<GlobalPoint>(scenePointer.x, scenePointer.y),
|
||||
@ -1082,19 +1099,16 @@ export class LinearElementEditor {
|
||||
let newPoint: LocalPoint;
|
||||
|
||||
if (shouldRotateWithDiscreteAngle(event) && points.length >= 2) {
|
||||
const lastCommittedPoint = points[points.length - 2];
|
||||
const anchor = points[points.length - 2];
|
||||
const [width, height] = LinearElementEditor._getShiftLockedDelta(
|
||||
element,
|
||||
elementsMap,
|
||||
lastCommittedPoint,
|
||||
anchor,
|
||||
pointFrom(scenePointerX, scenePointerY),
|
||||
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
newPoint = pointFrom(
|
||||
width + lastCommittedPoint[0],
|
||||
height + lastCommittedPoint[1],
|
||||
);
|
||||
newPoint = pointFrom(width + anchor[0], height + anchor[1]);
|
||||
} else {
|
||||
newPoint = LinearElementEditor.createPointAt(
|
||||
element,
|
||||
@ -1530,18 +1544,18 @@ export class LinearElementEditor {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { segmentMidpoint } = linearElementEditor.pointerDownState;
|
||||
const { segmentMidpoint } = linearElementEditor.initialState;
|
||||
|
||||
if (
|
||||
segmentMidpoint.added ||
|
||||
segmentMidpoint.value === null ||
|
||||
segmentMidpoint.index === null ||
|
||||
linearElementEditor.pointerDownState.origin === null
|
||||
linearElementEditor.initialState.origin === null
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const origin = linearElementEditor.pointerDownState.origin!;
|
||||
const origin = linearElementEditor.initialState.origin!;
|
||||
const dist = pointDistance(
|
||||
origin,
|
||||
pointFrom(pointerCoords.x, pointerCoords.y),
|
||||
@ -1570,12 +1584,12 @@ export class LinearElementEditor {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
const { segmentMidpoint } = linearElementEditor.pointerDownState;
|
||||
const { segmentMidpoint } = linearElementEditor.initialState;
|
||||
const ret: {
|
||||
pointerDownState: LinearElementEditor["pointerDownState"];
|
||||
pointerDownState: LinearElementEditor["initialState"];
|
||||
selectedPointsIndices: LinearElementEditor["selectedPointsIndices"];
|
||||
} = {
|
||||
pointerDownState: linearElementEditor.pointerDownState,
|
||||
pointerDownState: linearElementEditor.initialState,
|
||||
selectedPointsIndices: linearElementEditor.selectedPointsIndices,
|
||||
};
|
||||
|
||||
@ -1595,9 +1609,9 @@ export class LinearElementEditor {
|
||||
scene.mutateElement(element, { points });
|
||||
|
||||
ret.pointerDownState = {
|
||||
...linearElementEditor.pointerDownState,
|
||||
...linearElementEditor.initialState,
|
||||
segmentMidpoint: {
|
||||
...linearElementEditor.pointerDownState.segmentMidpoint,
|
||||
...linearElementEditor.initialState.segmentMidpoint,
|
||||
added: true,
|
||||
},
|
||||
lastClickedPoint: segmentMidpoint.index!,
|
||||
@ -1915,7 +1929,7 @@ export class LinearElementEditor {
|
||||
scene: Scene,
|
||||
): Pick<
|
||||
LinearElementEditor,
|
||||
"segmentMidPointHoveredCoords" | "pointerDownState"
|
||||
"segmentMidPointHoveredCoords" | "initialState"
|
||||
> {
|
||||
const elementsMap = scene.getNonDeletedElementsMap();
|
||||
const element = LinearElementEditor.getElement(
|
||||
@ -1978,8 +1992,8 @@ export class LinearElementEditor {
|
||||
return {
|
||||
...linearElement,
|
||||
segmentMidPointHoveredCoords: point,
|
||||
pointerDownState: {
|
||||
...linearElement.pointerDownState,
|
||||
initialState: {
|
||||
...linearElement.initialState,
|
||||
segmentMidpoint: {
|
||||
added: false,
|
||||
index: element.fixedSegments![offset].index,
|
||||
|
@ -452,7 +452,6 @@ export const newFreeDrawElement = (
|
||||
points: opts.points || [],
|
||||
pressures: opts.pressures || [],
|
||||
simulatePressure: opts.simulatePressure,
|
||||
lastCommittedPoint: null,
|
||||
};
|
||||
};
|
||||
|
||||
@ -466,7 +465,7 @@ export const newLinearElement = (
|
||||
const element = {
|
||||
..._newElementBase<ExcalidrawLinearElement>(opts.type, opts),
|
||||
points: opts.points || [],
|
||||
lastCommittedPoint: null,
|
||||
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
startArrowhead: null,
|
||||
@ -501,7 +500,6 @@ export const newArrowElement = <T extends boolean>(
|
||||
return {
|
||||
..._newElementBase<ExcalidrawElbowArrowElement>(opts.type, opts),
|
||||
points: opts.points || [],
|
||||
lastCommittedPoint: null,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
startArrowhead: opts.startArrowhead || null,
|
||||
@ -516,7 +514,6 @@ export const newArrowElement = <T extends boolean>(
|
||||
return {
|
||||
..._newElementBase<ExcalidrawArrowElement>(opts.type, opts),
|
||||
points: opts.points || [],
|
||||
lastCommittedPoint: null,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
startArrowhead: opts.startArrowhead || null,
|
||||
|
@ -1103,7 +1103,7 @@ export function getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) {
|
||||
smoothing: 0.5,
|
||||
streamline: 0.5,
|
||||
easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine
|
||||
last: !!element.lastCommittedPoint, // LastCommittedPoint is added on pointerup
|
||||
last: true,
|
||||
};
|
||||
|
||||
return getSvgPathFromStroke(getStroke(inputPoints as number[][], options));
|
||||
|
@ -321,7 +321,6 @@ export type ExcalidrawLinearElement = _ExcalidrawElementBase &
|
||||
Readonly<{
|
||||
type: "line" | "arrow";
|
||||
points: readonly LocalPoint[];
|
||||
lastCommittedPoint: LocalPoint | null;
|
||||
startBinding: FixedPointBinding | null;
|
||||
endBinding: FixedPointBinding | null;
|
||||
startArrowhead: Arrowhead | null;
|
||||
@ -378,7 +377,6 @@ export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase &
|
||||
points: readonly LocalPoint[];
|
||||
pressures: readonly number[];
|
||||
simulatePressure: boolean;
|
||||
lastCommittedPoint: LocalPoint | null;
|
||||
}>;
|
||||
|
||||
export type FileId = string & { _brand: "FileId" };
|
||||
|
@ -44,3 +44,14 @@ exports[`Test Linear Elements > Test bound text element > should resize and posi
|
||||
"Online whiteboard
|
||||
collaboration made easy"
|
||||
`;
|
||||
|
||||
exports[`Test Linear Elements > Test bound text element > should wrap the bound text when arrow bound container moves 1`] = `
|
||||
"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"
|
||||
`;
|
||||
|
@ -257,8 +257,8 @@ describe("binding for simple arrows", () => {
|
||||
const arrow = API.getSelectedElement() as ExcalidrawLinearElement;
|
||||
expect(arrow.x).toBe(10);
|
||||
expect(arrow.y).toBe(10);
|
||||
expect(arrow.width).toBeCloseTo(86.4669660940663);
|
||||
expect(arrow.height).toBeCloseTo(86.46696609406821);
|
||||
expect(arrow.width).toBeCloseTo(85.75985931287957);
|
||||
expect(arrow.height).toBeCloseTo(85.75985931288186);
|
||||
|
||||
// Should bind to the rectangle since endpoint is inside
|
||||
expect(arrow.startBinding).toBe(null);
|
||||
@ -280,8 +280,8 @@ describe("binding for simple arrows", () => {
|
||||
// Check if the arrow moved
|
||||
expect(arrow.x).toBe(10);
|
||||
expect(arrow.y).toBe(10);
|
||||
expect(arrow.width).toBeCloseTo(235);
|
||||
expect(arrow.height).toBeCloseTo(117.5);
|
||||
expect(arrow.width).toBeCloseTo(234);
|
||||
expect(arrow.height).toBeCloseTo(117);
|
||||
|
||||
// Restore bindable
|
||||
mouse.reset();
|
||||
@ -309,49 +309,9 @@ describe("binding for simple arrows", () => {
|
||||
expect(arrow.width).toBeCloseTo(86, 0);
|
||||
expect(arrow.height).toBeCloseTo(86, 0);
|
||||
});
|
||||
|
||||
it("should happen 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",
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
});
|
||||
|
||||
API.setElements([rect]);
|
||||
|
||||
// Draw an arrow that doesn't point at the rectangle (extended segment will miss)
|
||||
UI.clickTool("arrow");
|
||||
mouse.reset();
|
||||
mouse.downAt(125, 93); // Start point
|
||||
mouse.moveTo(175, 93); // End point - arrow direction is horizontal, misses rectangle
|
||||
mouse.up();
|
||||
|
||||
const arrow = API.getSelectedElement() as ExcalidrawLinearElement;
|
||||
|
||||
// Should create a fixed point binding since the extended line segment
|
||||
// from the last arrow segment misses the rectangle
|
||||
expect(arrow.startBinding?.elementId).toBe(rect.id);
|
||||
expect(arrow.startBinding).toHaveProperty("fixedPoint");
|
||||
expect(
|
||||
(arrow.startBinding as FixedPointBinding).fixedPoint[0],
|
||||
).toBeGreaterThanOrEqual(0);
|
||||
expect(
|
||||
(arrow.startBinding as FixedPointBinding).fixedPoint[0],
|
||||
).toBeLessThanOrEqual(1);
|
||||
expect(
|
||||
(arrow.startBinding as FixedPointBinding).fixedPoint[1],
|
||||
).toBeLessThanOrEqual(0.5);
|
||||
expect(
|
||||
(arrow.startBinding as FixedPointBinding).fixedPoint[1],
|
||||
).toBeLessThanOrEqual(1);
|
||||
expect(arrow.endBinding).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("", () => {
|
||||
describe("additional binding behavior", () => {
|
||||
beforeEach(async () => {
|
||||
mouse.reset();
|
||||
|
||||
@ -411,8 +371,8 @@ describe("binding for simple arrows", () => {
|
||||
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
size: 50,
|
||||
y: 5,
|
||||
size: 70,
|
||||
});
|
||||
|
||||
expect(arrow.endBinding?.elementId).toBe(rectangle.id);
|
||||
@ -435,9 +395,9 @@ describe("binding for simple arrows", () => {
|
||||
height: 500,
|
||||
});
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: 210,
|
||||
x: 190,
|
||||
y: 250,
|
||||
width: 180,
|
||||
width: 220,
|
||||
height: 1,
|
||||
});
|
||||
expect(arrow.startBinding?.elementId).toBe(rectLeft.id);
|
||||
@ -475,11 +435,11 @@ describe("binding for simple arrows", () => {
|
||||
|
||||
UI.clickTool("arrow");
|
||||
mouse.reset();
|
||||
mouse.clickAt(210, 250);
|
||||
mouse.clickAt(190, 250);
|
||||
mouse.moveTo(300, 200);
|
||||
mouse.clickAt(300, 200);
|
||||
mouse.moveTo(390, 251);
|
||||
mouse.clickAt(390, 251);
|
||||
mouse.moveTo(410, 251);
|
||||
mouse.clickAt(410, 251);
|
||||
|
||||
const arrow = API.getSelectedElement() as ExcalidrawArrowElement;
|
||||
|
||||
@ -517,9 +477,9 @@ describe("binding for simple arrows", () => {
|
||||
height: 500,
|
||||
});
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: 210,
|
||||
x: 190,
|
||||
y: 250,
|
||||
width: 177,
|
||||
width: 217,
|
||||
height: 1,
|
||||
});
|
||||
expect(arrow.startBinding?.elementId).toBe(rectLeft.id);
|
||||
@ -668,7 +628,7 @@ describe("binding for simple arrows", () => {
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
size: 50,
|
||||
size: 65,
|
||||
});
|
||||
|
||||
expect(arrow.endBinding?.elementId).toBe(text.id);
|
||||
@ -693,7 +653,7 @@ describe("binding for simple arrows", () => {
|
||||
it("should unbind on text element deletion by submitting empty text", async () => {
|
||||
const text = API.createElement({
|
||||
type: "text",
|
||||
text: "ola",
|
||||
text: "¡olá!",
|
||||
x: 60,
|
||||
y: 0,
|
||||
width: 100,
|
||||
@ -705,7 +665,7 @@ describe("binding for simple arrows", () => {
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
size: 50,
|
||||
size: 65,
|
||||
});
|
||||
|
||||
expect(arrow.endBinding?.elementId).toBe(text.id);
|
||||
|
@ -814,7 +814,7 @@ describe("duplication z-order", () => {
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: -100,
|
||||
y: 50,
|
||||
width: 95,
|
||||
width: 115,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
|
@ -131,6 +131,11 @@ describe("elbow arrow segment move", () => {
|
||||
});
|
||||
|
||||
describe("elbow arrow routing", () => {
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||
});
|
||||
|
||||
it("can properly generate orthogonal arrow points", () => {
|
||||
const scene = new Scene();
|
||||
const arrow = API.createElement({
|
||||
@ -194,9 +199,9 @@ describe("elbow arrow routing", () => {
|
||||
|
||||
expect(arrow.points).toEqual([
|
||||
[0, 0],
|
||||
[45, 0],
|
||||
[45, 200],
|
||||
[90, 200],
|
||||
[44, 0],
|
||||
[44, 200],
|
||||
[88, 200],
|
||||
]);
|
||||
});
|
||||
});
|
||||
@ -235,9 +240,9 @@ describe("elbow arrow ui", () => {
|
||||
expect(h.state.currentItemArrowType).toBe(ARROW_TYPE.elbow);
|
||||
|
||||
mouse.reset();
|
||||
mouse.moveTo(-43, -99);
|
||||
mouse.moveTo(-53, -99);
|
||||
mouse.click();
|
||||
mouse.moveTo(43, 99);
|
||||
mouse.moveTo(53, 99);
|
||||
mouse.click();
|
||||
|
||||
const arrow = h.scene.getSelectedElements(
|
||||
@ -248,9 +253,9 @@ describe("elbow arrow ui", () => {
|
||||
expect(arrow.elbowed).toBe(true);
|
||||
expect(arrow.points).toEqual([
|
||||
[0, 0],
|
||||
[45, 0],
|
||||
[45, 200],
|
||||
[90, 200],
|
||||
[44, 0],
|
||||
[44, 200],
|
||||
[88, 200],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -272,9 +277,9 @@ describe("elbow arrow ui", () => {
|
||||
UI.clickOnTestId("elbow-arrow");
|
||||
|
||||
mouse.reset();
|
||||
mouse.moveTo(-43, -99);
|
||||
mouse.moveTo(-53, -99);
|
||||
mouse.click();
|
||||
mouse.moveTo(43, 99);
|
||||
mouse.moveTo(53, 99);
|
||||
mouse.click();
|
||||
|
||||
const arrow = h.scene.getSelectedElements(
|
||||
@ -290,9 +295,11 @@ describe("elbow arrow ui", () => {
|
||||
|
||||
expect(arrow.points.map((point) => point.map(Math.round))).toEqual([
|
||||
[0, 0],
|
||||
[35, 0],
|
||||
[35, 165],
|
||||
[103, 165],
|
||||
[36, 0],
|
||||
[36, 90],
|
||||
[28, 90],
|
||||
[28, 164],
|
||||
[101, 164],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -314,9 +321,9 @@ describe("elbow arrow ui", () => {
|
||||
UI.clickOnTestId("elbow-arrow");
|
||||
|
||||
mouse.reset();
|
||||
mouse.moveTo(-43, -99);
|
||||
mouse.moveTo(-53, -99);
|
||||
mouse.click();
|
||||
mouse.moveTo(43, 99);
|
||||
mouse.moveTo(53, 99);
|
||||
mouse.click();
|
||||
|
||||
const arrow = h.scene.getSelectedElements(
|
||||
@ -346,9 +353,9 @@ describe("elbow arrow ui", () => {
|
||||
expect(duplicatedArrow.elbowed).toBe(true);
|
||||
expect(duplicatedArrow.points).toEqual([
|
||||
[0, 0],
|
||||
[45, 0],
|
||||
[45, 200],
|
||||
[90, 200],
|
||||
[44, 0],
|
||||
[44, 200],
|
||||
[88, 200],
|
||||
]);
|
||||
expect(arrow.startBinding).not.toBe(null);
|
||||
expect(arrow.endBinding).not.toBe(null);
|
||||
@ -372,9 +379,9 @@ describe("elbow arrow ui", () => {
|
||||
UI.clickOnTestId("elbow-arrow");
|
||||
|
||||
mouse.reset();
|
||||
mouse.moveTo(-43, -99);
|
||||
mouse.moveTo(-53, -99);
|
||||
mouse.click();
|
||||
mouse.moveTo(43, 99);
|
||||
mouse.moveTo(53, 99);
|
||||
mouse.click();
|
||||
|
||||
const arrow = h.scene.getSelectedElements(
|
||||
@ -401,8 +408,8 @@ describe("elbow arrow ui", () => {
|
||||
expect(duplicatedArrow.points).toEqual([
|
||||
[0, 0],
|
||||
[0, 100],
|
||||
[90, 100],
|
||||
[90, 200],
|
||||
[88, 100],
|
||||
[88, 200],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -1303,7 +1303,7 @@ describe("Test Linear Elements", () => {
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: -10,
|
||||
y: 250,
|
||||
width: 400,
|
||||
width: 410,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
@ -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).toBeCloseTo(405);
|
||||
expect(arrow.width).toBeCloseTo(404);
|
||||
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(205);
|
||||
expect(arrow.width).toBeCloseTo(204);
|
||||
expect(rect.x).toBe(200);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(handleBindTextResizeSpy).toHaveBeenCalledWith(
|
||||
|
@ -510,12 +510,12 @@ describe("arrow element", () => {
|
||||
h.state,
|
||||
)[0] as ExcalidrawElbowArrowElement;
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.06);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
||||
|
||||
UI.resize(rectangle, "se", [-200, -150]);
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.06);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
||||
});
|
||||
|
||||
@ -538,11 +538,11 @@ describe("arrow element", () => {
|
||||
h.state,
|
||||
)[0] as ExcalidrawElbowArrowElement;
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.06);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
||||
|
||||
UI.resize([rectangle, arrow], "nw", [300, 350]);
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(-0.05);
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(-0.06);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.25);
|
||||
});
|
||||
});
|
||||
@ -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(64.1246);
|
||||
expect(boundArrow.points[1][1]).toBeCloseTo(-85.4995);
|
||||
expect(boundArrow.points[1][0]).toBeCloseTo(66.3157);
|
||||
expect(boundArrow.points[1][1]).toBeCloseTo(-88.421);
|
||||
|
||||
expect(arrowLabelPos.x + arrowLabel.width / 2).toBeCloseTo(
|
||||
boundArrow.x + boundArrow.points[1][0] / 2,
|
||||
|
@ -151,6 +151,10 @@ export const actionFinalize = register<FormData>({
|
||||
...linearElementEditor,
|
||||
selectedPointsIndices: null,
|
||||
isEditing: false,
|
||||
initialState: {
|
||||
...linearElementEditor.initialState,
|
||||
lastClickedPoint: -1,
|
||||
},
|
||||
},
|
||||
selectionElement: null,
|
||||
suggestedBinding: null,
|
||||
@ -186,11 +190,13 @@ export const actionFinalize = register<FormData>({
|
||||
if (element) {
|
||||
// pen and mouse have hover
|
||||
if (
|
||||
appState.selectedLinearElement &&
|
||||
appState.multiElement &&
|
||||
element.type !== "freedraw" &&
|
||||
appState.lastPointerDownWith !== "touch"
|
||||
) {
|
||||
const { points, lastCommittedPoint } = element;
|
||||
const { points } = element;
|
||||
const { lastCommittedPoint } = appState.selectedLinearElement;
|
||||
if (
|
||||
!lastCommittedPoint ||
|
||||
points[points.length - 1] !== lastCommittedPoint
|
||||
@ -278,8 +284,9 @@ export const actionFinalize = register<FormData>({
|
||||
isEditing: appState.newElement
|
||||
? false
|
||||
: selectedLinearElement.isEditing,
|
||||
pointerDownState: {
|
||||
...selectedLinearElement.pointerDownState,
|
||||
initialState: {
|
||||
...selectedLinearElement.initialState,
|
||||
lastClickedPoint: -1,
|
||||
origin: null,
|
||||
},
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ describe("flipping re-centers selection", () => {
|
||||
|
||||
const rec1 = h.elements.find((el) => el.id === "rec1")!;
|
||||
expect(rec1.x).toBeCloseTo(100, 0);
|
||||
expect(rec1.y).toBeCloseTo(100, 0);
|
||||
expect(rec1.y).toBeCloseTo(101, 0);
|
||||
|
||||
const rec2 = h.elements.find((el) => el.id === "rec2")!;
|
||||
expect(rec2.x).toBeCloseTo(220, 0);
|
||||
expect(rec2.y).toBeCloseTo(250, 0);
|
||||
expect(rec2.y).toBeCloseTo(251, 0);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -866,8 +866,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
private handleSkipBindMode() {
|
||||
if (
|
||||
this.state.selectedLinearElement?.pointerDownState &&
|
||||
!this.state.selectedLinearElement.pointerDownState.arrowStartIsInside
|
||||
this.state.selectedLinearElement?.initialState &&
|
||||
!this.state.selectedLinearElement.initialState.arrowStartIsInside
|
||||
) {
|
||||
invariant(
|
||||
this.lastPointerMoveCoords,
|
||||
@ -894,8 +894,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
pointerDownState: {
|
||||
...this.state.selectedLinearElement.pointerDownState,
|
||||
initialState: {
|
||||
...this.state.selectedLinearElement.initialState,
|
||||
arrowStartIsInside: true,
|
||||
},
|
||||
},
|
||||
@ -983,8 +983,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
// Once the start is set to inside binding, it remains so
|
||||
const arrowStartIsInside =
|
||||
!this.state.newElement &&
|
||||
(this.state.selectedLinearElement.pointerDownState
|
||||
.arrowStartIsInside ||
|
||||
(this.state.selectedLinearElement.initialState.arrowStartIsInside ||
|
||||
arrow.startBinding?.elementId === hoveredElement.id);
|
||||
|
||||
// Change the global binding mode
|
||||
@ -998,8 +997,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
bindMode: "inside",
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
pointerDownState: {
|
||||
...this.state.selectedLinearElement.pointerDownState,
|
||||
initialState: {
|
||||
...this.state.selectedLinearElement.initialState,
|
||||
arrowStartIsInside,
|
||||
},
|
||||
},
|
||||
@ -5841,8 +5840,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
pointerDownState: {
|
||||
...this.state.selectedLinearElement.pointerDownState,
|
||||
initialState: {
|
||||
...this.state.selectedLinearElement.initialState,
|
||||
segmentMidpoint: {
|
||||
index: nextIndex,
|
||||
value: hitCoords,
|
||||
@ -6260,10 +6259,17 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
|
||||
if (this.state.multiElement) {
|
||||
const { multiElement } = this.state;
|
||||
const { x: rx, y: ry, points, lastCommittedPoint } = multiElement;
|
||||
const { multiElement, selectedLinearElement } = this.state;
|
||||
const { x: rx, y: ry, points } = multiElement;
|
||||
const lastPoint = points[points.length - 1];
|
||||
|
||||
invariant(
|
||||
selectedLinearElement,
|
||||
"There must be a selected linear element instace",
|
||||
);
|
||||
|
||||
const { lastCommittedPoint } = selectedLinearElement;
|
||||
|
||||
setCursorForShape(this.interactiveCanvas, this.state);
|
||||
|
||||
if (lastPoint === lastCommittedPoint) {
|
||||
@ -6285,13 +6291,18 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
if (this.state.selectedLinearElement?.pointerDownState) {
|
||||
invariant(
|
||||
this.state.selectedLinearElement?.initialState,
|
||||
"initialState must be set",
|
||||
);
|
||||
if (this.state.selectedLinearElement.initialState) {
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
lastCommittedPoint: points[points.length - 1],
|
||||
selectedPointsIndices: [multiElement.points.length - 1],
|
||||
pointerDownState: {
|
||||
...this.state.selectedLinearElement.pointerDownState,
|
||||
initialState: {
|
||||
...this.state.selectedLinearElement.initialState,
|
||||
lastClickedPoint: multiElement.points.length - 1,
|
||||
},
|
||||
},
|
||||
@ -6318,6 +6329,30 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...selectedLinearElement,
|
||||
selectedPointsIndices:
|
||||
selectedLinearElement.selectedPointsIndices?.includes(
|
||||
multiElement.points.length,
|
||||
)
|
||||
? [
|
||||
...selectedLinearElement.selectedPointsIndices.filter(
|
||||
(idx) =>
|
||||
idx !== multiElement.points.length &&
|
||||
idx !== multiElement.points.length - 1,
|
||||
),
|
||||
multiElement.points.length - 1,
|
||||
]
|
||||
: selectedLinearElement.selectedPointsIndices,
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
initialState: {
|
||||
...selectedLinearElement.initialState,
|
||||
lastClickedPoint: multiElement.points.length - 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if (isPathALoop(points, this.state.zoom.value)) {
|
||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
||||
@ -8171,16 +8206,30 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointerDownState: PointerDownState,
|
||||
): void => {
|
||||
if (this.state.multiElement) {
|
||||
const { multiElement } = this.state;
|
||||
const { multiElement, selectedLinearElement } = this.state;
|
||||
|
||||
invariant(
|
||||
selectedLinearElement,
|
||||
"selectedLinearElement is expected to be set",
|
||||
);
|
||||
|
||||
// finalize if completing a loop
|
||||
if (
|
||||
multiElement.type === "line" &&
|
||||
isPathALoop(multiElement.points, this.state.zoom.value)
|
||||
) {
|
||||
this.scene.mutateElement(multiElement, {
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
flushSync(() => {
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...selectedLinearElement,
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
initialState: {
|
||||
...selectedLinearElement.initialState,
|
||||
lastClickedPoint: -1, // Disable dragging
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
this.actionManager.executeAction(actionFinalize);
|
||||
return;
|
||||
@ -8189,10 +8238,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
// Elbow arrows cannot be created by putting down points
|
||||
// only the start and end points can be defined
|
||||
if (isElbowArrow(multiElement) && multiElement.points.length > 1) {
|
||||
this.scene.mutateElement(multiElement, {
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
});
|
||||
this.actionManager.executeAction(actionFinalize, "ui", {
|
||||
event: event.nativeEvent,
|
||||
sceneCoords: {
|
||||
@ -8203,7 +8248,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
||||
const { x: rx, y: ry } = multiElement;
|
||||
const { lastCommittedPoint } = selectedLinearElement;
|
||||
|
||||
const hoveredElementForBinding = getHoveredElementForBinding(
|
||||
pointFrom<GlobalPoint>(
|
||||
this.lastPointerMoveCoords?.x ??
|
||||
@ -8247,11 +8294,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
prevState,
|
||||
),
|
||||
}));
|
||||
// clicking outside commit zone → update reference for last committed
|
||||
// point
|
||||
this.scene.mutateElement(multiElement, {
|
||||
lastCommittedPoint: multiElement.points[multiElement.points.length - 1],
|
||||
});
|
||||
|
||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
||||
} else {
|
||||
const [gridX, gridY] = getGridPoint(
|
||||
@ -8373,27 +8416,24 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
if (isBindingElement(element)) {
|
||||
const endIdx = element.points.length - 1;
|
||||
linearElementEditor = {
|
||||
...linearElementEditor,
|
||||
selectedPointsIndices: [endIdx],
|
||||
pointerDownState: {
|
||||
...linearElementEditor.pointerDownState,
|
||||
lastClickedPoint: endIdx,
|
||||
origin: pointFrom<GlobalPoint>(
|
||||
pointerDownState.origin.x,
|
||||
pointerDownState.origin.y,
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
const endIdx = element.points.length - 1;
|
||||
linearElementEditor = {
|
||||
...linearElementEditor,
|
||||
selectedPointsIndices: [endIdx],
|
||||
initialState: {
|
||||
...linearElementEditor.initialState,
|
||||
lastClickedPoint: endIdx,
|
||||
origin: pointFrom<GlobalPoint>(
|
||||
pointerDownState.origin.x,
|
||||
pointerDownState.origin.y,
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
nextSelectedElementIds = makeNextSelectedElementIds(
|
||||
{ [element.id]: true },
|
||||
prevState,
|
||||
);
|
||||
nextSelectedElementIds = !this.state.activeTool.locked
|
||||
? makeNextSelectedElementIds({ [element.id]: true }, prevState)
|
||||
: prevState.selectedElementIds;
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
@ -8607,7 +8647,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
if (
|
||||
this.state.selectedLinearElement &&
|
||||
this.state.selectedLinearElement.elbowed &&
|
||||
this.state.selectedLinearElement.pointerDownState.segmentMidpoint.index
|
||||
this.state.selectedLinearElement.initialState.segmentMidpoint.index
|
||||
) {
|
||||
const [gridX, gridY] = getGridPoint(
|
||||
pointerCoords.x,
|
||||
@ -8616,8 +8656,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
);
|
||||
|
||||
let index =
|
||||
this.state.selectedLinearElement.pointerDownState.segmentMidpoint
|
||||
.index;
|
||||
this.state.selectedLinearElement.initialState.segmentMidpoint.index;
|
||||
if (index < 0) {
|
||||
const nextCoords = LinearElementEditor.getSegmentMidpointHitCoords(
|
||||
{
|
||||
@ -8650,7 +8689,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
segmentMidPointHoveredCoords: ret.segmentMidPointHoveredCoords,
|
||||
pointerDownState: ret.pointerDownState,
|
||||
initialState: ret.initialState,
|
||||
},
|
||||
});
|
||||
return;
|
||||
@ -8740,7 +8779,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
pointerDownState: ret.pointerDownState,
|
||||
initialState: ret.pointerDownState,
|
||||
selectedPointsIndices: ret.selectedPointsIndices,
|
||||
segmentMidPointHoveredCoords: null,
|
||||
},
|
||||
@ -8750,11 +8789,11 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
return;
|
||||
} else if (
|
||||
linearElementEditor.pointerDownState.segmentMidpoint.value !== null &&
|
||||
!linearElementEditor.pointerDownState.segmentMidpoint.added
|
||||
linearElementEditor.initialState.segmentMidpoint.value !== null &&
|
||||
!linearElementEditor.initialState.segmentMidpoint.added
|
||||
) {
|
||||
return;
|
||||
} else if (linearElementEditor.pointerDownState.lastClickedPoint > -1) {
|
||||
} else if (linearElementEditor.initialState.lastClickedPoint > -1) {
|
||||
const element = LinearElementEditor.getElement(
|
||||
linearElementEditor.elementId,
|
||||
elementsMap,
|
||||
@ -8776,12 +8815,16 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
if (
|
||||
event.altKey &&
|
||||
!this.state.selectedLinearElement?.pointerDownState
|
||||
?.arrowStartIsInside
|
||||
!this.state.selectedLinearElement?.initialState?.arrowStartIsInside
|
||||
) {
|
||||
this.handleSkipBindMode();
|
||||
}
|
||||
|
||||
// Ignore drag requests if the arrow modification already happened
|
||||
if (linearElementEditor.initialState.lastClickedPoint === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newState = LinearElementEditor.handlePointDragging(
|
||||
event,
|
||||
this,
|
||||
@ -8789,6 +8832,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointerCoords.y,
|
||||
linearElementEditor,
|
||||
);
|
||||
|
||||
if (newState) {
|
||||
pointerDownState.lastCoords.x = pointerCoords.x;
|
||||
pointerDownState.lastCoords.y = pointerCoords.y;
|
||||
@ -9277,13 +9321,12 @@ class App extends React.Component<AppProps, AppState> {
|
||||
linearElementEditor = {
|
||||
...linearElementEditor,
|
||||
selectedPointsIndices: [1],
|
||||
pointerDownState: {
|
||||
...linearElementEditor.pointerDownState,
|
||||
initialState: {
|
||||
...linearElementEditor.initialState,
|
||||
lastClickedPoint: 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
this.setState({
|
||||
newElement,
|
||||
...LinearElementEditor.handlePointDragging(
|
||||
@ -9612,6 +9655,23 @@ class App extends React.Component<AppProps, AppState> {
|
||||
sceneCoords,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
this.state.newElement &&
|
||||
this.state.multiElement &&
|
||||
isLinearElement(this.state.newElement) &&
|
||||
this.state.selectedLinearElement
|
||||
) {
|
||||
const { multiElement } = this.state;
|
||||
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.missingPointerEventCleanupEmitter.clear();
|
||||
@ -9663,7 +9723,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.scene.mutateElement(newElement, {
|
||||
points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
||||
pressures,
|
||||
lastCommittedPoint: pointFrom<LocalPoint>(dx, dy),
|
||||
});
|
||||
|
||||
this.actionManager.executeAction(actionFinalize);
|
||||
|
@ -114,7 +114,7 @@ describe("binding with linear elements", () => {
|
||||
mouse.up(200, 100);
|
||||
|
||||
UI.clickTool("arrow");
|
||||
mouse.down(5, 0);
|
||||
mouse.down(-5, 0);
|
||||
mouse.up(300, 50);
|
||||
|
||||
elementStats = stats?.querySelector("#elementStats");
|
||||
|
@ -101,7 +101,6 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -163,7 +162,6 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -359,7 +357,6 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -467,7 +464,6 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -649,7 +645,6 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -869,7 +864,6 @@ exports[`Test Transform > should transform linear elements 1`] = `
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -917,7 +911,6 @@ exports[`Test Transform > should transform linear elements 2`] = `
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -964,7 +957,6 @@ exports[`Test Transform > should transform linear elements 3`] = `
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -1012,7 +1004,6 @@ exports[`Test Transform > should transform linear elements 4`] = `
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -1519,7 +1510,6 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||
"id": Any<String>,
|
||||
"index": "a4",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -1588,7 +1578,6 @@ exports[`Test Transform > should transform the elements correctly when linear el
|
||||
"id": Any<String>,
|
||||
"index": "a5",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -1900,7 +1889,6 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -1953,7 +1941,6 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -2006,7 +1993,6 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -2059,7 +2045,6 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
|
@ -7,8 +7,6 @@ import {
|
||||
isPromiseLike,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import { clearElementsForExport } from "@excalidraw/element";
|
||||
|
||||
import type { ValueOf } from "@excalidraw/common/utility-types";
|
||||
import type { ExcalidrawElement, FileId } from "@excalidraw/element/types";
|
||||
|
||||
@ -159,7 +157,7 @@ export const loadSceneOrLibraryFromBlob = async (
|
||||
type: MIME_TYPES.excalidraw,
|
||||
data: restore(
|
||||
{
|
||||
elements: clearElementsForExport(data.elements || []),
|
||||
elements: data.elements || [],
|
||||
appState: {
|
||||
theme: localAppState?.theme,
|
||||
fileHandle: fileHandle || blob.handle || null,
|
||||
|
@ -6,11 +6,6 @@ import {
|
||||
VERSIONS,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
clearElementsForDatabase,
|
||||
clearElementsForExport,
|
||||
} from "@excalidraw/element";
|
||||
|
||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||
|
||||
import { cleanAppStateForExport, clearAppStateForDatabase } from "../appState";
|
||||
@ -57,10 +52,7 @@ export const serializeAsJSON = (
|
||||
type: EXPORT_DATA_TYPES.excalidraw,
|
||||
version: VERSIONS.excalidraw,
|
||||
source: getExportSource(),
|
||||
elements:
|
||||
type === "local"
|
||||
? clearElementsForExport(elements)
|
||||
: clearElementsForDatabase(elements),
|
||||
elements,
|
||||
appState:
|
||||
type === "local"
|
||||
? cleanAppStateForExport(appState)
|
||||
|
@ -292,7 +292,6 @@ export const restoreElement = (
|
||||
case "freedraw": {
|
||||
return restoreElementWithProperties(element, {
|
||||
points: element.points,
|
||||
lastCommittedPoint: null,
|
||||
simulatePressure: element.simulatePressure,
|
||||
pressures: element.pressures,
|
||||
});
|
||||
@ -328,7 +327,6 @@ export const restoreElement = (
|
||||
: element.type,
|
||||
startBinding: repairBinding(element, element.startBinding),
|
||||
endBinding: repairBinding(element, element.endBinding),
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead,
|
||||
endArrowhead,
|
||||
points,
|
||||
@ -361,7 +359,6 @@ export const restoreElement = (
|
||||
type: element.type,
|
||||
startBinding: repairBinding(element, element.startBinding),
|
||||
endBinding: repairBinding(element, element.endBinding),
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead,
|
||||
endArrowhead,
|
||||
points,
|
||||
|
@ -18,7 +18,6 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -135,7 +134,6 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -95,3 +95,141 @@ 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": 640725609,
|
||||
"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": 1051383431,
|
||||
"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.03333",
|
||||
"0.43333",
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": "90.03375",
|
||||
"id": "id6",
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"moveMidPointsWithElement": false,
|
||||
"opacity": 100,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
],
|
||||
[
|
||||
89,
|
||||
"90.03375",
|
||||
],
|
||||
],
|
||||
"roughness": 1,
|
||||
"roundness": {
|
||||
"type": 2,
|
||||
},
|
||||
"seed": 23633383,
|
||||
"startArrowhead": null,
|
||||
"startBinding": {
|
||||
"elementId": "id0",
|
||||
"fixedPoint": [
|
||||
"1.10000",
|
||||
"0.50010",
|
||||
],
|
||||
"mode": "orbit",
|
||||
},
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 9,
|
||||
"versionNonce": 1996028265,
|
||||
"width": 89,
|
||||
"x": 106,
|
||||
"y": "46.01049",
|
||||
}
|
||||
`;
|
||||
|
@ -16,10 +16,6 @@ exports[`multi point mode in linear elements > arrow 3`] = `
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
70,
|
||||
110,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -49,8 +45,8 @@ exports[`multi point mode in linear elements > arrow 3`] = `
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 7,
|
||||
"versionNonce": 400692809,
|
||||
"version": 5,
|
||||
"versionNonce": 1014066025,
|
||||
"width": 70,
|
||||
"x": 30,
|
||||
"y": 30,
|
||||
@ -72,10 +68,6 @@ exports[`multi point mode in linear elements > line 3`] = `
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
70,
|
||||
110,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -104,8 +96,8 @@ exports[`multi point mode in linear elements > line 3`] = `
|
||||
"strokeWidth": 2,
|
||||
"type": "line",
|
||||
"updated": 1,
|
||||
"version": 7,
|
||||
"versionNonce": 400692809,
|
||||
"version": 5,
|
||||
"versionNonce": 1014066025,
|
||||
"width": 70,
|
||||
"x": 30,
|
||||
"y": 30,
|
||||
|
@ -6242,7 +6242,7 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
||||
|
||||
exports[`regression tests > draw every type of shape > [end of test] number of elements 1`] = `0`;
|
||||
|
||||
exports[`regression tests > draw every type of shape > [end of test] number of renders 1`] = `31`;
|
||||
exports[`regression tests > draw every type of shape > [end of test] number of renders 1`] = `35`;
|
||||
|
||||
exports[`regression tests > draw every type of shape > [end of test] redo stack 1`] = `[]`;
|
||||
|
||||
@ -6446,7 +6446,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"height": 10,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -6525,7 +6524,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"height": 10,
|
||||
"index": "a4",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -6604,10 +6602,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"height": 10,
|
||||
"index": "a5",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -6631,14 +6625,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 5,
|
||||
"version": 4,
|
||||
"width": 50,
|
||||
"x": 310,
|
||||
"y": -10,
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 4,
|
||||
"version": 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -6660,10 +6654,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"id15": {
|
||||
"deleted": {
|
||||
"height": 20,
|
||||
"lastCommittedPoint": [
|
||||
80,
|
||||
20,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@ -6678,15 +6668,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 7,
|
||||
"version": 5,
|
||||
"width": 80,
|
||||
},
|
||||
"inserted": {
|
||||
"height": 10,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@ -6697,7 +6683,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 5,
|
||||
"version": 4,
|
||||
"width": 50,
|
||||
},
|
||||
},
|
||||
@ -6712,7 +6698,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"selectedElementIds": {
|
||||
"id20": true,
|
||||
},
|
||||
"selectedLinearElement": null,
|
||||
"selectedLinearElement": {
|
||||
"elementId": "id20",
|
||||
"isEditing": false,
|
||||
},
|
||||
},
|
||||
"inserted": {
|
||||
"selectedElementIds": {
|
||||
@ -6742,10 +6731,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"height": 10,
|
||||
"index": "a6",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -6768,14 +6753,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "line",
|
||||
"version": 5,
|
||||
"version": 4,
|
||||
"width": 50,
|
||||
"x": 430,
|
||||
"y": -10,
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
"version": 4,
|
||||
"version": 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -6797,10 +6782,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"id20": {
|
||||
"deleted": {
|
||||
"height": 20,
|
||||
"lastCommittedPoint": [
|
||||
80,
|
||||
20,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@ -6815,15 +6796,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 7,
|
||||
"version": 5,
|
||||
"width": 80,
|
||||
},
|
||||
"inserted": {
|
||||
"height": 10,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@ -6834,7 +6811,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 5,
|
||||
"version": 4,
|
||||
"width": 50,
|
||||
},
|
||||
},
|
||||
@ -6842,27 +6819,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
},
|
||||
"id": "id24",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
"deleted": {
|
||||
"selectedLinearElement": {
|
||||
"elementId": "id20",
|
||||
"isEditing": false,
|
||||
},
|
||||
},
|
||||
"inserted": {
|
||||
"selectedLinearElement": null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id26",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
"delta": Delta {
|
||||
@ -6881,7 +6837,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"removed": {},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id28",
|
||||
"id": "id26",
|
||||
},
|
||||
{
|
||||
"appState": AppStateDelta {
|
||||
@ -6900,7 +6856,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"elements": {
|
||||
"added": {},
|
||||
"removed": {
|
||||
"id29": {
|
||||
"id27": {
|
||||
"deleted": {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
@ -6912,10 +6868,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
"height": 10,
|
||||
"index": "a7",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
50,
|
||||
10,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -6958,7 +6910,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
},
|
||||
"updated": {},
|
||||
},
|
||||
"id": "id31",
|
||||
"id": "id29",
|
||||
},
|
||||
]
|
||||
`;
|
||||
@ -8680,12 +8632,8 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"initialState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
@ -8695,6 +8643,11 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastCommittedPoint": null,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": undefined,
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
@ -8728,7 +8681,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
|
||||
exports[`regression tests > key 5 selects arrow tool > [end of test] number of elements 1`] = `0`;
|
||||
|
||||
exports[`regression tests > key 5 selects arrow tool > [end of test] number of renders 1`] = `6`;
|
||||
exports[`regression tests > key 5 selects arrow tool > [end of test] number of renders 1`] = `7`;
|
||||
|
||||
exports[`regression tests > key 5 selects arrow tool > [end of test] redo stack 1`] = `[]`;
|
||||
|
||||
@ -8770,7 +8723,6 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] undo stack
|
||||
"height": 30,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -8908,12 +8860,8 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"initialState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
@ -8923,6 +8871,11 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastCommittedPoint": null,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": undefined,
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
@ -8956,7 +8909,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
|
||||
exports[`regression tests > key 6 selects line tool > [end of test] number of elements 1`] = `0`;
|
||||
|
||||
exports[`regression tests > key 6 selects line tool > [end of test] number of renders 1`] = `6`;
|
||||
exports[`regression tests > key 6 selects line tool > [end of test] number of renders 1`] = `7`;
|
||||
|
||||
exports[`regression tests > key 6 selects line tool > [end of test] redo stack 1`] = `[]`;
|
||||
|
||||
@ -8997,7 +8950,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] undo stack 1
|
||||
"height": 30,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -9182,10 +9134,6 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta
|
||||
"height": 30,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
30,
|
||||
30,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -9329,12 +9277,8 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"initialState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
@ -9344,6 +9288,11 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastCommittedPoint": null,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": undefined,
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
@ -9377,7 +9326,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
|
||||
exports[`regression tests > key a selects arrow tool > [end of test] number of elements 1`] = `0`;
|
||||
|
||||
exports[`regression tests > key a selects arrow tool > [end of test] number of renders 1`] = `6`;
|
||||
exports[`regression tests > key a selects arrow tool > [end of test] number of renders 1`] = `7`;
|
||||
|
||||
exports[`regression tests > key a selects arrow tool > [end of test] redo stack 1`] = `[]`;
|
||||
|
||||
@ -9419,7 +9368,6 @@ exports[`regression tests > key a selects arrow tool > [end of test] undo stack
|
||||
"height": 30,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -9736,12 +9684,8 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"hoverPointIndex": -1,
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": {
|
||||
"initialState": {
|
||||
"arrowStartIsInside": false,
|
||||
"lastClickedIsEndPoint": false,
|
||||
"lastClickedPoint": -1,
|
||||
"origin": null,
|
||||
"prevSelectedPointsIndices": null,
|
||||
@ -9751,6 +9695,11 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
"isDragging": false,
|
||||
"isEditing": false,
|
||||
"lastCommittedPoint": null,
|
||||
"lastUncommittedPoint": null,
|
||||
"pointerDownState": undefined,
|
||||
"pointerOffset": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
@ -9784,7 +9733,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
|
||||
exports[`regression tests > key l selects line tool > [end of test] number of elements 1`] = `0`;
|
||||
|
||||
exports[`regression tests > key l selects line tool > [end of test] number of renders 1`] = `6`;
|
||||
exports[`regression tests > key l selects line tool > [end of test] number of renders 1`] = `7`;
|
||||
|
||||
exports[`regression tests > key l selects line tool > [end of test] redo stack 1`] = `[]`;
|
||||
|
||||
@ -9825,7 +9774,6 @@ exports[`regression tests > key l selects line tool > [end of test] undo stack 1
|
||||
"height": 30,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -10189,10 +10137,6 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta
|
||||
"height": 30,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
30,
|
||||
30,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -14530,7 +14474,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
||||
|
||||
exports[`regression tests > undo/redo drawing an element > [end of test] number of elements 1`] = `0`;
|
||||
|
||||
exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `18`;
|
||||
exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `19`;
|
||||
|
||||
exports[`regression tests > undo/redo drawing an element > [end of test] redo stack 1`] = `
|
||||
[
|
||||
@ -14548,10 +14492,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"id6": {
|
||||
"deleted": {
|
||||
"height": 10,
|
||||
"lastCommittedPoint": [
|
||||
60,
|
||||
10,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@ -14562,15 +14502,11 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
10,
|
||||
],
|
||||
],
|
||||
"version": 8,
|
||||
"version": 6,
|
||||
"width": 60,
|
||||
},
|
||||
"inserted": {
|
||||
"height": 20,
|
||||
"lastCommittedPoint": [
|
||||
100,
|
||||
20,
|
||||
],
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
@ -14585,7 +14521,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 7,
|
||||
"version": 5,
|
||||
"width": 100,
|
||||
},
|
||||
},
|
||||
@ -14618,7 +14554,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"id6": {
|
||||
"deleted": {
|
||||
"isDeleted": true,
|
||||
"version": 9,
|
||||
"version": 7,
|
||||
},
|
||||
"inserted": {
|
||||
"angle": 0,
|
||||
@ -14634,10 +14570,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"height": 10,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": [
|
||||
60,
|
||||
10,
|
||||
],
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -14661,7 +14593,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"version": 8,
|
||||
"version": 6,
|
||||
"width": 60,
|
||||
"x": 130,
|
||||
"y": 10,
|
||||
|
@ -16,7 +16,6 @@ exports[`select single element on the scene > arrow 1`] = `
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -65,7 +64,6 @@ exports[`select single element on the scene > arrow escape 1`] = `
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
|
@ -16,7 +16,6 @@ exports[`restoreElements > should restore arrow element correctly 1`] = `
|
||||
"id": "id-arrow01",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -175,7 +174,6 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = `
|
||||
"id": "id-freedraw01",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -222,7 +220,6 @@ exports[`restoreElements > should restore line and draw elements correctly 1`] =
|
||||
"id": "id-line01",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
@ -270,7 +267,6 @@ exports[`restoreElements > should restore line and draw elements correctly 2`] =
|
||||
"id": "id-draw01",
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
|
@ -157,9 +157,9 @@ describe("Test dragCreate", () => {
|
||||
fireEvent.pointerUp(canvas);
|
||||
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`5`,
|
||||
`6`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
|
||||
expect(h.elements.length).toEqual(1);
|
||||
@ -195,9 +195,9 @@ describe("Test dragCreate", () => {
|
||||
fireEvent.pointerUp(canvas);
|
||||
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`5`,
|
||||
`6`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
|
||||
expect(h.elements.length).toEqual(1);
|
||||
|
@ -210,7 +210,6 @@ describe("Basic lasso selection tests", () => {
|
||||
[0, 0],
|
||||
[168.4765625, -153.38671875],
|
||||
],
|
||||
lastCommittedPoint: null,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
startArrowhead: null,
|
||||
@ -250,7 +249,6 @@ describe("Basic lasso selection tests", () => {
|
||||
[0, 0],
|
||||
[206.12890625, 35.4140625],
|
||||
],
|
||||
lastCommittedPoint: null,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
startArrowhead: null,
|
||||
@ -354,7 +352,6 @@ describe("Basic lasso selection tests", () => {
|
||||
],
|
||||
pressures: [],
|
||||
simulatePressure: true,
|
||||
lastCommittedPoint: null,
|
||||
},
|
||||
].map(
|
||||
(e) =>
|
||||
@ -1229,7 +1226,6 @@ describe("Special cases", () => {
|
||||
locked: false,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead: null,
|
||||
endArrowhead: null,
|
||||
points: [
|
||||
@ -1271,7 +1267,6 @@ describe("Special cases", () => {
|
||||
locked: false,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead: null,
|
||||
endArrowhead: null,
|
||||
points: [
|
||||
@ -1312,7 +1307,6 @@ describe("Special cases", () => {
|
||||
locked: false,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead: null,
|
||||
endArrowhead: null,
|
||||
points: [
|
||||
@ -1353,7 +1347,6 @@ describe("Special cases", () => {
|
||||
locked: false,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead: null,
|
||||
endArrowhead: null,
|
||||
points: [
|
||||
@ -1692,7 +1685,6 @@ describe("Special cases", () => {
|
||||
locked: false,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead: null,
|
||||
endArrowhead: null,
|
||||
points: [
|
||||
@ -1744,7 +1736,6 @@ describe("Special cases", () => {
|
||||
locked: false,
|
||||
startBinding: null,
|
||||
endBinding: null,
|
||||
lastCommittedPoint: null,
|
||||
startArrowhead: null,
|
||||
endArrowhead: null,
|
||||
points: [
|
||||
|
@ -102,16 +102,16 @@ describe("move element", () => {
|
||||
new Pointer("mouse").clickOn(rectB);
|
||||
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||
`15`,
|
||||
`16`,
|
||||
);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`13`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`14`);
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
expect(h.elements.length).toEqual(3);
|
||||
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([[105, 45]], 0);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[90, 90]], 0);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[110, 50]], 0);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[80, 80]], 0);
|
||||
|
||||
renderInteractiveScene.mockClear();
|
||||
renderStaticScene.mockClear();
|
||||
@ -129,8 +129,11 @@ 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([[105, 45]], 0);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[91, 91]], 0);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[106, 46]], 0);
|
||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints(
|
||||
[[89, 90.033]],
|
||||
0,
|
||||
);
|
||||
|
||||
h.elements.forEach((element) => expect(element).toMatchSnapshot());
|
||||
});
|
||||
|
@ -118,8 +118,8 @@ describe("multi point mode in linear elements", () => {
|
||||
key: KEYS.ENTER,
|
||||
});
|
||||
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`11`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(h.elements.length).toEqual(1);
|
||||
|
||||
const element = h.elements[0] as ExcalidrawLinearElement;
|
||||
@ -161,8 +161,8 @@ describe("multi point mode in linear elements", () => {
|
||||
fireEvent.keyDown(document, {
|
||||
key: KEYS.ENTER,
|
||||
});
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`11`);
|
||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||
expect(h.elements.length).toEqual(1);
|
||||
|
||||
const element = h.elements[0] as ExcalidrawLinearElement;
|
||||
|
@ -24,7 +24,7 @@ test("unselected bound arrow updates when rotating its target element", async ()
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: -80,
|
||||
y: 50,
|
||||
width: 70,
|
||||
width: 85,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
@ -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(81.75, 1);
|
||||
expect(arrow.height).toBeCloseTo(62.3, 1);
|
||||
expect(arrow.width).toBeCloseTo(84.9, 1);
|
||||
expect(arrow.height).toBeCloseTo(52.717, 1);
|
||||
});
|
||||
|
||||
test("unselected bound arrows update when rotating their target elements", async () => {
|
||||
@ -48,9 +48,10 @@ test("unselected bound arrows update when rotating their target elements", async
|
||||
height: 120,
|
||||
});
|
||||
const ellipseArrow = UI.createElement("arrow", {
|
||||
position: 0,
|
||||
width: 40,
|
||||
height: 80,
|
||||
x: -10,
|
||||
y: 80,
|
||||
width: 50,
|
||||
height: 60,
|
||||
});
|
||||
const text = UI.createElement("text", {
|
||||
position: 220,
|
||||
@ -59,8 +60,8 @@ test("unselected bound arrows update when rotating their target elements", async
|
||||
const textArrow = UI.createElement("arrow", {
|
||||
x: 360,
|
||||
y: 300,
|
||||
width: -100,
|
||||
height: -40,
|
||||
width: -140,
|
||||
height: -60,
|
||||
});
|
||||
|
||||
expect(ellipseArrow.endBinding?.elementId).toEqual(ellipse.id);
|
||||
@ -69,16 +70,16 @@ test("unselected bound arrows update when rotating their target elements", async
|
||||
UI.rotate([ellipse, text], [-82, 23], { shift: true });
|
||||
|
||||
expect(ellipseArrow.endBinding?.elementId).toEqual(ellipse.id);
|
||||
expect(ellipseArrow.x).toEqual(0);
|
||||
expect(ellipseArrow.y).toEqual(0);
|
||||
expect(ellipseArrow.x).toEqual(-10);
|
||||
expect(ellipseArrow.y).toEqual(80);
|
||||
expect(ellipseArrow.points[0]).toEqual([0, 0]);
|
||||
expect(ellipseArrow.points[1][0]).toBeCloseTo(16.52, 1);
|
||||
expect(ellipseArrow.points[1][1]).toBeCloseTo(216.57, 1);
|
||||
expect(ellipseArrow.points[1][0]).toBeCloseTo(42.318, 1);
|
||||
expect(ellipseArrow.points[1][1]).toBeCloseTo(92.133, 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(-63, 0);
|
||||
expect(textArrow.points[1][1]).toBeCloseTo(-146, 0);
|
||||
expect(textArrow.points[1][0]).toBeCloseTo(-98.86, 0);
|
||||
expect(textArrow.points[1][1]).toBeCloseTo(-123.65, 0);
|
||||
});
|
||||
|
@ -425,8 +425,8 @@ describe("select single element on the scene", () => {
|
||||
fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
|
||||
fireEvent.pointerUp(canvas);
|
||||
|
||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(8);
|
||||
expect(renderStaticScene).toHaveBeenCalledTimes(6);
|
||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
|
||||
expect(renderStaticScene).toHaveBeenCalledTimes(7);
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
expect(h.elements.length).toEqual(1);
|
||||
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
|
||||
@ -469,8 +469,8 @@ describe("select single element on the scene", () => {
|
||||
fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
|
||||
fireEvent.pointerUp(canvas);
|
||||
|
||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(8);
|
||||
expect(renderStaticScene).toHaveBeenCalledTimes(6);
|
||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
|
||||
expect(renderStaticScene).toHaveBeenCalledTimes(7);
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
expect(h.elements.length).toEqual(1);
|
||||
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
|
||||
|
Loading…
x
Reference in New Issue
Block a user