42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import type { CanvasNode, Viewport } from "@/types/canvas";
|
|
|
|
export function getCanvasFitViewport(
|
|
nodes: Pick<CanvasNode, "position" | "size">[],
|
|
container: { width: number; height: number },
|
|
occlusionRight = 0
|
|
): Viewport | null {
|
|
const visibleWidth = container.width - Math.max(0, occlusionRight);
|
|
if (visibleWidth <= 0 || container.height <= 0) return null;
|
|
const validNodes = nodes.filter(
|
|
(node) =>
|
|
[
|
|
node.position.x,
|
|
node.position.y,
|
|
node.size.width,
|
|
node.size.height,
|
|
].every(Number.isFinite) &&
|
|
node.size.width > 0 &&
|
|
node.size.height > 0
|
|
);
|
|
if (!validNodes.length) return null;
|
|
const minX = Math.min(...validNodes.map((node) => node.position.x));
|
|
const minY = Math.min(...validNodes.map((node) => node.position.y));
|
|
const maxX = Math.max(
|
|
...validNodes.map((node) => node.position.x + node.size.width)
|
|
);
|
|
const maxY = Math.max(
|
|
...validNodes.map((node) => node.position.y + node.size.height)
|
|
);
|
|
const padding = Math.min(80, visibleWidth / 4, container.height / 4);
|
|
const zoom = Math.min(
|
|
4,
|
|
visibleWidth / (maxX - minX + 2 * padding),
|
|
container.height / (maxY - minY + 2 * padding)
|
|
);
|
|
return {
|
|
x: visibleWidth / 2 - ((minX + maxX) / 2) * zoom,
|
|
y: container.height / 2 - ((minY + maxY) / 2) * zoom,
|
|
zoom,
|
|
};
|
|
}
|