Bounds refactor and duplication removal

This commit is contained in:
Mark Tolmacs 2024-09-27 15:58:18 +02:00
parent 7b4e989d65
commit 91b6057d9c
No known key found for this signature in database
28 changed files with 431 additions and 147 deletions

View file

@ -1,8 +1,8 @@
import type { Bounds } from "../excalidraw/element/bounds";
import type { Bounds } from "../excalidraw/element/types";
import { API } from "../excalidraw/tests/helpers/api";
import {
elementPartiallyOverlapsWithOrContainsBBox,
elementsOverlappingBBox,
elementPartiallyOverlapsWithOrContainsBounds,
elementsOverlappingBounds,
isElementInsideBBox,
} from "./withinBounds";
@ -99,13 +99,13 @@ describe("elementPartiallyOverlapsWithOrContainsBBox()", () => {
// bbox contains element
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(0, 0, 100, 100),
bbox,
),
).toBe(true);
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(10, 10, 90, 90),
bbox,
),
@ -113,7 +113,7 @@ describe("elementPartiallyOverlapsWithOrContainsBBox()", () => {
// element contains bbox
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(-10, -10, 110, 110),
bbox,
),
@ -121,28 +121,28 @@ describe("elementPartiallyOverlapsWithOrContainsBBox()", () => {
// element overlaps bbox from top-left
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(-10, -10, 100, 100),
bbox,
),
).toBe(true);
// element overlaps bbox from top-right
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(90, -10, 100, 100),
bbox,
),
).toBe(true);
// element overlaps bbox from bottom-left
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(-10, 90, 100, 100),
bbox,
),
).toBe(true);
// element overlaps bbox from bottom-right
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(90, 90, 100, 100),
bbox,
),
@ -154,7 +154,7 @@ describe("elementPartiallyOverlapsWithOrContainsBBox()", () => {
// outside diagonally
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(110, 110, 100, 100),
bbox,
),
@ -162,28 +162,28 @@ describe("elementPartiallyOverlapsWithOrContainsBBox()", () => {
// outside on the left
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(-110, 10, 50, 50),
bbox,
),
).toBe(false);
// outside on the right
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(110, 10, 50, 50),
bbox,
),
).toBe(false);
// outside on the top
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(10, -110, 50, 50),
bbox,
),
).toBe(false);
// outside on the bottom
expect(
elementPartiallyOverlapsWithOrContainsBBox(
elementPartiallyOverlapsWithOrContainsBounds(
makeElement(10, 110, 50, 50),
bbox,
),
@ -201,7 +201,7 @@ describe("elementsOverlappingBBox()", () => {
const rectOverlappingTopLeft = makeElement(-10, -10, 50, 50);
expect(
elementsOverlappingBBox({
elementsOverlappingBounds({
bounds: bbox,
type: "overlap",
elements: [
@ -223,7 +223,7 @@ describe("elementsOverlappingBBox()", () => {
const rectOverlappingTopLeft = makeElement(-10, -10, 50, 50);
expect(
elementsOverlappingBBox({
elementsOverlappingBounds({
bounds: bbox,
type: "contain",
elements: [
@ -245,7 +245,7 @@ describe("elementsOverlappingBBox()", () => {
const rectOverlappingTopLeft = makeElement(-10, -10, 50, 50);
expect(
elementsOverlappingBBox({
elementsOverlappingBounds({
bounds: bbox,
type: "inside",
elements: [

View file

@ -1,4 +1,5 @@
import type {
Bounds,
ExcalidrawElement,
ExcalidrawFreeDrawElement,
ExcalidrawLinearElement,
@ -11,7 +12,6 @@ import {
isLinearElement,
isTextElement,
} from "../excalidraw/element/typeChecks";
import type { Bounds } from "../excalidraw/element/bounds";
import { getElementBounds } from "../excalidraw/element/bounds";
import { arrayToMap } from "../excalidraw/utils";
import type { LocalPoint } from "../math";
@ -22,15 +22,10 @@ import {
rangeInclusive,
} from "../math";
type Element = NonDeletedExcalidrawElement;
type Elements = readonly NonDeletedExcalidrawElement[];
type Points = readonly LocalPoint[];
/** @returns vertices relative to element's top-left [0,0] position */
const getNonLinearElementRelativePoints = (
element: Exclude<
Element,
NonDeletedExcalidrawElement,
ExcalidrawLinearElement | ExcalidrawFreeDrawElement
>,
): [
@ -56,14 +51,16 @@ const getNonLinearElementRelativePoints = (
};
/** @returns vertices relative to element's top-left [0,0] position */
const getElementRelativePoints = (element: ExcalidrawElement): Points => {
const getElementRelativePoints = (
element: ExcalidrawElement,
): readonly LocalPoint[] => {
if (isLinearElement(element) || isFreeDrawElement(element)) {
return element.points;
}
return getNonLinearElementRelativePoints(element);
};
const getMinMaxPoints = (points: Points) => {
const getMinMaxPoints = (points: readonly LocalPoint[]) => {
const ret = points.reduce(
(limits, [x, y]) => {
limits.minY = Math.min(limits.minY, y);
@ -90,7 +87,7 @@ const getMinMaxPoints = (points: Points) => {
return ret;
};
const getRotatedBBox = (element: Element): Bounds => {
const getRotatedBBox = (element: NonDeletedExcalidrawElement): Bounds => {
const points = getElementRelativePoints(element);
const { cx, cy } = getMinMaxPoints(points);
@ -110,7 +107,7 @@ const getRotatedBBox = (element: Element): Bounds => {
};
export const isElementInsideBBox = (
element: Element,
element: NonDeletedExcalidrawElement,
bbox: Bounds,
eitherDirection = false,
): boolean => {
@ -138,8 +135,8 @@ export const isElementInsideBBox = (
);
};
export const elementPartiallyOverlapsWithOrContainsBBox = (
element: Element,
export const elementPartiallyOverlapsWithOrContainsBounds = (
element: NonDeletedExcalidrawElement,
bbox: Bounds,
): boolean => {
const elementBBox = getRotatedBBox(element);
@ -158,13 +155,13 @@ export const elementPartiallyOverlapsWithOrContainsBBox = (
);
};
export const elementsOverlappingBBox = ({
export const elementsOverlappingBounds = ({
elements,
bounds,
type,
errorMargin = 0,
}: {
elements: Elements;
elements: readonly NonDeletedExcalidrawElement[];
bounds: Bounds | ExcalidrawElement;
/** safety offset. Defaults to 0. */
errorMargin?: number;
@ -194,7 +191,7 @@ export const elementsOverlappingBBox = ({
const isOverlaping =
type === "overlap"
? elementPartiallyOverlapsWithOrContainsBBox(element, adjustedBBox)
? elementPartiallyOverlapsWithOrContainsBounds(element, adjustedBBox)
: type === "inside"
? isElementInsideBBox(element, adjustedBBox)
: isElementInsideBBox(element, adjustedBBox, true);