From f3dba020b0c1cd0b3f4df4943a08c2704a57a1df Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Mon, 30 Mar 2026 14:17:53 +0000 Subject: [PATCH] chore: Introducing RotatedBounds Signed-off-by: Mark Tolmacs --- packages/common/src/bounds.ts | 37 +++++- packages/element/src/bounds.ts | 133 +++++++++++--------- packages/element/src/collision.ts | 45 ++++--- packages/element/src/linearElementEditor.ts | 7 +- packages/excalidraw/components/App.tsx | 4 +- packages/excalidraw/eraser/index.ts | 4 +- packages/excalidraw/lasso/utils.ts | 4 +- packages/math/src/types.ts | 17 ++- packages/utils/src/withinBounds.ts | 35 +++--- 9 files changed, 176 insertions(+), 110 deletions(-) diff --git a/packages/common/src/bounds.ts b/packages/common/src/bounds.ts index b23462dd72..0464b41d48 100644 --- a/packages/common/src/bounds.ts +++ b/packages/common/src/bounds.ts @@ -1,3 +1,5 @@ +import type { Radians } from "@excalidraw/math"; + /** * x and y position of top left corner, x and y position of bottom right corner */ @@ -6,7 +8,31 @@ export type Bounds = readonly [ minY: number, maxX: number, maxY: number, -]; +] & { _brand: "excalidraw__bounds" }; + +export type RotatedBounds = readonly [ + minX: number, + minY: number, + maxX: number, + maxY: number, + angle: Radians, +] & { + _brand_rotated: "excalidraw__rotated_bounds"; +}; + +export const bounds = ( + minX: number, + minY: number, + maxX: number, + maxY: number, + angle: T = undefined as T, +) => { + return ( + angle + ? ([minX, minY, maxX, maxY, angle] as unknown) + : ([minX, minY, maxX, maxY] as unknown) + ) as T extends Radians ? RotatedBounds : Bounds; +}; export const isBounds = (box: unknown): box is Bounds => Array.isArray(box) && @@ -15,3 +41,12 @@ export const isBounds = (box: unknown): box is Bounds => typeof box[1] === "number" && typeof box[2] === "number" && typeof box[3] === "number"; + +export const isRotatedBounds = (box: unknown): box is RotatedBounds => + Array.isArray(box) && + box.length === 5 && + typeof box[0] === "number" && + typeof box[1] === "number" && + typeof box[2] === "number" && + typeof box[3] === "number" && + typeof box[4] === "number"; diff --git a/packages/element/src/bounds.ts b/packages/element/src/bounds.ts index ebecc7b5bb..581e3f176c 100644 --- a/packages/element/src/bounds.ts +++ b/packages/element/src/bounds.ts @@ -2,9 +2,11 @@ import rough from "roughjs/bin/rough"; import { arrayToMap, + bounds, type Bounds, invariant, rescalePoints, + type RotatedBounds, sizeOf, } from "@excalidraw/common"; @@ -27,7 +29,6 @@ import type { GlobalPoint, LineSegment, LocalPoint, - NonRotated, Radians, } from "@excalidraw/math"; @@ -91,7 +92,7 @@ export class ElementBounds { private static boundsCache = new WeakMap< ExcalidrawElement, { - bounds: Bounds; + bounds: RotatedBounds; version: ExcalidrawElement["version"]; } >(); @@ -103,11 +104,11 @@ export class ElementBounds { } >(); - static getBounds( + static getBounds( element: ExcalidrawElement, elementsMap: ElementsMap, - nonRotated: boolean = false, - ) { + nonRotated: T = false as T, + ): T extends true ? Bounds : RotatedBounds { const cachedBounds = nonRotated && element.angle !== 0 ? ElementBounds.nonRotatedBoundsCache.get(element) @@ -120,40 +121,41 @@ export class ElementBounds { // which is causing problems down the line. Fix TBA. !isBoundToContainer(element) ) { - return cachedBounds.bounds; + return cachedBounds.bounds as T extends true ? Bounds : RotatedBounds; } if (nonRotated && element.angle !== 0) { - const nonRotatedBounds = ElementBounds.calculateBounds( + const [minX, minY, maxX, maxY] = ElementBounds.calculateBounds( { ...element, angle: 0 as Radians, }, elementsMap, ); + const nonRotatedBounds = bounds(minX, minY, maxX, maxY); ElementBounds.nonRotatedBoundsCache.set(element, { version: element.version, bounds: nonRotatedBounds, }); - return nonRotatedBounds; + return nonRotatedBounds as T extends true ? Bounds : RotatedBounds; } - const bounds = ElementBounds.calculateBounds(element, elementsMap); + const _bounds = ElementBounds.calculateBounds(element, elementsMap); ElementBounds.boundsCache.set(element, { version: element.version, - bounds, + bounds: _bounds, }); - return bounds; + return _bounds as T extends true ? Bounds : RotatedBounds; } private static calculateBounds( element: ExcalidrawElement, elementsMap: ElementsMap, - ): Bounds { - let bounds: Bounds; + ): RotatedBounds { + let _bounds: RotatedBounds; const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords( element, @@ -170,14 +172,15 @@ export class ElementBounds { ), ); - return [ + return bounds( minX + element.x, minY + element.y, maxX + element.x, maxY + element.y, - ]; + element.angle, + ); } else if (isLinearElement(element)) { - bounds = getLinearElementRotatedBounds(element, cx, cy, elementsMap); + _bounds = getLinearElementRotatedBounds(element, cx, cy, elementsMap); } else if (element.type === "diamond") { const [x11, y11] = pointRotateRads( pointFrom(cx, y1), @@ -203,7 +206,7 @@ export class ElementBounds { const minY = Math.min(y11, y12, y22, y21); const maxX = Math.max(x11, x12, x22, x21); const maxY = Math.max(y11, y12, y22, y21); - bounds = [minX, minY, maxX, maxY]; + _bounds = bounds(minX, minY, maxX, maxY, element.angle); } else if (element.type === "ellipse") { const w = (x2 - x1) / 2; const h = (y2 - y1) / 2; @@ -211,7 +214,7 @@ export class ElementBounds { const sin = Math.sin(element.angle); const ww = Math.hypot(w * cos, h * sin); const hh = Math.hypot(h * cos, w * sin); - bounds = [cx - ww, cy - hh, cx + ww, cy + hh]; + _bounds = bounds(cx - ww, cy - hh, cx + ww, cy + hh, element.angle); } else { const [x11, y11] = pointRotateRads( pointFrom(x1, y1), @@ -237,10 +240,10 @@ export class ElementBounds { const minY = Math.min(y11, y12, y22, y21); const maxX = Math.max(x11, x12, x22, x21); const maxY = Math.max(y11, y12, y22, y21); - bounds = [minX, minY, maxX, maxY]; + _bounds = bounds(minX, minY, maxX, maxY, element.angle); } - return bounds; + return _bounds; } } @@ -625,7 +628,7 @@ export const getCubicBezierCurveBound = ( minY = Math.min(minY, ...ys); maxY = Math.max(maxY, ...ys); } - return [minX, minY, maxX, maxY]; + return bounds(minX, minY, maxX, maxY); }; export const getMinMaxXYFromCurvePathOps = ( @@ -678,7 +681,7 @@ export const getMinMaxXYFromCurvePathOps = ( }, { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity }, ); - return [minX, minY, maxX, maxY]; + return bounds(minX, minY, maxX, maxY); }; export const getBoundsFromPoints = ( @@ -696,7 +699,7 @@ export const getBoundsFromPoints = ( maxY = Math.max(maxY, y); } - return [minX, minY, maxX, maxY]; + return bounds(minX, minY, maxX, maxY); }; const getFreeDrawElementAbsoluteCoords = ( @@ -939,7 +942,7 @@ const getLinearElementRotatedBounds = ( cx: number, cy: number, elementsMap: ElementsMap, -): Bounds => { +): RotatedBounds => { const boundTextElement = getBoundTextElement(element, elementsMap); if (element.points.length < 2) { @@ -950,20 +953,21 @@ const getLinearElementRotatedBounds = ( element.angle, ); - let coords: Bounds = [x, y, x, y]; + let coords: RotatedBounds = bounds(x, y, x, y, element.angle); if (boundTextElement) { const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText( element, elementsMap, - [x, y, x, y], + bounds(x, y, x, y, element.angle), boundTextElement, ); - coords = [ + coords = bounds( coordsWithBoundText[0], coordsWithBoundText[1], coordsWithBoundText[2], coordsWithBoundText[3], - ]; + element.angle, + ); } return coords; } @@ -979,7 +983,13 @@ const getLinearElementRotatedBounds = ( element.angle, ); const res = getMinMaxXYFromCurvePathOps(ops, transformXY); - let coords: Bounds = [res[0], res[1], res[2], res[3]]; + let coords: RotatedBounds = bounds( + res[0], + res[1], + res[2], + res[3], + element.angle, + ); if (boundTextElement) { const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText( element, @@ -987,12 +997,13 @@ const getLinearElementRotatedBounds = ( coords, boundTextElement, ); - coords = [ + coords = bounds( coordsWithBoundText[0], coordsWithBoundText[1], coordsWithBoundText[2], coordsWithBoundText[3], - ]; + element.angle, + ); } return coords; }; @@ -1001,12 +1012,8 @@ export const getElementBounds = ( element: ExcalidrawElement, elementsMap: ElementsMap, nonRotated: T = false as T, -): T extends true ? NonRotated : Bounds => { - return ElementBounds.getBounds( - element, - elementsMap, - nonRotated, - ) as T extends true ? NonRotated : Bounds; +) => { + return ElementBounds.getBounds(element, elementsMap, nonRotated); }; export const getCommonBounds = ( @@ -1014,7 +1021,7 @@ export const getCommonBounds = ( elementsMap?: ElementsMap, ): Bounds => { if (!sizeOf(elements)) { - return [0, 0, 0, 0]; + return bounds(0, 0, 0, 0); } let minX = Infinity; @@ -1032,7 +1039,7 @@ export const getCommonBounds = ( maxY = Math.max(maxY, y2); }); - return [minX, minY, maxX, maxY]; + return bounds(minX, minY, maxX, maxY); }; export const getDraggedElementsBounds = ( @@ -1055,12 +1062,12 @@ export const getResizedElementAbsoluteCoords = ( normalizePoints: boolean, ): Bounds => { if (!(isLinearElement(element) || isFreeDrawElement(element))) { - return [ + return bounds( element.x, element.y, element.x + nextWidth, element.y + nextHeight, - ]; + ); } const points = rescalePoints( @@ -1070,11 +1077,11 @@ export const getResizedElementAbsoluteCoords = ( normalizePoints, ); - let bounds: Bounds; + let _bounds: Bounds; if (isFreeDrawElement(element)) { // Free Draw - bounds = getBoundsFromPoints(points); + _bounds = getBoundsFromPoints(points); } else { // Line const gen = rough.generator(); @@ -1086,16 +1093,16 @@ export const getResizedElementAbsoluteCoords = ( : gen.curve(points as [number, number][], generateRoughOptions(element)); const ops = getCurvePathOps(curve); - bounds = getMinMaxXYFromCurvePathOps(ops); + _bounds = getMinMaxXYFromCurvePathOps(ops); } - const [minX, minY, maxX, maxY] = bounds; - return [ + const [minX, minY, maxX, maxY] = _bounds; + return bounds( minX + element.x, minY + element.y, maxX + element.x, maxY + element.y, - ]; + ); }; export const getElementPointsCoords = ( @@ -1113,20 +1120,20 @@ export const getElementPointsCoords = ( : gen.curve(points as [number, number][], generateRoughOptions(element)); const ops = getCurvePathOps(curve); const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops); - return [ + return bounds( minX + element.x, minY + element.y, maxX + element.x, maxY + element.y, - ]; + ); }; export const getClosestElementBounds = ( elements: readonly ExcalidrawElement[], from: { x: number; y: number }, -): Bounds => { +): RotatedBounds => { if (!elements.length) { - return [0, 0, 0, 0]; + return bounds(0, 0, 0, 0, 0 as Radians); } let minDistance = Infinity; @@ -1195,7 +1202,9 @@ export const getVisibleSceneBounds = ({ ]; }; -export const getCenterForBounds = (bounds: Bounds): GlobalPoint => +export const getCenterForBounds = ( + bounds: Bounds | RotatedBounds, +): GlobalPoint => pointFrom( bounds[0] + (bounds[2] - bounds[0]) / 2, bounds[1] + (bounds[3] - bounds[1]) / 2, @@ -1240,24 +1249,24 @@ export const aabbForElement = ( element.angle, ); - const bounds = [ + const _bounds = bounds( Math.min(topLeftX, topRightX, bottomRightX, bottomLeftX), Math.min(topLeftY, topRightY, bottomRightY, bottomLeftY), Math.max(topLeftX, topRightX, bottomRightX, bottomLeftX), Math.max(topLeftY, topRightY, bottomRightY, bottomLeftY), - ] as Bounds; + ); if (offset) { const [topOffset, rightOffset, downOffset, leftOffset] = offset; - return [ - bounds[0] - leftOffset, - bounds[1] - topOffset, - bounds[2] + rightOffset, - bounds[3] + downOffset, - ] as Bounds; + return bounds( + _bounds[0] - leftOffset, + _bounds[1] - topOffset, + _bounds[2] + rightOffset, + _bounds[3] + downOffset, + ); } - return bounds; + return _bounds; }; export const pointInsideBounds =

( @@ -1266,7 +1275,7 @@ export const pointInsideBounds =

( ): boolean => p[0] > bounds[0] && p[0] < bounds[2] && p[1] > bounds[1] && p[1] < bounds[3]; -export const doBoundsIntersect = ( +export const doNonRotatedBoundsIntersect = ( bounds1: Bounds | null, bounds2: Bounds | null, ): boolean => { diff --git a/packages/element/src/collision.ts b/packages/element/src/collision.ts index 0d89f18cb6..93f04411f1 100644 --- a/packages/element/src/collision.ts +++ b/packages/element/src/collision.ts @@ -1,4 +1,9 @@ -import { invariant, isTransparent, type Bounds } from "@excalidraw/common"; +import { + bounds, + invariant, + isTransparent, + type Bounds, +} from "@excalidraw/common"; import { curveIntersectLineSegment, isPointWithinBounds, @@ -22,7 +27,6 @@ import type { Curve, GlobalPoint, LineSegment, - NonRotated, Radians, } from "@excalidraw/math"; @@ -30,7 +34,7 @@ import type { FrameNameBounds } from "@excalidraw/excalidraw/types"; import { isPathALoop } from "./utils"; import { - doBoundsIntersect, + doNonRotatedBoundsIntersect, elementCenterPoint, getCenterForBounds, getCubicBezierCurveBound, @@ -194,7 +198,7 @@ export function getBoundsCorners( bounds: Bounds, ): readonly [GlobalPoint, GlobalPoint, GlobalPoint, GlobalPoint]; export function getBoundsCorners( - bounds: NonRotated, + bounds: Bounds, angle: Radians, ): readonly [GlobalPoint, GlobalPoint, GlobalPoint, GlobalPoint]; export function getBoundsCorners( @@ -234,7 +238,7 @@ export const getBoundsEdges = ( const isPointInRotatedBounds = ( point: GlobalPoint, - bounds: NonRotated, + bounds: Bounds, angle: Radians, tolerance = 0, ) => { @@ -344,9 +348,13 @@ const bindingBorderTest = ( // PERF: Run a cheap test to see if the binding element // is even close to the element const t = Math.max(1, tolerance); - const bounds = [x - t, y - t, x + t, y + t] as Bounds; - const elementBounds = getElementBounds(element, elementsMap); - if (!doBoundsIntersect(bounds, elementBounds)) { + const elementBounds = getElementBounds(element, elementsMap, true); + if ( + !doNonRotatedBoundsIntersect( + bounds(x - t, y - t, x + t, y + t), + elementBounds, + ) + ) { return false; } @@ -357,6 +365,7 @@ const bindingBorderTest = ( const enclosingFrameBounds = getElementBounds( enclosingFrame, elementsMap, + true, ); if (!pointInsideBounds(p, enclosingFrameBounds)) { return false; @@ -506,15 +515,15 @@ export const intersectElementWithLineSegment = ( ): GlobalPoint[] => { // First check if the line intersects the element's axis-aligned bounding box // as it is much faster than checking intersection against the element's shape - const intersectorBounds = [ + const intersectorBounds = bounds( Math.min(line[0][0] - offset, line[1][0] - offset), Math.min(line[0][1] - offset, line[1][1] - offset), Math.max(line[0][0] + offset, line[1][0] + offset), Math.max(line[0][1] + offset, line[1][1] + offset), - ] as Bounds; - const elementBounds = getElementBounds(element, elementsMap); + ); + const elementBounds = getElementBounds(element, elementsMap, true); - if (!doBoundsIntersect(intersectorBounds, elementBounds)) { + if (!doNonRotatedBoundsIntersect(intersectorBounds, elementBounds)) { return []; } @@ -573,14 +582,14 @@ const curveIntersections = ( for (const c of curves) { // Optimize by doing a cheap bounding box check first const b1 = getCubicBezierCurveBound(c[0], c[1], c[2], c[3]); - const b2 = [ + const b2 = bounds( Math.min(segment[0][0], segment[1][0]), Math.min(segment[0][1], segment[1][1]), Math.max(segment[0][0], segment[1][0]), Math.max(segment[0][1], segment[1][1]), - ] as Bounds; + ); - if (!doBoundsIntersect(b1, b2)) { + if (!doNonRotatedBoundsIntersect(b1, b2)) { continue; } @@ -650,14 +659,14 @@ const intersectLinearOrFreeDrawWithLineSegment = ( for (const c of curves) { // Optimize by doing a cheap bounding box check first const b1 = getCubicBezierCurveBound(c[0], c[1], c[2], c[3]); - const b2 = [ + const b2 = bounds( Math.min(segment[0][0], segment[1][0]), Math.min(segment[0][1], segment[1][1]), Math.max(segment[0][0], segment[1][0]), Math.max(segment[0][1], segment[1][1]), - ] as Bounds; + ); - if (!doBoundsIntersect(b1, b2)) { + if (!doNonRotatedBoundsIntersect(b1, b2)) { continue; } diff --git a/packages/element/src/linearElementEditor.ts b/packages/element/src/linearElementEditor.ts index 8af8ecd858..6b27ce5543 100644 --- a/packages/element/src/linearElementEditor.ts +++ b/packages/element/src/linearElementEditor.ts @@ -21,6 +21,7 @@ import { invariant, isShallowEqual, getFeatureFlag, + bounds, } from "@excalidraw/common"; import { @@ -42,7 +43,7 @@ import type { NullableGridSize, Zoom, } from "@excalidraw/excalidraw/types"; -import type { Bounds } from "@excalidraw/common"; +import type { RotatedBounds } from "@excalidraw/common"; import { calculateFixedPointForNonElbowArrowBinding, @@ -1879,7 +1880,7 @@ export class LinearElementEditor { static getMinMaxXYWithBoundText = ( element: ExcalidrawLinearElement, elementsMap: ElementsMap, - elementBounds: Bounds, + elementBounds: RotatedBounds, boundTextElement: ExcalidrawTextElementWithContainer, ): [number, number, number, number, number, number] => { let [x1, y1, x2, y2] = elementBounds; @@ -2004,7 +2005,7 @@ export class LinearElementEditor { return LinearElementEditor.getMinMaxXYWithBoundText( element, elementsMap, - [x1, y1, x2, y2], + bounds(x1, y1, x2, y2, element.angle), boundTextElement, ); } diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 7382e9d503..e553c03e78 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -246,7 +246,7 @@ import { bindOrUnbindBindingElement, mutateElement, getElementBounds, - doBoundsIntersect, + doNonRotatedBoundsIntersect, isPointInElement, maxBindingDistance_simple, convertToExcalidrawElements, @@ -1154,7 +1154,7 @@ class App extends React.Component { startBounds && endBounds && startElement.id !== endElement.id && - doBoundsIntersect(startBounds, endBounds) + doNonRotatedBoundsIntersect(startBounds, endBounds) ); } diff --git a/packages/excalidraw/eraser/index.ts b/packages/excalidraw/eraser/index.ts index cf60309886..c0e84bf1c8 100644 --- a/packages/excalidraw/eraser/index.ts +++ b/packages/excalidraw/eraser/index.ts @@ -2,7 +2,7 @@ import { arrayToMap, easeOut, THEME } from "@excalidraw/common"; import { computeBoundTextPosition, - doBoundsIntersect, + doNonRotatedBoundsIntersect, getBoundTextElement, getElementBounds, getElementLineSegments, @@ -219,7 +219,7 @@ const eraserTest = ( origElementBounds[3] + threshold, ]; - if (!doBoundsIntersect(segmentBounds, elementBounds)) { + if (!doNonRotatedBoundsIntersect(segmentBounds, elementBounds)) { return false; } diff --git a/packages/excalidraw/lasso/utils.ts b/packages/excalidraw/lasso/utils.ts index f7eb7cba55..445f53c40e 100644 --- a/packages/excalidraw/lasso/utils.ts +++ b/packages/excalidraw/lasso/utils.ts @@ -10,7 +10,7 @@ import { type Bounds } from "@excalidraw/common"; import { computeBoundTextPosition, - doBoundsIntersect, + doNonRotatedBoundsIntersect, getBoundTextElement, getElementBounds, intersectElementWithLineSegment, @@ -66,7 +66,7 @@ export const getLassoSelectedElementIds = (input: { const elementBounds = getElementBounds(element, elementsMap); if ( - doBoundsIntersect(lassoBounds, elementBounds) && + doNonRotatedBoundsIntersect(lassoBounds, elementBounds) && !intersectedElements.has(element.id) && !enclosedElements.has(element.id) ) { diff --git a/packages/math/src/types.ts b/packages/math/src/types.ts index 9842901e68..6dfcca2e03 100644 --- a/packages/math/src/types.ts +++ b/packages/math/src/types.ts @@ -1,3 +1,14 @@ +// +// Generic markers +// + +/** + * Can be used for any type of point-likes to mark them as rotated to enlist + * the type checker to weed out subtle bugs due to rotated and non-rotated + * versions of the same data point. + */ +export type Rotated = T & { _brand_rotated: "excalimath_rotated" }; + // // Measurements // @@ -23,12 +34,6 @@ export type Degrees = number & { _brand: "excalimath_degree" }; */ export type InclusiveRange = [number, number] & { _brand: "excalimath_degree" }; -/** - * Can be used for any type of point-likes that are non-rotated, such as - * non-AABB Bounds, or non-rotated Point. - */ -export type NonRotated = T & { _brand_nonrotated: "excalimath_nonrotated" }; - // // Point // diff --git a/packages/utils/src/withinBounds.ts b/packages/utils/src/withinBounds.ts index 3ffab9d370..4d50bb9d1a 100644 --- a/packages/utils/src/withinBounds.ts +++ b/packages/utils/src/withinBounds.ts @@ -1,4 +1,9 @@ -import { arrayToMap, type Bounds } from "@excalidraw/common"; +import { + arrayToMap, + bounds, + type RotatedBounds, + type Bounds, +} from "@excalidraw/common"; import { getElementBounds } from "@excalidraw/element"; import { isArrowElement, @@ -90,7 +95,7 @@ const getMinMaxPoints = (points: Points) => { return ret; }; -const getRotatedBBox = (element: Element): Bounds => { +const getRotatedBBox = (element: Element): RotatedBounds => { const points = getElementRelativePoints(element); const { cx, cy } = getMinMaxPoints(points); @@ -101,12 +106,13 @@ const getRotatedBBox = (element: Element): Bounds => { ); const { minX, minY, maxX, maxY } = getMinMaxPoints(rotatedPoints); - return [ + return bounds( minX + element.x, minY + element.y, maxX + element.x, maxY + element.y, - ]; + element.angle, + ); }; export const isElementInsideBBox = ( @@ -160,12 +166,12 @@ export const elementPartiallyOverlapsWithOrContainsBBox = ( export const elementsOverlappingBBox = ({ elements, - bounds, + bounds: _bounds, type, errorMargin = 0, }: { elements: Elements; - bounds: Bounds | ExcalidrawElement; + bounds: RotatedBounds | ExcalidrawElement; /** safety offset. Defaults to 0. */ errorMargin?: number; /** @@ -175,15 +181,16 @@ export const elementsOverlappingBBox = ({ **/ type: "overlap" | "contain" | "inside"; }) => { - if (isExcalidrawElement(bounds)) { - bounds = getElementBounds(bounds, arrayToMap(elements)); + if (isExcalidrawElement(_bounds)) { + _bounds = getElementBounds(_bounds, arrayToMap(elements)); } - const adjustedBBox: Bounds = [ - bounds[0] - errorMargin, - bounds[1] - errorMargin, - bounds[2] + errorMargin, - bounds[3] + errorMargin, - ]; + const adjustedBBox = bounds( + _bounds[0] - errorMargin, + _bounds[1] - errorMargin, + _bounds[2] + errorMargin, + _bounds[3] + errorMargin, + _bounds[4], + ); const includedElementSet = new Set();