This commit is contained in:
2026-07-12 21:26:08 +08:00
commit 9dd41afd48
502 changed files with 129901 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
GRAPH_MINIMAP_VIEWBOX,
GRAPH_WORLD_SIZE,
layerDeltaToWorldDelta,
layerPointToWorldPoint,
minimapPointToWorldPoint,
rootClientPointToScreenPoint,
screenPointToWorldPoint,
sideExitWorldAnchor,
svgPointToWorldPoint,
visibleWorldRectForViewport,
visibleWorldRectToMinimapRect,
worldDeltaToLayerDelta,
worldPointDeltaToLayerDelta,
worldPointToCssPercentPoint,
worldPointToLayerPoint,
worldPointToMinimapPoint,
worldPointToScreenPoint,
worldPointToSvgPoint
} from "../src/render";
import type { RendererViewport, RendererViewportSize } from "../src/render";
const VIEWPORT_SIZE: RendererViewportSize = { width: 1200, height: 816 };
function assertNear(actual: number, expected: number, message?: string): void {
assert.ok(Math.abs(actual - expected) < 0.01, `${message ?? "number"}: expected ${expected}, got ${actual}`);
}
function assertPointNear(actual: { x: number; y: number }, expected: { x: number; y: number }): void {
assertNear(actual.x, expected.x, "x");
assertNear(actual.y, expected.y, "y");
}
describe("graph geometry projection", () => {
for (const scale of [0.5, 1, 2.25]) {
it(`round trips world and screen points at scale ${scale}`, () => {
const viewport: RendererViewport = { x: -180.5, y: 74.25, scale };
const worldPoint = { x: 812.34, y: 123.45 };
const screenPoint = worldPointToScreenPoint(worldPoint, viewport, VIEWPORT_SIZE);
const roundTrip = screenPointToWorldPoint(screenPoint, viewport, VIEWPORT_SIZE);
assertPointNear(roundTrip, worldPoint);
});
}
it("projects through viewport pan and zoom", () => {
const viewport: RendererViewport = { x: 120, y: -80, scale: 1.75 };
const worldPoint = { x: 500, y: 340 };
assertPointNear(
worldPointToScreenPoint(worldPoint, viewport, { width: 1000, height: 680 }),
{ x: 995, y: 515 }
);
});
it("converts root client point to graph screen point", () => {
const screenPoint = rootClientPointToScreenPoint(
{ x: 940, y: 520 },
{ left: 270, top: 88, width: 1000, height: 680 }
);
assert.deepEqual(screenPoint, { x: 670, y: 432 });
});
it("does not silently clamp screen to world projection outside the visible root", () => {
const viewport: RendererViewport = { x: -200, y: -100, scale: 2 };
const worldPoint = screenPointToWorldPoint({ x: -240, y: 1500 }, viewport, { width: 1000, height: 680 });
assert.ok(worldPoint.x < 0, `x should remain outside world for drag handling, got ${worldPoint.x}`);
assert.ok(worldPoint.y > GRAPH_WORLD_SIZE.height, `y should remain outside world for drag handling, got ${worldPoint.y}`);
});
it("round trips world and layer points after drawer-style viewport resize", () => {
const worldPoint = { x: 760, y: 340 };
const beforeLayer = worldPointToLayerPoint(worldPoint, { width: 1170, height: 856 });
const afterLayer = worldPointToLayerPoint(worldPoint, { width: 750, height: 856 });
assert.notEqual(beforeLayer.x, afterLayer.x);
assertPointNear(layerPointToWorldPoint(afterLayer, { width: 750, height: 856 }), worldPoint);
});
it("converts deltas without treating them as absolute points", () => {
const worldDelta = { x: 50, y: -34 };
const layerDelta = worldDeltaToLayerDelta(worldDelta, VIEWPORT_SIZE);
const roundTrip = layerDeltaToWorldDelta(layerDelta, VIEWPORT_SIZE);
assertPointNear(roundTrip, worldDelta);
assertPointNear(
worldPointDeltaToLayerDelta({ x: 220, y: 180 }, { x: 270, y: 146 }, VIEWPORT_SIZE),
layerDelta
);
});
it("maps out-of-world positions to css percentages without clamping them", () => {
const cssPoint = worldPointToCssPercentPoint({ x: 1240, y: 816 });
assertPointNear(cssPoint, { x: 124, y: 120 });
});
it("maps expanded world bounds without clamping or drifting coordinates", () => {
const bounds = { minX: -200, minY: 0, maxX: 1320, maxY: 896, width: 1520, height: 896 };
const worldPoint = { x: 1240, y: 816 };
const layerPoint = worldPointToLayerPoint(worldPoint, VIEWPORT_SIZE, bounds);
const cssPoint = worldPointToCssPercentPoint(worldPoint, bounds);
const minimapPoint = worldPointToMinimapPoint(worldPoint, undefined, bounds);
assertPointNear(layerPointToWorldPoint(layerPoint, VIEWPORT_SIZE, bounds), worldPoint);
assertPointNear(cssPoint, { x: 94.737, y: 91.071 });
assertPointNear(minimapPointToWorldPoint(minimapPoint, undefined, bounds), worldPoint);
});
it("keeps svg point naming explicit even while svg and world share the same domain", () => {
const worldPoint = { x: 220.5, y: 410.25 };
const svgPoint = worldPointToSvgPoint(worldPoint);
assert.deepEqual(svgPoint, worldPoint);
assert.deepEqual(svgPointToWorldPoint(svgPoint), worldPoint);
});
it("maps world and viewport rectangles to minimap coordinates", () => {
const minimapPoint = worldPointToMinimapPoint({ x: 500, y: 340 });
const worldPoint = minimapPointToWorldPoint(minimapPoint);
const viewportRect = visibleWorldRectForViewport(
{ x: -250, y: -170, scale: 2 },
{ width: 1000, height: 680 }
);
const minimapRect = visibleWorldRectToMinimapRect(viewportRect);
assertPointNear(minimapPoint, {
x: GRAPH_MINIMAP_VIEWBOX.x + GRAPH_MINIMAP_VIEWBOX.width / 2,
y: GRAPH_MINIMAP_VIEWBOX.y + GRAPH_MINIMAP_VIEWBOX.height / 2
});
assertPointNear(worldPoint, { x: 500, y: 340 });
assert.ok(minimapRect.x > GRAPH_MINIMAP_VIEWBOX.x);
assert.ok(minimapRect.y > GRAPH_MINIMAP_VIEWBOX.y);
assert.ok(minimapRect.width > 0);
assert.ok(minimapRect.height > 0);
});
it("derives side anchors for isolated diff motion outside the default world", () => {
assert.deepEqual(sideExitWorldAnchor({ x: 120, y: 20 }), { x: -80, y: 80 });
assert.deepEqual(sideExitWorldAnchor({ x: 900, y: 900 }), { x: 1080, y: 600 });
});
});