mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
refactor code
This commit is contained in:
parent
ba7e3439f4
commit
5d8fd603bb
4 changed files with 168 additions and 259 deletions
|
@ -6,6 +6,8 @@ import type {
|
||||||
NonDeleted,
|
NonDeleted,
|
||||||
ExcalidrawTextElementWithContainer,
|
ExcalidrawTextElementWithContainer,
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
|
ExcalidrawRectanguloidElement,
|
||||||
|
ExcalidrawEllipseElement,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import rough from "roughjs/bin/rough";
|
import rough from "roughjs/bin/rough";
|
||||||
import type { Point as RoughPoint } from "roughjs/bin/geometry";
|
import type { Point as RoughPoint } from "roughjs/bin/geometry";
|
||||||
|
@ -25,6 +27,7 @@ import { LinearElementEditor } from "./linearElementEditor";
|
||||||
import { ShapeCache } from "../scene/ShapeCache";
|
import { ShapeCache } from "../scene/ShapeCache";
|
||||||
import { arrayToMap, invariant } from "../utils";
|
import { arrayToMap, invariant } from "../utils";
|
||||||
import type {
|
import type {
|
||||||
|
Curve,
|
||||||
Degrees,
|
Degrees,
|
||||||
GlobalPoint,
|
GlobalPoint,
|
||||||
LineSegment,
|
LineSegment,
|
||||||
|
@ -40,6 +43,12 @@ import {
|
||||||
pointRotateRads,
|
pointRotateRads,
|
||||||
} from "../../math";
|
} from "../../math";
|
||||||
import type { Mutable } from "../utility-types";
|
import type { Mutable } from "../utility-types";
|
||||||
|
import { getElementShape } from "../shapes";
|
||||||
|
import { pointsOnBezierCurves } from "points-on-curve";
|
||||||
|
import {
|
||||||
|
deconstructDiamondElement,
|
||||||
|
deconstructRectanguloidElement,
|
||||||
|
} from "./utils";
|
||||||
|
|
||||||
export type RectangleBox = {
|
export type RectangleBox = {
|
||||||
x: number;
|
x: number;
|
||||||
|
@ -246,50 +255,69 @@ export const getElementAbsoluteCoords = (
|
||||||
* that can be used for visual collision detection (useful for frames)
|
* that can be used for visual collision detection (useful for frames)
|
||||||
* as opposed to bounding box collision detection
|
* as opposed to bounding box collision detection
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Given an element, return the line segments that make up the element.
|
||||||
|
*
|
||||||
|
* Uses helpers from /math
|
||||||
|
*/
|
||||||
export const getElementLineSegments = (
|
export const getElementLineSegments = (
|
||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
): LineSegment<GlobalPoint>[] => {
|
): LineSegment<GlobalPoint>[] => {
|
||||||
|
const shape = getElementShape(element, elementsMap);
|
||||||
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(
|
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(
|
||||||
element,
|
element,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
const center = pointFrom<GlobalPoint>(cx, cy);
|
||||||
|
|
||||||
const center: GlobalPoint = pointFrom(cx, cy);
|
if (shape.type === "polycurve") {
|
||||||
|
const curves = shape.data;
|
||||||
if (isLinearElement(element) || isFreeDrawElement(element)) {
|
const points = curves
|
||||||
const segments: LineSegment<GlobalPoint>[] = [];
|
.map((curve) => pointsOnBezierCurves(curve, 10))
|
||||||
|
.flat();
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
const segments: LineSegment<GlobalPoint>[] = [];
|
||||||
while (i < element.points.length - 1) {
|
while (i < points.length - 1) {
|
||||||
segments.push(
|
segments.push(
|
||||||
lineSegment(
|
lineSegment(
|
||||||
pointRotateRads(
|
pointFrom(points[i][0], points[i][1]),
|
||||||
pointFrom(
|
pointFrom(points[i + 1][0], points[i + 1][1]),
|
||||||
element.points[i][0] + element.x,
|
|
||||||
element.points[i][1] + element.y,
|
|
||||||
),
|
|
||||||
center,
|
|
||||||
element.angle,
|
|
||||||
),
|
|
||||||
pointRotateRads(
|
|
||||||
pointFrom(
|
|
||||||
element.points[i + 1][0] + element.x,
|
|
||||||
element.points[i + 1][1] + element.y,
|
|
||||||
),
|
|
||||||
center,
|
|
||||||
element.angle,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return segments;
|
return segments;
|
||||||
|
} else if (shape.type === "polyline") {
|
||||||
|
return shape.data as LineSegment<GlobalPoint>[];
|
||||||
|
} else if (_isRectanguloidElement(element)) {
|
||||||
|
const [sides, corners] = deconstructRectanguloidElement(element);
|
||||||
|
const cornerSegments: LineSegment<GlobalPoint>[] = corners
|
||||||
|
.map((corner) => getSegmentsOnCurve(corner, center, element.angle))
|
||||||
|
.flat();
|
||||||
|
const rotatedSides = getRotatedSides(sides, center, element.angle);
|
||||||
|
return [...rotatedSides, ...cornerSegments];
|
||||||
|
} else if (element.type === "diamond") {
|
||||||
|
const [sides, corners] = deconstructDiamondElement(element);
|
||||||
|
const cornerSegments = corners
|
||||||
|
.map((corner) => getSegmentsOnCurve(corner, center, element.angle))
|
||||||
|
.flat();
|
||||||
|
const rotatedSides = getRotatedSides(sides, center, element.angle);
|
||||||
|
|
||||||
|
return [...rotatedSides, ...cornerSegments];
|
||||||
|
} else if (shape.type === "polygon") {
|
||||||
|
const points = shape.data as GlobalPoint[];
|
||||||
|
const segments: LineSegment<GlobalPoint>[] = [];
|
||||||
|
for (let i = 0; i < points.length - 1; i++) {
|
||||||
|
segments.push(lineSegment(points[i], points[i + 1]));
|
||||||
|
}
|
||||||
|
return segments;
|
||||||
|
} else if (shape.type === "ellipse") {
|
||||||
|
return getSegmentsOnEllipse(element as ExcalidrawEllipseElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [nw, ne, sw, se, n, s, w, e] = (
|
const [nw, ne, sw, se, , , w, e] = (
|
||||||
[
|
[
|
||||||
[x1, y1],
|
[x1, y1],
|
||||||
[x2, y1],
|
[x2, y1],
|
||||||
|
@ -302,28 +330,6 @@ export const getElementLineSegments = (
|
||||||
] as GlobalPoint[]
|
] as GlobalPoint[]
|
||||||
).map((point) => pointRotateRads(point, center, element.angle));
|
).map((point) => pointRotateRads(point, center, element.angle));
|
||||||
|
|
||||||
if (element.type === "diamond") {
|
|
||||||
return [
|
|
||||||
lineSegment(n, w),
|
|
||||||
lineSegment(n, e),
|
|
||||||
lineSegment(s, w),
|
|
||||||
lineSegment(s, e),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.type === "ellipse") {
|
|
||||||
return [
|
|
||||||
lineSegment(n, w),
|
|
||||||
lineSegment(n, e),
|
|
||||||
lineSegment(s, w),
|
|
||||||
lineSegment(s, e),
|
|
||||||
lineSegment(n, w),
|
|
||||||
lineSegment(n, e),
|
|
||||||
lineSegment(s, w),
|
|
||||||
lineSegment(s, e),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
lineSegment(nw, ne),
|
lineSegment(nw, ne),
|
||||||
lineSegment(sw, se),
|
lineSegment(sw, se),
|
||||||
|
@ -336,6 +342,94 @@ export const getElementLineSegments = (
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _isRectanguloidElement = (
|
||||||
|
element: ExcalidrawElement,
|
||||||
|
): element is ExcalidrawRectanguloidElement => {
|
||||||
|
return (
|
||||||
|
element != null &&
|
||||||
|
(element.type === "rectangle" ||
|
||||||
|
element.type === "image" ||
|
||||||
|
element.type === "iframe" ||
|
||||||
|
element.type === "embeddable" ||
|
||||||
|
element.type === "frame" ||
|
||||||
|
element.type === "magicframe" ||
|
||||||
|
(element.type === "text" && !element.containerId))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRotatedSides = (
|
||||||
|
sides: LineSegment<GlobalPoint>[],
|
||||||
|
center: GlobalPoint,
|
||||||
|
angle: Radians,
|
||||||
|
) => {
|
||||||
|
return sides.map((side) => {
|
||||||
|
return lineSegment(
|
||||||
|
pointRotateRads<GlobalPoint>(side[0], center, angle),
|
||||||
|
pointRotateRads<GlobalPoint>(side[1], center, angle),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSegmentsOnCurve = (
|
||||||
|
curve: Curve<GlobalPoint>,
|
||||||
|
center: GlobalPoint,
|
||||||
|
angle: Radians,
|
||||||
|
): LineSegment<GlobalPoint>[] => {
|
||||||
|
const points = pointsOnBezierCurves(curve, 10);
|
||||||
|
let i = 0;
|
||||||
|
const segments: LineSegment<GlobalPoint>[] = [];
|
||||||
|
while (i < points.length - 1) {
|
||||||
|
segments.push(
|
||||||
|
lineSegment(
|
||||||
|
pointRotateRads<GlobalPoint>(
|
||||||
|
pointFrom(points[i][0], points[i][1]),
|
||||||
|
center,
|
||||||
|
angle,
|
||||||
|
),
|
||||||
|
pointRotateRads<GlobalPoint>(
|
||||||
|
pointFrom(points[i + 1][0], points[i + 1][1]),
|
||||||
|
center,
|
||||||
|
angle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSegmentsOnEllipse = (
|
||||||
|
ellipse: ExcalidrawEllipseElement,
|
||||||
|
): LineSegment<GlobalPoint>[] => {
|
||||||
|
const center = pointFrom<GlobalPoint>(
|
||||||
|
ellipse.x + ellipse.width / 2,
|
||||||
|
ellipse.y + ellipse.height / 2,
|
||||||
|
);
|
||||||
|
|
||||||
|
const a = ellipse.width / 2;
|
||||||
|
const b = ellipse.height / 2;
|
||||||
|
|
||||||
|
const segments: LineSegment<GlobalPoint>[] = [];
|
||||||
|
const points: GlobalPoint[] = [];
|
||||||
|
const n = 90;
|
||||||
|
const deltaT = (Math.PI * 2) / n;
|
||||||
|
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
const t = i * deltaT;
|
||||||
|
const x = center[0] + a * Math.cos(t);
|
||||||
|
const y = center[1] + b * Math.sin(t);
|
||||||
|
points.push(pointRotateRads(pointFrom(x, y), center, ellipse.angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length - 1; i++) {
|
||||||
|
segments.push(lineSegment(points[i], points[i + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
segments.push(lineSegment(points[points.length - 1], points[0]));
|
||||||
|
return segments;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scene -> Scene coords, but in x1,x2,y1,y2 format.
|
* Scene -> Scene coords, but in x1,x2,y1,y2 format.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,36 +1,19 @@
|
||||||
import { pointsOnBezierCurves } from "points-on-curve";
|
import { type GlobalPoint, type LineSegment, pointFrom } from "../../math";
|
||||||
import {
|
|
||||||
type Curve,
|
|
||||||
type GlobalPoint,
|
|
||||||
type LineSegment,
|
|
||||||
type Radians,
|
|
||||||
lineSegment,
|
|
||||||
pointFrom,
|
|
||||||
pointRotateRads,
|
|
||||||
} from "../../math";
|
|
||||||
import { AnimatedTrail } from "../animated-trail";
|
import { AnimatedTrail } from "../animated-trail";
|
||||||
import { type AnimationFrameHandler } from "../animation-frame-handler";
|
import { type AnimationFrameHandler } from "../animation-frame-handler";
|
||||||
import type App from "../components/App";
|
import type App from "../components/App";
|
||||||
|
import { getElementLineSegments } from "../element/bounds";
|
||||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||||
import { isFrameLikeElement, isLinearElement } from "../element/typeChecks";
|
import { isFrameLikeElement, isLinearElement } from "../element/typeChecks";
|
||||||
import type {
|
import type {
|
||||||
ElementsMap,
|
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
ExcalidrawEllipseElement,
|
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
ExcalidrawRectanguloidElement,
|
|
||||||
NonDeleted,
|
NonDeleted,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import { getFrameChildren } from "../frame";
|
import { getFrameChildren } from "../frame";
|
||||||
import { selectGroupsForSelectedElements } from "../groups";
|
import { selectGroupsForSelectedElements } from "../groups";
|
||||||
import { getElementShape } from "../shapes";
|
|
||||||
import { arrayToMap, easeOut } from "../utils";
|
import { arrayToMap, easeOut } from "../utils";
|
||||||
import type { LassoWorkerInput, LassoWorkerOutput } from "./worker";
|
import type { LassoWorkerInput, LassoWorkerOutput } from "./types";
|
||||||
import {
|
|
||||||
deconstructDiamondElement,
|
|
||||||
deconstructRectanguloidElement,
|
|
||||||
} from "../element/utils";
|
|
||||||
import { getElementAbsoluteCoords } from "../element";
|
|
||||||
|
|
||||||
export class LassoTrail extends AnimatedTrail {
|
export class LassoTrail extends AnimatedTrail {
|
||||||
private intersectedElements: Set<ExcalidrawElement["id"]> = new Set();
|
private intersectedElements: Set<ExcalidrawElement["id"]> = new Set();
|
||||||
|
@ -187,178 +170,3 @@ export class LassoTrail extends AnimatedTrail {
|
||||||
this.worker?.terminate();
|
this.worker?.terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an element, return the line segments that make up the element.
|
|
||||||
*
|
|
||||||
* Uses helpers from /math
|
|
||||||
*/
|
|
||||||
const getElementLineSegments = (
|
|
||||||
element: ExcalidrawElement,
|
|
||||||
elementsMap: ElementsMap,
|
|
||||||
): LineSegment<GlobalPoint>[] => {
|
|
||||||
const shape = getElementShape(element, elementsMap);
|
|
||||||
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(
|
|
||||||
element,
|
|
||||||
elementsMap,
|
|
||||||
);
|
|
||||||
const center = pointFrom<GlobalPoint>(cx, cy);
|
|
||||||
|
|
||||||
if (shape.type === "polycurve") {
|
|
||||||
const curves = shape.data;
|
|
||||||
const points = curves
|
|
||||||
.map((curve) => pointsOnBezierCurves(curve, 10))
|
|
||||||
.flat();
|
|
||||||
let i = 0;
|
|
||||||
const segments: LineSegment<GlobalPoint>[] = [];
|
|
||||||
while (i < points.length - 1) {
|
|
||||||
segments.push(
|
|
||||||
lineSegment(
|
|
||||||
pointFrom(points[i][0], points[i][1]),
|
|
||||||
pointFrom(points[i + 1][0], points[i + 1][1]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return segments;
|
|
||||||
} else if (shape.type === "polyline") {
|
|
||||||
return shape.data as LineSegment<GlobalPoint>[];
|
|
||||||
} else if (isRectanguloidElement(element)) {
|
|
||||||
const [sides, corners] = deconstructRectanguloidElement(element);
|
|
||||||
const cornerSegments: LineSegment<GlobalPoint>[] = corners
|
|
||||||
.map((corner) => getSegmentsOnCurve(corner, center, element.angle))
|
|
||||||
.flat();
|
|
||||||
const rotatedSides = getRotatedSides(sides, center, element.angle);
|
|
||||||
return [...rotatedSides, ...cornerSegments];
|
|
||||||
} else if (element.type === "diamond") {
|
|
||||||
const [sides, corners] = deconstructDiamondElement(element);
|
|
||||||
const cornerSegments = corners
|
|
||||||
.map((corner) => getSegmentsOnCurve(corner, center, element.angle))
|
|
||||||
.flat();
|
|
||||||
const rotatedSides = getRotatedSides(sides, center, element.angle);
|
|
||||||
|
|
||||||
return [...rotatedSides, ...cornerSegments];
|
|
||||||
} else if (shape.type === "polygon") {
|
|
||||||
const points = shape.data as GlobalPoint[];
|
|
||||||
const segments: LineSegment<GlobalPoint>[] = [];
|
|
||||||
for (let i = 0; i < points.length - 1; i++) {
|
|
||||||
segments.push(lineSegment(points[i], points[i + 1]));
|
|
||||||
}
|
|
||||||
return segments;
|
|
||||||
} else if (shape.type === "ellipse") {
|
|
||||||
return getSegmentsOnEllipse(element as ExcalidrawEllipseElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [nw, ne, sw, se, , , w, e] = (
|
|
||||||
[
|
|
||||||
[x1, y1],
|
|
||||||
[x2, y1],
|
|
||||||
[x1, y2],
|
|
||||||
[x2, y2],
|
|
||||||
[cx, y1],
|
|
||||||
[cx, y2],
|
|
||||||
[x1, cy],
|
|
||||||
[x2, cy],
|
|
||||||
] as GlobalPoint[]
|
|
||||||
).map((point) => pointRotateRads(point, center, element.angle));
|
|
||||||
|
|
||||||
return [
|
|
||||||
lineSegment(nw, ne),
|
|
||||||
lineSegment(sw, se),
|
|
||||||
lineSegment(nw, sw),
|
|
||||||
lineSegment(ne, se),
|
|
||||||
lineSegment(nw, e),
|
|
||||||
lineSegment(sw, e),
|
|
||||||
lineSegment(ne, w),
|
|
||||||
lineSegment(se, w),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const isRectanguloidElement = (
|
|
||||||
element: ExcalidrawElement,
|
|
||||||
): element is ExcalidrawRectanguloidElement => {
|
|
||||||
return (
|
|
||||||
element != null &&
|
|
||||||
(element.type === "rectangle" ||
|
|
||||||
element.type === "image" ||
|
|
||||||
element.type === "iframe" ||
|
|
||||||
element.type === "embeddable" ||
|
|
||||||
element.type === "frame" ||
|
|
||||||
element.type === "magicframe" ||
|
|
||||||
(element.type === "text" && !element.containerId))
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRotatedSides = (
|
|
||||||
sides: LineSegment<GlobalPoint>[],
|
|
||||||
center: GlobalPoint,
|
|
||||||
angle: Radians,
|
|
||||||
) => {
|
|
||||||
return sides.map((side) => {
|
|
||||||
return lineSegment(
|
|
||||||
pointRotateRads<GlobalPoint>(side[0], center, angle),
|
|
||||||
pointRotateRads<GlobalPoint>(side[1], center, angle),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSegmentsOnCurve = (
|
|
||||||
curve: Curve<GlobalPoint>,
|
|
||||||
center: GlobalPoint,
|
|
||||||
angle: Radians,
|
|
||||||
): LineSegment<GlobalPoint>[] => {
|
|
||||||
const points = pointsOnBezierCurves(curve, 10);
|
|
||||||
let i = 0;
|
|
||||||
const segments: LineSegment<GlobalPoint>[] = [];
|
|
||||||
while (i < points.length - 1) {
|
|
||||||
segments.push(
|
|
||||||
lineSegment(
|
|
||||||
pointRotateRads<GlobalPoint>(
|
|
||||||
pointFrom(points[i][0], points[i][1]),
|
|
||||||
center,
|
|
||||||
angle,
|
|
||||||
),
|
|
||||||
pointRotateRads<GlobalPoint>(
|
|
||||||
pointFrom(points[i + 1][0], points[i + 1][1]),
|
|
||||||
center,
|
|
||||||
angle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return segments;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSegmentsOnEllipse = (
|
|
||||||
ellipse: ExcalidrawEllipseElement,
|
|
||||||
): LineSegment<GlobalPoint>[] => {
|
|
||||||
const center = pointFrom<GlobalPoint>(
|
|
||||||
ellipse.x + ellipse.width / 2,
|
|
||||||
ellipse.y + ellipse.height / 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
const a = ellipse.width / 2;
|
|
||||||
const b = ellipse.height / 2;
|
|
||||||
|
|
||||||
const segments: LineSegment<GlobalPoint>[] = [];
|
|
||||||
const points: GlobalPoint[] = [];
|
|
||||||
const n = 90;
|
|
||||||
const deltaT = (Math.PI * 2) / n;
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const t = i * deltaT;
|
|
||||||
const x = center[0] + a * Math.cos(t);
|
|
||||||
const y = center[1] + b * Math.sin(t);
|
|
||||||
points.push(pointRotateRads(pointFrom(x, y), center, ellipse.angle));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < points.length - 1; i++) {
|
|
||||||
segments.push(lineSegment(points[i], points[i + 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
segments.push(lineSegment(points[points.length - 1], points[0]));
|
|
||||||
return segments;
|
|
||||||
};
|
|
||||||
|
|
17
packages/excalidraw/lasso/types.ts
Normal file
17
packages/excalidraw/lasso/types.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import type { GlobalPoint, LineSegment } from "../../math";
|
||||||
|
import type { ExcalidrawElement } from "../element/types";
|
||||||
|
|
||||||
|
export type ElementsSegmentsMap = Map<string, LineSegment<GlobalPoint>[]>;
|
||||||
|
|
||||||
|
export type LassoWorkerInput = {
|
||||||
|
lassoPath: GlobalPoint[];
|
||||||
|
elements: readonly ExcalidrawElement[];
|
||||||
|
elementsSegments: ElementsSegmentsMap;
|
||||||
|
intersectedElements: Set<ExcalidrawElement["id"]>;
|
||||||
|
enclosedElements: Set<ExcalidrawElement["id"]>;
|
||||||
|
simplifyDistance: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LassoWorkerOutput = {
|
||||||
|
selectedElementIds: string[];
|
||||||
|
};
|
|
@ -3,6 +3,11 @@ import { polygonFromPoints, polygonIncludesPoint } from "../../math/polygon";
|
||||||
import type { ExcalidrawElement } from "../element/types";
|
import type { ExcalidrawElement } from "../element/types";
|
||||||
import { lineSegment, lineSegmentIntersectionPoints } from "../../math/segment";
|
import { lineSegment, lineSegmentIntersectionPoints } from "../../math/segment";
|
||||||
import { simplify } from "points-on-curve";
|
import { simplify } from "points-on-curve";
|
||||||
|
import type {
|
||||||
|
ElementsSegmentsMap,
|
||||||
|
LassoWorkerInput,
|
||||||
|
LassoWorkerOutput,
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
// variables to track processing state and latest input data
|
// variables to track processing state and latest input data
|
||||||
// for "backpressure" purposes
|
// for "backpressure" purposes
|
||||||
|
@ -71,21 +76,6 @@ const processInputData = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type ElementsSegments = Map<string, LineSegment<GlobalPoint>[]>;
|
|
||||||
|
|
||||||
export type LassoWorkerInput = {
|
|
||||||
lassoPath: GlobalPoint[];
|
|
||||||
elements: readonly ExcalidrawElement[];
|
|
||||||
elementsSegments: ElementsSegments;
|
|
||||||
intersectedElements: Set<ExcalidrawElement["id"]>;
|
|
||||||
enclosedElements: Set<ExcalidrawElement["id"]>;
|
|
||||||
simplifyDistance: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LassoWorkerOutput = {
|
|
||||||
selectedElementIds: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateSelection = (input: LassoWorkerInput): LassoWorkerOutput => {
|
export const updateSelection = (input: LassoWorkerInput): LassoWorkerOutput => {
|
||||||
const {
|
const {
|
||||||
lassoPath,
|
lassoPath,
|
||||||
|
@ -96,7 +86,7 @@ export const updateSelection = (input: LassoWorkerInput): LassoWorkerOutput => {
|
||||||
simplifyDistance,
|
simplifyDistance,
|
||||||
} = input;
|
} = input;
|
||||||
// simplify the path to reduce the number of points
|
// simplify the path to reduce the number of points
|
||||||
let path = simplify(lassoPath, simplifyDistance) as GlobalPoint[];
|
const path = simplify(lassoPath, simplifyDistance) as GlobalPoint[];
|
||||||
// close the path to form a polygon for enclosure check
|
// close the path to form a polygon for enclosure check
|
||||||
const closedPath = polygonFromPoints(path);
|
const closedPath = polygonFromPoints(path);
|
||||||
// as the path might not enclose a shape anymore, clear before checking
|
// as the path might not enclose a shape anymore, clear before checking
|
||||||
|
@ -132,7 +122,7 @@ export const updateSelection = (input: LassoWorkerInput): LassoWorkerOutput => {
|
||||||
const enclosureTest = (
|
const enclosureTest = (
|
||||||
lassoPath: GlobalPoint[],
|
lassoPath: GlobalPoint[],
|
||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
elementsSegments: ElementsSegments,
|
elementsSegments: ElementsSegmentsMap,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const lassoPolygon = polygonFromPoints(lassoPath);
|
const lassoPolygon = polygonFromPoints(lassoPath);
|
||||||
const segments = elementsSegments.get(element.id);
|
const segments = elementsSegments.get(element.id);
|
||||||
|
@ -148,7 +138,7 @@ const enclosureTest = (
|
||||||
const intersectionTest = (
|
const intersectionTest = (
|
||||||
lassoPath: GlobalPoint[],
|
lassoPath: GlobalPoint[],
|
||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
elementsSegments: ElementsSegments,
|
elementsSegments: ElementsSegmentsMap,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const elementSegments = elementsSegments.get(element.id);
|
const elementSegments = elementsSegments.get(element.id);
|
||||||
if (!elementSegments) {
|
if (!elementSegments) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue