Fixing tests

This commit is contained in:
Mark Tolmacs 2025-05-08 12:48:36 +02:00
parent 508d4c3681
commit db3e5c63ef
No known key found for this signature in database
5 changed files with 375 additions and 664 deletions

View File

@ -2465,7 +2465,7 @@ exports[`regression tests > can drag element that covers another element, while
"scrolledOutside": false,
"searchMatches": null,
"selectedElementIds": {
"id3": true,
"id0": true,
},
"selectedElementsAreBeingDragged": false,
"selectedGroupIds": {},
@ -2667,7 +2667,7 @@ exports[`regression tests > can drag element that covers another element, while
"delta": Delta {
"deleted": {
"selectedElementIds": {
"id3": true,
"id0": true,
},
},
"inserted": {
@ -2681,7 +2681,7 @@ exports[`regression tests > can drag element that covers another element, while
"added": {},
"removed": {},
"updated": {
"id3": {
"id0": {
"deleted": {
"x": 300,
"y": 300,

View File

@ -304,12 +304,12 @@ describe("contextMenu element", () => {
it("selecting 'Copy styles' in context menu copies styles", () => {
UI.clickTool("rectangle");
mouse.down(10, 10);
mouse.down(13, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 3,
clientX: 13,
clientY: 3,
});
const contextMenu = UI.queryContextMenu();
@ -389,12 +389,12 @@ describe("contextMenu element", () => {
it("selecting 'Delete' in context menu deletes element", () => {
UI.clickTool("rectangle");
mouse.down(10, 10);
mouse.down(13, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 3,
clientX: 13,
clientY: 3,
});
const contextMenu = UI.queryContextMenu();
@ -405,12 +405,12 @@ describe("contextMenu element", () => {
it("selecting 'Add to library' in context menu adds element to library", async () => {
UI.clickTool("rectangle");
mouse.down(10, 10);
mouse.down(13, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 3,
clientX: 13,
clientY: 3,
});
const contextMenu = UI.queryContextMenu();
@ -424,12 +424,12 @@ describe("contextMenu element", () => {
it("selecting 'Duplicate' in context menu duplicates element", () => {
UI.clickTool("rectangle");
mouse.down(10, 10);
mouse.down(13, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 3,
clientX: 13,
clientY: 3,
});
const contextMenu = UI.queryContextMenu();

View File

@ -704,7 +704,7 @@ describe("regression tests", () => {
// pointer down on rectangle
mouse.reset();
mouse.down(100, 100);
mouse.down(110, 100); // Rectangle is rounded, there is no selection at the corner
mouse.up(200, 200);
expect(API.getSelectedElement().type).toBe("rectangle");
@ -989,6 +989,7 @@ describe("regression tests", () => {
// select rectangle
mouse.reset();
mouse.moveTo(30, 0); // Rectangle is rounded, there is no selection at the corner
mouse.click();
// click on intersection between ellipse and rectangle
@ -1155,6 +1156,7 @@ it(
// Select first rectangle while keeping third one selected.
// Third rectangle is selected because it was the last element to be created.
mouse.reset();
mouse.moveTo(30, 0);
Keyboard.withModifierKeys({ shift: true }, () => {
mouse.click();
});
@ -1176,6 +1178,7 @@ it(
// Pointer down o first rectangle that is part of the group
mouse.reset();
mouse.moveTo(30, 0);
Keyboard.withModifierKeys({ shift: true }, () => {
mouse.down();
});

View File

@ -6,6 +6,8 @@ import {
type GlobalPoint,
type LocalPoint,
type Polygon,
vectorCross,
vectorFromPoint,
} from "@excalidraw/math";
import { intersectElementWithLineSegment } from "@excalidraw/element/collision";
@ -40,10 +42,19 @@ export const isPointInShape = (
point: GlobalPoint,
element: ExcalidrawElement,
) => {
if (
(isLinearElement(element) || isFreeDrawElement(element)) &&
!isPathALoop(element.points)
) {
if (isLinearElement(element) || isFreeDrawElement(element)) {
if (isPathALoop(element.points)) {
// for a closed path, we need to check if the point is inside the path
const r = isPointInClosedPath(
element.points.map((p) =>
pointFrom<GlobalPoint>(element.x + p[0], element.y + p[1]),
),
point,
);
//console.log(r);
return r;
}
// There isn't any "inside" for a non-looping path
return false;
}
@ -56,6 +67,36 @@ export const isPointInShape = (
return intersections.length === 0;
};
/**
* Determine if a closed path contains a point.
*
* Implementation notes: We'll use the fact that the path is a consecutive
* sequence of line segments, these line segments have a winding order and
* the fact that if a point is inside the closed path, the cross product of the
* start point of a line segment to the point p and the end point of the line
* segment will be negative for all segments.
*
* @param points
* @param p
*/
const isPointInClosedPath = (
points: readonly GlobalPoint[],
p: GlobalPoint,
) => {
const segments = points.slice(1).map((point, i) => {
return lineSegment(points[i], point);
});
return segments.every((segment) => {
const c = vectorCross(
vectorFromPoint(segment[0], p),
vectorFromPoint(segment[0], segment[1]),
);
return c < 0;
});
};
// check if the given element is in the given bounds
export const isPointInBounds = <Point extends GlobalPoint | LocalPoint>(
point: Point,