summaryrefslogtreecommitdiffstats
path: root/packages/utils/withinBounds.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/utils/withinBounds.test.ts')
-rw-r--r--packages/utils/withinBounds.test.ts262
1 files changed, 262 insertions, 0 deletions
diff --git a/packages/utils/withinBounds.test.ts b/packages/utils/withinBounds.test.ts
new file mode 100644
index 0000000..85354d7
--- /dev/null
+++ b/packages/utils/withinBounds.test.ts
@@ -0,0 +1,262 @@
+import type { Bounds } from "@excalidraw/excalidraw/element/bounds";
+import { API } from "@excalidraw/excalidraw/tests/helpers/api";
+import {
+ elementPartiallyOverlapsWithOrContainsBBox,
+ elementsOverlappingBBox,
+ isElementInsideBBox,
+} from "./withinBounds";
+
+const makeElement = (x: number, y: number, width: number, height: number) =>
+ API.createElement({
+ type: "rectangle",
+ x,
+ y,
+ width,
+ height,
+ });
+
+const makeBBox = (
+ minX: number,
+ minY: number,
+ maxX: number,
+ maxY: number,
+): Bounds => [minX, minY, maxX, maxY];
+
+describe("isElementInsideBBox()", () => {
+ it("should return true if element is fully inside", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ // bbox contains element
+ expect(isElementInsideBBox(makeElement(0, 0, 100, 100), bbox)).toBe(true);
+ expect(isElementInsideBBox(makeElement(10, 10, 90, 90), bbox)).toBe(true);
+ });
+
+ it("should return false if element is only partially overlapping", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ // element contains bbox
+ expect(isElementInsideBBox(makeElement(-10, -10, 110, 110), bbox)).toBe(
+ false,
+ );
+
+ // element overlaps bbox from top-left
+ expect(isElementInsideBBox(makeElement(-10, -10, 100, 100), bbox)).toBe(
+ false,
+ );
+ // element overlaps bbox from top-right
+ expect(isElementInsideBBox(makeElement(90, -10, 100, 100), bbox)).toBe(
+ false,
+ );
+ // element overlaps bbox from bottom-left
+ expect(isElementInsideBBox(makeElement(-10, 90, 100, 100), bbox)).toBe(
+ false,
+ );
+ // element overlaps bbox from bottom-right
+ expect(isElementInsideBBox(makeElement(90, 90, 100, 100), bbox)).toBe(
+ false,
+ );
+ });
+
+ it("should return false if element outside", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ // outside diagonally
+ expect(isElementInsideBBox(makeElement(110, 110, 100, 100), bbox)).toBe(
+ false,
+ );
+
+ // outside on the left
+ expect(isElementInsideBBox(makeElement(-110, 10, 50, 50), bbox)).toBe(
+ false,
+ );
+ // outside on the right
+ expect(isElementInsideBBox(makeElement(110, 10, 50, 50), bbox)).toBe(false);
+ // outside on the top
+ expect(isElementInsideBBox(makeElement(10, -110, 50, 50), bbox)).toBe(
+ false,
+ );
+ // outside on the bottom
+ expect(isElementInsideBBox(makeElement(10, 110, 50, 50), bbox)).toBe(false);
+ });
+
+ it("should return true if bbox contains element and flag enabled", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ // element contains bbox
+ expect(
+ isElementInsideBBox(makeElement(-10, -10, 110, 110), bbox, true),
+ ).toBe(true);
+
+ // bbox contains element
+ expect(isElementInsideBBox(makeElement(0, 0, 100, 100), bbox)).toBe(true);
+ expect(isElementInsideBBox(makeElement(10, 10, 90, 90), bbox)).toBe(true);
+ });
+});
+
+describe("elementPartiallyOverlapsWithOrContainsBBox()", () => {
+ it("should return true if element overlaps, is inside, or contains", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ // bbox contains element
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(0, 0, 100, 100),
+ bbox,
+ ),
+ ).toBe(true);
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(10, 10, 90, 90),
+ bbox,
+ ),
+ ).toBe(true);
+
+ // element contains bbox
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(-10, -10, 110, 110),
+ bbox,
+ ),
+ ).toBe(true);
+
+ // element overlaps bbox from top-left
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(-10, -10, 100, 100),
+ bbox,
+ ),
+ ).toBe(true);
+ // element overlaps bbox from top-right
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(90, -10, 100, 100),
+ bbox,
+ ),
+ ).toBe(true);
+ // element overlaps bbox from bottom-left
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(-10, 90, 100, 100),
+ bbox,
+ ),
+ ).toBe(true);
+ // element overlaps bbox from bottom-right
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(90, 90, 100, 100),
+ bbox,
+ ),
+ ).toBe(true);
+ });
+
+ it("should return false if element does not overlap", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ // outside diagonally
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(110, 110, 100, 100),
+ bbox,
+ ),
+ ).toBe(false);
+
+ // outside on the left
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(-110, 10, 50, 50),
+ bbox,
+ ),
+ ).toBe(false);
+ // outside on the right
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(110, 10, 50, 50),
+ bbox,
+ ),
+ ).toBe(false);
+ // outside on the top
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(10, -110, 50, 50),
+ bbox,
+ ),
+ ).toBe(false);
+ // outside on the bottom
+ expect(
+ elementPartiallyOverlapsWithOrContainsBBox(
+ makeElement(10, 110, 50, 50),
+ bbox,
+ ),
+ ).toBe(false);
+ });
+});
+
+describe("elementsOverlappingBBox()", () => {
+ it("should return elements that overlap bbox", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ const rectOutside = makeElement(110, 110, 100, 100);
+ const rectInside = makeElement(10, 10, 90, 90);
+ const rectContainingBBox = makeElement(-10, -10, 110, 110);
+ const rectOverlappingTopLeft = makeElement(-10, -10, 50, 50);
+
+ expect(
+ elementsOverlappingBBox({
+ bounds: bbox,
+ type: "overlap",
+ elements: [
+ rectOutside,
+ rectInside,
+ rectContainingBBox,
+ rectOverlappingTopLeft,
+ ],
+ }),
+ ).toEqual([rectInside, rectContainingBBox, rectOverlappingTopLeft]);
+ });
+
+ it("should return elements inside/containing bbox", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ const rectOutside = makeElement(110, 110, 100, 100);
+ const rectInside = makeElement(10, 10, 90, 90);
+ const rectContainingBBox = makeElement(-10, -10, 110, 110);
+ const rectOverlappingTopLeft = makeElement(-10, -10, 50, 50);
+
+ expect(
+ elementsOverlappingBBox({
+ bounds: bbox,
+ type: "contain",
+ elements: [
+ rectOutside,
+ rectInside,
+ rectContainingBBox,
+ rectOverlappingTopLeft,
+ ],
+ }),
+ ).toEqual([rectInside, rectContainingBBox]);
+ });
+
+ it("should return elements inside bbox", () => {
+ const bbox = makeBBox(0, 0, 100, 100);
+
+ const rectOutside = makeElement(110, 110, 100, 100);
+ const rectInside = makeElement(10, 10, 90, 90);
+ const rectContainingBBox = makeElement(-10, -10, 110, 110);
+ const rectOverlappingTopLeft = makeElement(-10, -10, 50, 50);
+
+ expect(
+ elementsOverlappingBBox({
+ bounds: bbox,
+ type: "inside",
+ elements: [
+ rectOutside,
+ rectInside,
+ rectContainingBBox,
+ rectOverlappingTopLeft,
+ ],
+ }),
+ ).toEqual([rectInside]);
+ });
+
+ // TODO test linear, freedraw, and diamond element types (+rotated)
+});