mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
fix: Elbow arrow fixedpoint flipping now properly flips on inverted resize and flip action (#8324)
* Flipping action now properly mirrors selections with elbow arrows * Flipping action now re-centers the selection to the original center to avoid "walking" selections on repeated flipping
This commit is contained in:
parent
44a1c8d857
commit
f3f0ab7c83
17 changed files with 290 additions and 85 deletions
|
@ -8430,6 +8430,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
|||
"selectedElementsAreBeingDragged": false,
|
||||
"selectedGroupIds": {},
|
||||
"selectedLinearElement": LinearElementEditor {
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"endBindingElement": "keep",
|
||||
"hoverPointIndex": -1,
|
||||
|
@ -8649,6 +8650,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
|||
"selectedElementsAreBeingDragged": false,
|
||||
"selectedGroupIds": {},
|
||||
"selectedLinearElement": LinearElementEditor {
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"endBindingElement": "keep",
|
||||
"hoverPointIndex": -1,
|
||||
|
@ -9058,6 +9060,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
|||
"selectedElementsAreBeingDragged": false,
|
||||
"selectedGroupIds": {},
|
||||
"selectedLinearElement": LinearElementEditor {
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"endBindingElement": "keep",
|
||||
"hoverPointIndex": -1,
|
||||
|
@ -9454,6 +9457,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
|||
"selectedElementsAreBeingDragged": false,
|
||||
"selectedGroupIds": {},
|
||||
"selectedLinearElement": LinearElementEditor {
|
||||
"elbowed": false,
|
||||
"elementId": "id0",
|
||||
"endBindingElement": "keep",
|
||||
"hoverPointIndex": -1,
|
||||
|
|
|
@ -9,6 +9,8 @@ import type {
|
|||
ExcalidrawFrameElement,
|
||||
ExcalidrawElementType,
|
||||
ExcalidrawMagicFrameElement,
|
||||
ExcalidrawElbowArrowElement,
|
||||
ExcalidrawArrowElement,
|
||||
} from "../../element/types";
|
||||
import { newElement, newTextElement, newLinearElement } from "../../element";
|
||||
import { DEFAULT_VERTICAL_ALIGN, ROUNDNESS } from "../../constants";
|
||||
|
@ -179,10 +181,10 @@ export class API {
|
|||
scale?: T extends "image" ? ExcalidrawImageElement["scale"] : never;
|
||||
status?: T extends "image" ? ExcalidrawImageElement["status"] : never;
|
||||
startBinding?: T extends "arrow"
|
||||
? ExcalidrawLinearElement["startBinding"]
|
||||
? ExcalidrawArrowElement["startBinding"] | ExcalidrawElbowArrowElement["startBinding"]
|
||||
: never;
|
||||
endBinding?: T extends "arrow"
|
||||
? ExcalidrawLinearElement["endBinding"]
|
||||
? ExcalidrawArrowElement["endBinding"] | ExcalidrawElbowArrowElement["endBinding"]
|
||||
: never;
|
||||
elbowed?: boolean;
|
||||
}): T extends "arrow" | "line"
|
||||
|
|
|
@ -31,6 +31,7 @@ import type {
|
|||
ExcalidrawGenericElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawTextElement,
|
||||
FixedPointBinding,
|
||||
FractionalIndex,
|
||||
SceneElementsMap,
|
||||
} from "../element/types";
|
||||
|
@ -2049,13 +2050,13 @@ describe("history", () => {
|
|||
focus: -0.001587301587301948,
|
||||
gap: 5,
|
||||
fixedPoint: [1.0318471337579618, 0.49920634920634904],
|
||||
},
|
||||
} as FixedPointBinding,
|
||||
endBinding: {
|
||||
elementId: "u2JGnnmoJ0VATV4vCNJE5",
|
||||
focus: -0.0016129032258049847,
|
||||
gap: 3.537079145500037,
|
||||
fixedPoint: [0.4991935483870975, -0.03875193720914723],
|
||||
},
|
||||
} as FixedPointBinding,
|
||||
},
|
||||
],
|
||||
storeAction: StoreAction.CAPTURE,
|
||||
|
@ -4455,7 +4456,7 @@ describe("history", () => {
|
|||
elements: [
|
||||
h.elements[0],
|
||||
newElementWith(h.elements[1], { boundElements: [] }),
|
||||
newElementWith(h.elements[2] as ExcalidrawLinearElement, {
|
||||
newElementWith(h.elements[2] as ExcalidrawElbowArrowElement, {
|
||||
endBinding: {
|
||||
elementId: remoteContainer.id,
|
||||
gap: 1,
|
||||
|
@ -4655,7 +4656,7 @@ describe("history", () => {
|
|||
// Simulate remote update
|
||||
API.updateScene({
|
||||
elements: [
|
||||
newElementWith(h.elements[0] as ExcalidrawLinearElement, {
|
||||
newElementWith(h.elements[0] as ExcalidrawElbowArrowElement, {
|
||||
startBinding: {
|
||||
elementId: rect1.id,
|
||||
gap: 1,
|
||||
|
|
|
@ -4,6 +4,7 @@ import { render } from "./test-utils";
|
|||
import { reseed } from "../random";
|
||||
import { UI, Keyboard, Pointer } from "./helpers/ui";
|
||||
import type {
|
||||
ExcalidrawElbowArrowElement,
|
||||
ExcalidrawFreeDrawElement,
|
||||
ExcalidrawLinearElement,
|
||||
} from "../element/types";
|
||||
|
@ -333,6 +334,62 @@ describe("arrow element", () => {
|
|||
expect(label.angle).toBeCloseTo(0);
|
||||
expect(label.fontSize).toEqual(20);
|
||||
});
|
||||
|
||||
it("flips the fixed point binding on negative resize for single bindable", () => {
|
||||
const rectangle = UI.createElement("rectangle", {
|
||||
x: -100,
|
||||
y: -75,
|
||||
width: 95,
|
||||
height: 100,
|
||||
});
|
||||
UI.clickTool("arrow");
|
||||
UI.clickOnTestId("elbow-arrow");
|
||||
mouse.reset();
|
||||
mouse.moveTo(-5, 0);
|
||||
mouse.click();
|
||||
mouse.moveTo(120, 200);
|
||||
mouse.click();
|
||||
|
||||
const arrow = h.scene.getSelectedElements(
|
||||
h.state,
|
||||
)[0] as ExcalidrawElbowArrowElement;
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
||||
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?.[1]).toBeCloseTo(0.75);
|
||||
});
|
||||
|
||||
it("flips the fixed point binding on negative resize for group selection", () => {
|
||||
const rectangle = UI.createElement("rectangle", {
|
||||
x: -100,
|
||||
y: -75,
|
||||
width: 95,
|
||||
height: 100,
|
||||
});
|
||||
UI.clickTool("arrow");
|
||||
UI.clickOnTestId("elbow-arrow");
|
||||
mouse.reset();
|
||||
mouse.moveTo(-5, 0);
|
||||
mouse.click();
|
||||
mouse.moveTo(120, 200);
|
||||
mouse.click();
|
||||
|
||||
const arrow = h.scene.getSelectedElements(
|
||||
h.state,
|
||||
)[0] as ExcalidrawElbowArrowElement;
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
||||
|
||||
UI.resize([rectangle, arrow], "nw", [300, 350]);
|
||||
|
||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(-0.144, 2);
|
||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.25);
|
||||
});
|
||||
});
|
||||
|
||||
describe("text element", () => {
|
||||
|
@ -828,7 +885,6 @@ describe("multiple selection", () => {
|
|||
expect(leftBoundArrow.endBinding?.elementId).toBe(
|
||||
leftArrowBinding.elementId,
|
||||
);
|
||||
expect(leftBoundArrow.endBinding?.fixedPoint).toBeNull();
|
||||
expect(leftBoundArrow.endBinding?.focus).toBe(leftArrowBinding.focus);
|
||||
|
||||
expect(rightBoundArrow.x).toBeCloseTo(210);
|
||||
|
@ -843,7 +899,6 @@ describe("multiple selection", () => {
|
|||
expect(rightBoundArrow.endBinding?.elementId).toBe(
|
||||
rightArrowBinding.elementId,
|
||||
);
|
||||
expect(rightBoundArrow.endBinding?.fixedPoint).toBeNull();
|
||||
expect(rightBoundArrow.endBinding?.focus).toBe(rightArrowBinding.focus);
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue