mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
move the files to src and tests folders under utils
This commit is contained in:
parent
a76999e9a2
commit
58567dd2b6
13 changed files with 55 additions and 42 deletions
133
packages/utils/tests/export.test.ts
Normal file
133
packages/utils/tests/export.test.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
import * as utils from "../src/export";
|
||||
import { diagramFactory } from "../../excalidraw/tests/fixtures/diagramFixture";
|
||||
import { vi } from "vitest";
|
||||
import * as mockedSceneExportUtils from "../../excalidraw/scene/export";
|
||||
|
||||
import { MIME_TYPES } from "../../excalidraw/constants";
|
||||
|
||||
const exportToSvgSpy = vi.spyOn(mockedSceneExportUtils, "exportToSvg");
|
||||
|
||||
describe("exportToCanvas", async () => {
|
||||
const EXPORT_PADDING = 10;
|
||||
|
||||
it("with default arguments", async () => {
|
||||
const canvas = await utils.exportToCanvas({
|
||||
...diagramFactory({ elementOverrides: { width: 100, height: 100 } }),
|
||||
});
|
||||
|
||||
expect(canvas.width).toBe(100 + 2 * EXPORT_PADDING);
|
||||
expect(canvas.height).toBe(100 + 2 * EXPORT_PADDING);
|
||||
});
|
||||
|
||||
it("when custom width and height", async () => {
|
||||
const canvas = await utils.exportToCanvas({
|
||||
...diagramFactory({ elementOverrides: { width: 100, height: 100 } }),
|
||||
getDimensions: () => ({ width: 200, height: 200, scale: 1 }),
|
||||
});
|
||||
|
||||
expect(canvas.width).toBe(200);
|
||||
expect(canvas.height).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe("exportToBlob", async () => {
|
||||
describe("mime type", () => {
|
||||
// afterEach(vi.restoreAllMocks);
|
||||
it("should change image/jpg to image/jpeg", async () => {
|
||||
const blob = await utils.exportToBlob({
|
||||
...diagramFactory(),
|
||||
getDimensions: (width, height) => ({ width, height, scale: 1 }),
|
||||
// testing typo in MIME type (jpg → jpeg)
|
||||
mimeType: "image/jpg",
|
||||
appState: {
|
||||
exportBackground: true,
|
||||
},
|
||||
});
|
||||
expect(blob?.type).toBe(MIME_TYPES.jpg);
|
||||
});
|
||||
it("should default to image/png", async () => {
|
||||
const blob = await utils.exportToBlob({
|
||||
...diagramFactory(),
|
||||
});
|
||||
expect(blob?.type).toBe(MIME_TYPES.png);
|
||||
});
|
||||
|
||||
it("should warn when using quality with image/png", async () => {
|
||||
const consoleSpy = vi
|
||||
.spyOn(console, "warn")
|
||||
.mockImplementationOnce(() => void 0);
|
||||
await utils.exportToBlob({
|
||||
...diagramFactory(),
|
||||
mimeType: MIME_TYPES.png,
|
||||
quality: 1,
|
||||
});
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
`"quality" will be ignored for "${MIME_TYPES.png}" mimeType`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("exportToSvg", () => {
|
||||
const passedElements = () => exportToSvgSpy.mock.calls[0][0];
|
||||
const passedOptions = () => exportToSvgSpy.mock.calls[0][1];
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("with default arguments", async () => {
|
||||
await utils.exportToSvg({
|
||||
...diagramFactory({
|
||||
overrides: { appState: void 0 },
|
||||
}),
|
||||
});
|
||||
|
||||
const passedOptionsWhenDefault = {
|
||||
...passedOptions(),
|
||||
// To avoid varying snapshots
|
||||
name: "name",
|
||||
};
|
||||
expect(passedElements().length).toBe(3);
|
||||
expect(passedOptionsWhenDefault).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// FIXME the utils.exportToSvg no longer filters out deleted elements.
|
||||
// It's already supposed to be passed non-deleted elements by we're not
|
||||
// type-checking for it correctly.
|
||||
it.skip("with deleted elements", async () => {
|
||||
await utils.exportToSvg({
|
||||
...diagramFactory({
|
||||
overrides: { appState: void 0 },
|
||||
elementOverrides: { isDeleted: true },
|
||||
}),
|
||||
});
|
||||
|
||||
expect(passedElements().length).toBe(0);
|
||||
});
|
||||
|
||||
it("with exportPadding", async () => {
|
||||
await utils.exportToSvg({
|
||||
...diagramFactory({ overrides: { appState: { name: "diagram name" } } }),
|
||||
exportPadding: 0,
|
||||
});
|
||||
|
||||
expect(passedElements().length).toBe(3);
|
||||
expect(passedOptions()).toEqual(
|
||||
expect.objectContaining({ exportPadding: 0 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("with exportEmbedScene", async () => {
|
||||
await utils.exportToSvg({
|
||||
...diagramFactory({
|
||||
overrides: {
|
||||
appState: { name: "diagram name", exportEmbedScene: true },
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
expect(passedElements().length).toBe(3);
|
||||
expect(passedOptions().exportEmbedScene).toBe(true);
|
||||
});
|
||||
});
|
256
packages/utils/tests/geometry.test.ts
Normal file
256
packages/utils/tests/geometry.test.ts
Normal file
|
@ -0,0 +1,256 @@
|
|||
import {
|
||||
lineIntersectsLine,
|
||||
lineRotate,
|
||||
pointInEllipse,
|
||||
pointInPolygon,
|
||||
pointLeftofLine,
|
||||
pointOnCurve,
|
||||
pointOnEllipse,
|
||||
pointOnLine,
|
||||
pointOnPolygon,
|
||||
pointOnPolyline,
|
||||
pointRightofLine,
|
||||
pointRotate,
|
||||
} from "../src/geometry/geometry";
|
||||
import type {
|
||||
Curve,
|
||||
Ellipse,
|
||||
Line,
|
||||
Point,
|
||||
Polygon,
|
||||
Polyline,
|
||||
} from "../src/geometry/shape";
|
||||
|
||||
describe("point and line", () => {
|
||||
const line: Line = [
|
||||
[1, 0],
|
||||
[1, 2],
|
||||
];
|
||||
|
||||
it("point on left or right of line", () => {
|
||||
expect(pointLeftofLine([0, 1], line)).toBe(true);
|
||||
expect(pointLeftofLine([1, 1], line)).toBe(false);
|
||||
expect(pointLeftofLine([2, 1], line)).toBe(false);
|
||||
|
||||
expect(pointRightofLine([0, 1], line)).toBe(false);
|
||||
expect(pointRightofLine([1, 1], line)).toBe(false);
|
||||
expect(pointRightofLine([2, 1], line)).toBe(true);
|
||||
});
|
||||
|
||||
it("point on the line", () => {
|
||||
expect(pointOnLine([0, 1], line)).toBe(false);
|
||||
expect(pointOnLine([1, 1], line, 0)).toBe(true);
|
||||
expect(pointOnLine([2, 1], line)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("point and polylines", () => {
|
||||
const polyline: Polyline = [
|
||||
[
|
||||
[1, 0],
|
||||
[1, 2],
|
||||
],
|
||||
[
|
||||
[1, 2],
|
||||
[2, 2],
|
||||
],
|
||||
[
|
||||
[2, 2],
|
||||
[2, 1],
|
||||
],
|
||||
[
|
||||
[2, 1],
|
||||
[3, 1],
|
||||
],
|
||||
];
|
||||
|
||||
it("point on the line", () => {
|
||||
expect(pointOnPolyline([1, 0], polyline)).toBe(true);
|
||||
expect(pointOnPolyline([1, 2], polyline)).toBe(true);
|
||||
expect(pointOnPolyline([2, 2], polyline)).toBe(true);
|
||||
expect(pointOnPolyline([2, 1], polyline)).toBe(true);
|
||||
expect(pointOnPolyline([3, 1], polyline)).toBe(true);
|
||||
|
||||
expect(pointOnPolyline([1, 1], polyline)).toBe(true);
|
||||
expect(pointOnPolyline([2, 1.5], polyline)).toBe(true);
|
||||
expect(pointOnPolyline([2.5, 1], polyline)).toBe(true);
|
||||
|
||||
expect(pointOnPolyline([0, 1], polyline)).toBe(false);
|
||||
expect(pointOnPolyline([2.1, 1.5], polyline)).toBe(false);
|
||||
});
|
||||
|
||||
it("point on the line with rotation", () => {
|
||||
const truePoints = [
|
||||
[1, 0],
|
||||
[1, 2],
|
||||
[2, 2],
|
||||
[2, 1],
|
||||
[3, 1],
|
||||
] as Point[];
|
||||
|
||||
truePoints.forEach((point) => {
|
||||
const rotation = Math.random() * 360;
|
||||
const rotatedPoint = pointRotate(point, rotation);
|
||||
const rotatedPolyline: Polyline = polyline.map((line) =>
|
||||
lineRotate(line, rotation, [0, 0]),
|
||||
);
|
||||
expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(true);
|
||||
});
|
||||
|
||||
const falsePoints = [
|
||||
[0, 1],
|
||||
[2.1, 1.5],
|
||||
] as Point[];
|
||||
|
||||
falsePoints.forEach((point) => {
|
||||
const rotation = Math.random() * 360;
|
||||
const rotatedPoint = pointRotate(point, rotation);
|
||||
const rotatedPolyline: Polyline = polyline.map((line) =>
|
||||
lineRotate(line, rotation, [0, 0]),
|
||||
);
|
||||
expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("point and polygon", () => {
|
||||
const polygon: Polygon = [
|
||||
[10, 10],
|
||||
[50, 10],
|
||||
[50, 50],
|
||||
[10, 50],
|
||||
];
|
||||
|
||||
it("point on polygon", () => {
|
||||
expect(pointOnPolygon([30, 10], polygon)).toBe(true);
|
||||
expect(pointOnPolygon([50, 30], polygon)).toBe(true);
|
||||
expect(pointOnPolygon([30, 50], polygon)).toBe(true);
|
||||
expect(pointOnPolygon([10, 30], polygon)).toBe(true);
|
||||
expect(pointOnPolygon([30, 30], polygon)).toBe(false);
|
||||
expect(pointOnPolygon([30, 70], polygon)).toBe(false);
|
||||
});
|
||||
|
||||
it("point in polygon", () => {
|
||||
const polygon: Polygon = [
|
||||
[0, 0],
|
||||
[2, 0],
|
||||
[2, 2],
|
||||
[0, 2],
|
||||
];
|
||||
expect(pointInPolygon([1, 1], polygon)).toBe(true);
|
||||
expect(pointInPolygon([3, 3], polygon)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("point and curve", () => {
|
||||
const curve: Curve = [
|
||||
[1.4, 1.65],
|
||||
[1.9, 7.9],
|
||||
[5.9, 1.65],
|
||||
[6.44, 4.84],
|
||||
];
|
||||
|
||||
it("point on curve", () => {
|
||||
expect(pointOnCurve(curve[0], curve)).toBe(true);
|
||||
expect(pointOnCurve(curve[3], curve)).toBe(true);
|
||||
|
||||
expect(pointOnCurve([2, 4], curve, 0.1)).toBe(true);
|
||||
expect(pointOnCurve([4, 4.4], curve, 0.1)).toBe(true);
|
||||
expect(pointOnCurve([5.6, 3.85], curve, 0.1)).toBe(true);
|
||||
|
||||
expect(pointOnCurve([5.6, 4], curve, 0.1)).toBe(false);
|
||||
expect(pointOnCurve(curve[1], curve, 0.1)).toBe(false);
|
||||
expect(pointOnCurve(curve[2], curve, 0.1)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("point and ellipse", () => {
|
||||
const ellipse: Ellipse = {
|
||||
center: [0, 0],
|
||||
angle: 0,
|
||||
halfWidth: 2,
|
||||
halfHeight: 1,
|
||||
};
|
||||
|
||||
it("point on ellipse", () => {
|
||||
[
|
||||
[0, 1],
|
||||
[0, -1],
|
||||
[2, 0],
|
||||
[-2, 0],
|
||||
].forEach((point) => {
|
||||
expect(pointOnEllipse(point as Point, ellipse)).toBe(true);
|
||||
});
|
||||
expect(pointOnEllipse([-1.4, 0.7], ellipse, 0.1)).toBe(true);
|
||||
expect(pointOnEllipse([-1.4, 0.71], ellipse, 0.01)).toBe(true);
|
||||
|
||||
expect(pointOnEllipse([1.4, 0.7], ellipse, 0.1)).toBe(true);
|
||||
expect(pointOnEllipse([1.4, 0.71], ellipse, 0.01)).toBe(true);
|
||||
|
||||
expect(pointOnEllipse([1, -0.86], ellipse, 0.1)).toBe(true);
|
||||
expect(pointOnEllipse([1, -0.86], ellipse, 0.01)).toBe(true);
|
||||
|
||||
expect(pointOnEllipse([-1, -0.86], ellipse, 0.1)).toBe(true);
|
||||
expect(pointOnEllipse([-1, -0.86], ellipse, 0.01)).toBe(true);
|
||||
|
||||
expect(pointOnEllipse([-1, 0.8], ellipse)).toBe(false);
|
||||
expect(pointOnEllipse([1, -0.8], ellipse)).toBe(false);
|
||||
});
|
||||
|
||||
it("point in ellipse", () => {
|
||||
[
|
||||
[0, 1],
|
||||
[0, -1],
|
||||
[2, 0],
|
||||
[-2, 0],
|
||||
].forEach((point) => {
|
||||
expect(pointInEllipse(point as Point, ellipse)).toBe(true);
|
||||
});
|
||||
|
||||
expect(pointInEllipse([-1, 0.8], ellipse)).toBe(true);
|
||||
expect(pointInEllipse([1, -0.8], ellipse)).toBe(true);
|
||||
|
||||
expect(pointInEllipse([-1, 1], ellipse)).toBe(false);
|
||||
expect(pointInEllipse([-1.4, 0.8], ellipse)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("line and line", () => {
|
||||
const lineA: Line = [
|
||||
[1, 4],
|
||||
[3, 4],
|
||||
];
|
||||
const lineB: Line = [
|
||||
[2, 1],
|
||||
[2, 7],
|
||||
];
|
||||
const lineC: Line = [
|
||||
[1, 8],
|
||||
[3, 8],
|
||||
];
|
||||
const lineD: Line = [
|
||||
[1, 8],
|
||||
[3, 8],
|
||||
];
|
||||
const lineE: Line = [
|
||||
[1, 9],
|
||||
[3, 9],
|
||||
];
|
||||
const lineF: Line = [
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
];
|
||||
const lineG: Line = [
|
||||
[0, 1],
|
||||
[2, 3],
|
||||
];
|
||||
|
||||
it("intersection", () => {
|
||||
expect(lineIntersectsLine(lineA, lineB)).toBe(true);
|
||||
expect(lineIntersectsLine(lineA, lineC)).toBe(false);
|
||||
expect(lineIntersectsLine(lineB, lineC)).toBe(false);
|
||||
expect(lineIntersectsLine(lineC, lineD)).toBe(true);
|
||||
expect(lineIntersectsLine(lineE, lineD)).toBe(false);
|
||||
expect(lineIntersectsLine(lineF, lineG)).toBe(true);
|
||||
});
|
||||
});
|
70
packages/utils/tests/utils.unmocked.test.ts
Normal file
70
packages/utils/tests/utils.unmocked.test.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
import {
|
||||
decodePngMetadata,
|
||||
decodeSvgMetadata,
|
||||
} from "../../excalidraw/data/image";
|
||||
import type { ImportedDataState } from "../../excalidraw/data/types";
|
||||
import * as utils from "../dist/prod";
|
||||
import { API } from "../../excalidraw/tests/helpers/api";
|
||||
|
||||
// NOTE this test file is using the actual API, unmocked. Hence splitting it
|
||||
// from the other test file, because I couldn't figure out how to test
|
||||
// mocked and unmocked API in the same file.
|
||||
|
||||
describe("embedding scene data", () => {
|
||||
describe("exportToSvg", () => {
|
||||
it("embedding scene data shouldn't modify them", async () => {
|
||||
const rectangle = API.createElement({ type: "rectangle" });
|
||||
const ellipse = API.createElement({ type: "ellipse" });
|
||||
|
||||
const sourceElements = [rectangle, ellipse];
|
||||
|
||||
const svgNode = await utils.exportToSvg({
|
||||
elements: sourceElements,
|
||||
appState: {
|
||||
viewBackgroundColor: "#ffffff",
|
||||
gridSize: null,
|
||||
exportEmbedScene: true,
|
||||
},
|
||||
files: null,
|
||||
});
|
||||
|
||||
const svg = svgNode.outerHTML;
|
||||
|
||||
const parsedString = await decodeSvgMetadata({ svg });
|
||||
const importedData: ImportedDataState = JSON.parse(parsedString);
|
||||
|
||||
expect(sourceElements.map((x) => x.id)).toEqual(
|
||||
importedData.elements?.map((el) => el.id),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// skipped because we can't test png encoding right now
|
||||
// (canvas.toBlob not supported in jsdom)
|
||||
describe.skip("exportToBlob", () => {
|
||||
it("embedding scene data shouldn't modify them", async () => {
|
||||
const rectangle = API.createElement({ type: "rectangle" });
|
||||
const ellipse = API.createElement({ type: "ellipse" });
|
||||
|
||||
const sourceElements = [rectangle, ellipse];
|
||||
|
||||
const blob = await utils.exportToBlob({
|
||||
mimeType: "image/png",
|
||||
elements: sourceElements,
|
||||
appState: {
|
||||
viewBackgroundColor: "#ffffff",
|
||||
gridSize: null,
|
||||
exportEmbedScene: true,
|
||||
},
|
||||
files: null,
|
||||
});
|
||||
|
||||
const parsedString = await decodePngMetadata(blob);
|
||||
const importedData: ImportedDataState = JSON.parse(parsedString);
|
||||
|
||||
expect(sourceElements.map((x) => x.id)).toEqual(
|
||||
importedData.elements?.map((el) => el.id),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
262
packages/utils/tests/withinBounds.test.ts
Normal file
262
packages/utils/tests/withinBounds.test.ts
Normal file
|
@ -0,0 +1,262 @@
|
|||
import type { Bounds } from "../../excalidraw/element/bounds";
|
||||
import { API } from "../../excalidraw/tests/helpers/api";
|
||||
import {
|
||||
elementPartiallyOverlapsWithOrContainsBBox,
|
||||
elementsOverlappingBBox,
|
||||
isElementInsideBBox,
|
||||
} from "../src/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)
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue