feat: add approximate elements in bbox detection
This commit is contained in:
parent
3d57112480
commit
e8f1e10f36
@ -437,7 +437,7 @@ export const getMinMaxXYFromCurvePathOps = (
|
|||||||
return [minX, minY, maxX, maxY];
|
return [minX, minY, maxX, maxY];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBoundsFromPoints = (
|
export const getBoundsFromPoints = (
|
||||||
points: ExcalidrawFreeDrawElement["points"],
|
points: ExcalidrawFreeDrawElement["points"],
|
||||||
): [number, number, number, number] => {
|
): [number, number, number, number] => {
|
||||||
let minX = Infinity;
|
let minX = Infinity;
|
||||||
|
147
src/frame.ts
147
src/frame.ts
@ -23,6 +23,7 @@ import { moveOneRight } from "./zindex";
|
|||||||
import { getElementsInGroup, selectGroupsFromGivenElements } from "./groups";
|
import { getElementsInGroup, selectGroupsFromGivenElements } from "./groups";
|
||||||
import Scene, { ExcalidrawElementsIncludingDeleted } from "./scene/Scene";
|
import Scene, { ExcalidrawElementsIncludingDeleted } from "./scene/Scene";
|
||||||
import { getElementLineSegments } from "./element/bounds";
|
import { getElementLineSegments } from "./element/bounds";
|
||||||
|
import { doLineSegmentsIntersect } from "./packages/utils";
|
||||||
|
|
||||||
// --------------------------- Frame State ------------------------------------
|
// --------------------------- Frame State ------------------------------------
|
||||||
export const bindElementsToFramesAfterDuplication = (
|
export const bindElementsToFramesAfterDuplication = (
|
||||||
@ -56,130 +57,21 @@ export const bindElementsToFramesAfterDuplication = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------- Frame Geometry ---------------------------------
|
export function isElementIntersectingFrame(
|
||||||
class Point {
|
element: ExcalidrawElement,
|
||||||
x: number;
|
frame: ExcalidrawFrameElement,
|
||||||
y: number;
|
) {
|
||||||
|
const frameLineSegments = getElementLineSegments(frame);
|
||||||
|
|
||||||
constructor(x: number, y: number) {
|
const elementLineSegments = getElementLineSegments(element);
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LineSegment {
|
const intersecting = frameLineSegments.some((frameLineSegment) =>
|
||||||
first: Point;
|
elementLineSegments.some((elementLineSegment) =>
|
||||||
second: Point;
|
doLineSegmentsIntersect(frameLineSegment, elementLineSegment),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
constructor(pointA: Point, pointB: Point) {
|
return intersecting;
|
||||||
this.first = pointA;
|
|
||||||
this.second = pointB;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getBoundingBox(): [Point, Point] {
|
|
||||||
return [
|
|
||||||
new Point(
|
|
||||||
Math.min(this.first.x, this.second.x),
|
|
||||||
Math.min(this.first.y, this.second.y),
|
|
||||||
),
|
|
||||||
new Point(
|
|
||||||
Math.max(this.first.x, this.second.x),
|
|
||||||
Math.max(this.first.y, this.second.y),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://martin-thoma.com/how-to-check-if-two-line-segments-intersect/
|
|
||||||
class FrameGeometry {
|
|
||||||
private static EPSILON = 0.000001;
|
|
||||||
|
|
||||||
private static crossProduct(a: Point, b: Point) {
|
|
||||||
return a.x * b.y - b.x * a.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static doBoundingBoxesIntersect(
|
|
||||||
a: [Point, Point],
|
|
||||||
b: [Point, Point],
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
a[0].x <= b[1].x &&
|
|
||||||
a[1].x >= b[0].x &&
|
|
||||||
a[0].y <= b[1].y &&
|
|
||||||
a[1].y >= b[0].y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static isPointOnLine(a: LineSegment, b: Point) {
|
|
||||||
const aTmp = new LineSegment(
|
|
||||||
new Point(0, 0),
|
|
||||||
new Point(a.second.x - a.first.x, a.second.y - a.first.y),
|
|
||||||
);
|
|
||||||
const bTmp = new Point(b.x - a.first.x, b.y - a.first.y);
|
|
||||||
const r = this.crossProduct(aTmp.second, bTmp);
|
|
||||||
return Math.abs(r) < this.EPSILON;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static isPointRightOfLine(a: LineSegment, b: Point) {
|
|
||||||
const aTmp = new LineSegment(
|
|
||||||
new Point(0, 0),
|
|
||||||
new Point(a.second.x - a.first.x, a.second.y - a.first.y),
|
|
||||||
);
|
|
||||||
const bTmp = new Point(b.x - a.first.x, b.y - a.first.y);
|
|
||||||
return this.crossProduct(aTmp.second, bTmp) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static lineSegmentTouchesOrCrossesLine(
|
|
||||||
a: LineSegment,
|
|
||||||
b: LineSegment,
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
this.isPointOnLine(a, b.first) ||
|
|
||||||
this.isPointOnLine(a, b.second) ||
|
|
||||||
(this.isPointRightOfLine(a, b.first)
|
|
||||||
? !this.isPointRightOfLine(a, b.second)
|
|
||||||
: this.isPointRightOfLine(a, b.second))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static doLineSegmentsIntersect(
|
|
||||||
a: [readonly [number, number], readonly [number, number]],
|
|
||||||
b: [readonly [number, number], readonly [number, number]],
|
|
||||||
) {
|
|
||||||
const aSegment = new LineSegment(
|
|
||||||
new Point(a[0][0], a[0][1]),
|
|
||||||
new Point(a[1][0], a[1][1]),
|
|
||||||
);
|
|
||||||
const bSegment = new LineSegment(
|
|
||||||
new Point(b[0][0], b[0][1]),
|
|
||||||
new Point(b[1][0], b[1][1]),
|
|
||||||
);
|
|
||||||
|
|
||||||
const box1 = aSegment.getBoundingBox();
|
|
||||||
const box2 = bSegment.getBoundingBox();
|
|
||||||
return (
|
|
||||||
this.doBoundingBoxesIntersect(box1, box2) &&
|
|
||||||
this.lineSegmentTouchesOrCrossesLine(aSegment, bSegment) &&
|
|
||||||
this.lineSegmentTouchesOrCrossesLine(bSegment, aSegment)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static isElementIntersectingFrame(
|
|
||||||
element: ExcalidrawElement,
|
|
||||||
frame: ExcalidrawFrameElement,
|
|
||||||
) {
|
|
||||||
const frameLineSegments = getElementLineSegments(frame);
|
|
||||||
|
|
||||||
const elementLineSegments = getElementLineSegments(element);
|
|
||||||
|
|
||||||
const intersecting = frameLineSegments.some((frameLineSegment) =>
|
|
||||||
elementLineSegments.some((elementLineSegment) =>
|
|
||||||
this.doLineSegmentsIntersect(frameLineSegment, elementLineSegment),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return intersecting;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getElementsCompletelyInFrame = (
|
export const getElementsCompletelyInFrame = (
|
||||||
@ -207,10 +99,7 @@ export const isElementContainingFrame = (
|
|||||||
export const getElementsIntersectingFrame = (
|
export const getElementsIntersectingFrame = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
frame: ExcalidrawFrameElement,
|
frame: ExcalidrawFrameElement,
|
||||||
) =>
|
) => elements.filter((element) => isElementIntersectingFrame(element, frame));
|
||||||
elements.filter((element) =>
|
|
||||||
FrameGeometry.isElementIntersectingFrame(element, frame),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const elementsAreInFrameBounds = (
|
export const elementsAreInFrameBounds = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
@ -236,7 +125,7 @@ export const elementOverlapsWithFrame = (
|
|||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
elementsAreInFrameBounds([element], frame) ||
|
elementsAreInFrameBounds([element], frame) ||
|
||||||
FrameGeometry.isElementIntersectingFrame(element, frame) ||
|
isElementIntersectingFrame(element, frame) ||
|
||||||
isElementContainingFrame([frame], element, frame)
|
isElementContainingFrame([frame], element, frame)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -273,7 +162,7 @@ export const groupsAreAtLeastIntersectingTheFrame = (
|
|||||||
return !!elementsInGroup.find(
|
return !!elementsInGroup.find(
|
||||||
(element) =>
|
(element) =>
|
||||||
elementsAreInFrameBounds([element], frame) ||
|
elementsAreInFrameBounds([element], frame) ||
|
||||||
FrameGeometry.isElementIntersectingFrame(element, frame),
|
isElementIntersectingFrame(element, frame),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -294,7 +183,7 @@ export const groupsAreCompletelyOutOfFrame = (
|
|||||||
elementsInGroup.find(
|
elementsInGroup.find(
|
||||||
(element) =>
|
(element) =>
|
||||||
elementsAreInFrameBounds([element], frame) ||
|
elementsAreInFrameBounds([element], frame) ||
|
||||||
FrameGeometry.isElementIntersectingFrame(element, frame),
|
isElementIntersectingFrame(element, frame),
|
||||||
) === undefined
|
) === undefined
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -354,7 +243,7 @@ export const getElementsInResizingFrame = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const element of elementsNotCompletelyInFrame) {
|
for (const element of elementsNotCompletelyInFrame) {
|
||||||
if (!FrameGeometry.isElementIntersectingFrame(element, frame)) {
|
if (!isElementIntersectingFrame(element, frame)) {
|
||||||
if (element.groupIds.length === 0) {
|
if (element.groupIds.length === 0) {
|
||||||
nextElementsInFrame.delete(element);
|
nextElementsInFrame.delete(element);
|
||||||
}
|
}
|
||||||
|
72
src/packages/bbox.ts
Normal file
72
src/packages/bbox.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Point } from "../types";
|
||||||
|
|
||||||
|
export type LineSegment = [Point, Point];
|
||||||
|
export type BBox = [topLeft: Point, bottomRight: Point];
|
||||||
|
|
||||||
|
export function bbox(topLeft: Point, bottomRight: Point): BBox {
|
||||||
|
return [topLeft, bottomRight];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBBox(line: LineSegment): BBox {
|
||||||
|
return [
|
||||||
|
[Math.min(line[0][0], line[1][0]), Math.min(line[0][1], line[1][1])],
|
||||||
|
[Math.max(line[0][0], line[1][0]), Math.max(line[0][1], line[1][1])],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function crossProduct(a: Point, b: Point) {
|
||||||
|
return a[0] * b[1] - b[0] * a[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doBBoxesIntersect(a: BBox, b: BBox) {
|
||||||
|
return (
|
||||||
|
a[0][0] <= b[1][0] &&
|
||||||
|
a[1][0] >= b[0][0] &&
|
||||||
|
a[0][1] <= b[1][1] &&
|
||||||
|
a[1][1] >= b[0][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function translate(a: Point, b: Point): Point {
|
||||||
|
return [a[0] - b[0], a[1] - b[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
const EPSILON = 0.000001;
|
||||||
|
|
||||||
|
export function isPointOnLine(l: LineSegment, p: Point) {
|
||||||
|
const p1 = translate(l[1], l[0]);
|
||||||
|
const p2 = translate(p, l[0]);
|
||||||
|
|
||||||
|
const r = crossProduct(p1, p2);
|
||||||
|
|
||||||
|
return Math.abs(r) < EPSILON;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPointRightOfLine(l: LineSegment, p: Point) {
|
||||||
|
const p1 = translate(l[1], l[0]);
|
||||||
|
const p2 = translate(p, l[0]);
|
||||||
|
|
||||||
|
return crossProduct(p1, p2) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLineSegmentTouchingOrCrossingLine(
|
||||||
|
a: LineSegment,
|
||||||
|
b: LineSegment,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
isPointOnLine(a, b[0]) ||
|
||||||
|
isPointOnLine(a, b[1]) ||
|
||||||
|
(isPointRightOfLine(a, b[0])
|
||||||
|
? !isPointRightOfLine(a, b[1])
|
||||||
|
: isPointRightOfLine(a, b[1]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://martin-thoma.com/how-to-check-if-two-line-segments-intersect/
|
||||||
|
export function doLineSegmentsIntersect(a: LineSegment, b: LineSegment) {
|
||||||
|
return (
|
||||||
|
doBBoxesIntersect(getBBox(a), getBBox(b)) &&
|
||||||
|
isLineSegmentTouchingOrCrossingLine(a, b) &&
|
||||||
|
isLineSegmentTouchingOrCrossingLine(b, a)
|
||||||
|
);
|
||||||
|
}
|
@ -226,6 +226,11 @@ export const exportToClipboard = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export * from "./bbox";
|
||||||
|
export {
|
||||||
|
elementsOverlappingBBox,
|
||||||
|
isElementOverlappingBBox,
|
||||||
|
} from "./withinBounds";
|
||||||
export { serializeAsJSON, serializeLibraryAsJSON } from "../data/json";
|
export { serializeAsJSON, serializeLibraryAsJSON } from "../data/json";
|
||||||
export {
|
export {
|
||||||
loadFromBlob,
|
loadFromBlob,
|
||||||
|
224
src/packages/withinBounds.ts
Normal file
224
src/packages/withinBounds.ts
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
import { BBox, bbox } from "./bbox";
|
||||||
|
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||||
|
import {
|
||||||
|
isArrowElement,
|
||||||
|
isFreeDrawElement,
|
||||||
|
isLinearElement,
|
||||||
|
isTextElement,
|
||||||
|
} from "../element/typeChecks";
|
||||||
|
import { getBoundsFromPoints } from "../element/bounds";
|
||||||
|
import { rotatePoint } from "../math";
|
||||||
|
import { Point } from "../types";
|
||||||
|
|
||||||
|
type Element = NonDeletedExcalidrawElement;
|
||||||
|
type Elements = readonly NonDeletedExcalidrawElement[];
|
||||||
|
|
||||||
|
function getVertices(bbox: BBox): [Point, Point, Point, Point] {
|
||||||
|
return [bbox[0], [bbox[1][0], bbox[0][1]], bbox[1], [bbox[0][0], bbox[1][1]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrimitiveBBox(element: Element): BBox {
|
||||||
|
if (isFreeDrawElement(element)) {
|
||||||
|
const [minX, minY, maxX, maxY] = getBoundsFromPoints(element.points);
|
||||||
|
|
||||||
|
return bbox(
|
||||||
|
[minX + element.x, minY + element.y],
|
||||||
|
[maxX + element.x, maxY + element.y],
|
||||||
|
);
|
||||||
|
} else if (isLinearElement(element)) {
|
||||||
|
const { minX, minY, maxX, maxY } = element.points.reduce(
|
||||||
|
(limits, [x, y]) => {
|
||||||
|
limits.minY = Math.min(limits.minY, y);
|
||||||
|
limits.minX = Math.min(limits.minX, x);
|
||||||
|
|
||||||
|
limits.maxX = Math.max(limits.maxX, x);
|
||||||
|
limits.maxY = Math.max(limits.maxY, y);
|
||||||
|
|
||||||
|
return limits;
|
||||||
|
},
|
||||||
|
{ minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity },
|
||||||
|
);
|
||||||
|
|
||||||
|
return bbox(
|
||||||
|
[element.x + minX, element.y + minY],
|
||||||
|
[element.x + maxX, element.y + maxY],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bbox(
|
||||||
|
[element.x, element.y],
|
||||||
|
[element.x + element.width, element.y + element.height],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElementBBox(element: Element): BBox {
|
||||||
|
const primitiveBBox = getPrimitiveBBox(element);
|
||||||
|
|
||||||
|
const centerPoint: Point = [
|
||||||
|
primitiveBBox[0][0] + (primitiveBBox[1][0] - primitiveBBox[0][0]) / 2,
|
||||||
|
primitiveBBox[0][1] + (primitiveBBox[1][1] - primitiveBBox[0][1]) / 2,
|
||||||
|
];
|
||||||
|
|
||||||
|
const [otl, otr, obr, obl] = getVertices(primitiveBBox);
|
||||||
|
|
||||||
|
const rtl = rotatePoint(otl, centerPoint, element.angle);
|
||||||
|
const rbr = rotatePoint(obr, centerPoint, element.angle);
|
||||||
|
const rtr = rotatePoint(otr, centerPoint, element.angle);
|
||||||
|
const rbl = rotatePoint(obl, centerPoint, element.angle);
|
||||||
|
|
||||||
|
return bbox(
|
||||||
|
[
|
||||||
|
Math.min(rtl[0], rbr[0], rtr[0], rbl[0]),
|
||||||
|
Math.min(rtl[1], rbr[1], rtr[1], rbl[1]),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Math.max(rtl[0], rbr[0], rtr[0], rbl[0]),
|
||||||
|
Math.max(rtl[1], rbr[1], rtr[1], rbl[1]),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isElementInsideBBox(element: Element, bbox: BBox): boolean {
|
||||||
|
const elementBBox = getElementBBox(element);
|
||||||
|
|
||||||
|
return (
|
||||||
|
bbox[0][0] < elementBBox[0][0] &&
|
||||||
|
bbox[1][0] > elementBBox[1][0] &&
|
||||||
|
bbox[0][1] < elementBBox[0][1] &&
|
||||||
|
bbox[1][1] > elementBBox[1][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValueInRange(value: number, min: number, max: number) {
|
||||||
|
return value >= min && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isElementIntersectingBBox(element: Element, bbox: BBox): boolean {
|
||||||
|
const elementBBox = getElementBBox(element);
|
||||||
|
|
||||||
|
return (
|
||||||
|
bbox[0][0] < elementBBox[0][0] &&
|
||||||
|
bbox[1][0] > elementBBox[1][0] &&
|
||||||
|
bbox[0][1] < elementBBox[0][1] &&
|
||||||
|
bbox[1][1] > elementBBox[1][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isElementContainingBBox(element: Element, bbox: BBox): boolean {
|
||||||
|
const elementBBox = getElementBBox(element);
|
||||||
|
|
||||||
|
return (
|
||||||
|
(isValueInRange(elementBBox[0][0], bbox[0][0], bbox[1][0]) ||
|
||||||
|
isValueInRange(bbox[0][0], elementBBox[0][0], elementBBox[1][0])) &&
|
||||||
|
(isValueInRange(elementBBox[0][1], bbox[0][1], bbox[1][1]) ||
|
||||||
|
isValueInRange(bbox[0][1], elementBBox[0][1], elementBBox[1][1]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isElementOverlappingBBox(element: Element, bbox: BBox) {
|
||||||
|
return (
|
||||||
|
isElementInsideBBox(element, bbox) ||
|
||||||
|
isElementIntersectingBBox(element, bbox) ||
|
||||||
|
isElementContainingBBox(element, bbox)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const elementsOverlappingBBox = ({
|
||||||
|
elements,
|
||||||
|
bounds,
|
||||||
|
errorMargin = 0,
|
||||||
|
}: {
|
||||||
|
elements: Elements;
|
||||||
|
bounds: BBox;
|
||||||
|
errorMargin: number;
|
||||||
|
}) => {
|
||||||
|
const adjustedBBox = bbox(
|
||||||
|
[bounds[0][0] - errorMargin, bounds[0][1] - errorMargin],
|
||||||
|
[bounds[1][0] + errorMargin, bounds[1][1] + errorMargin],
|
||||||
|
);
|
||||||
|
|
||||||
|
const includedElementSet = new Set<string>();
|
||||||
|
|
||||||
|
for (const element of elements) {
|
||||||
|
if (includedElementSet.has(element.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOverlaping = isElementOverlappingBBox(element, adjustedBBox);
|
||||||
|
|
||||||
|
if (isOverlaping) {
|
||||||
|
includedElementSet.add(element.id);
|
||||||
|
|
||||||
|
if (element.boundElements) {
|
||||||
|
for (const boundElement of element.boundElements) {
|
||||||
|
includedElementSet.add(boundElement.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTextElement(element) && element.containerId) {
|
||||||
|
includedElementSet.add(element.containerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArrowElement(element)) {
|
||||||
|
if (element.startBinding) {
|
||||||
|
includedElementSet.add(element.startBinding.elementId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.endBinding) {
|
||||||
|
includedElementSet.add(element.endBinding?.elementId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements.filter((element) => includedElementSet.has(element.id));
|
||||||
|
};
|
||||||
|
|
||||||
|
// ### DEBUG
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
debug: () => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.debug = () => {
|
||||||
|
const boundsIndex = window.h.elements.findIndex(
|
||||||
|
(e) => e.type === "rectangle" && e.strokeStyle === "dashed",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (boundsIndex === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boundsElement = window.h.elements[boundsIndex];
|
||||||
|
|
||||||
|
const boundsBBox = bbox(
|
||||||
|
[boundsElement.x, boundsElement.y],
|
||||||
|
[
|
||||||
|
boundsElement.x + boundsElement.width,
|
||||||
|
boundsElement.y + boundsElement.height,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const allElements = [
|
||||||
|
...window.h.elements.slice(0, boundsIndex),
|
||||||
|
...window.h.elements.slice(boundsIndex + 1, window.h.elements.length),
|
||||||
|
];
|
||||||
|
|
||||||
|
const boundedElements = elementsOverlappingBBox({
|
||||||
|
elements: allElements,
|
||||||
|
bounds: boundsBBox,
|
||||||
|
errorMargin: 0,
|
||||||
|
}).map((element) => element.id);
|
||||||
|
|
||||||
|
const newElements = allElements.map((element) => {
|
||||||
|
if (boundedElements.includes(element.id)) {
|
||||||
|
return { ...element, strokeColor: "#ff0000" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...element, strokeColor: "#000000" };
|
||||||
|
});
|
||||||
|
|
||||||
|
window.h.elements = [boundsElement, ...newElements];
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user