import { useMemo } from "react"; import type { ViewportConfig, ViewportTransform } from "./types"; const DEFAULT_WIDTH = 680; const DEFAULT_HEIGHT = 480; const DEFAULT_PADDING = { top: 36, right: 44, bottom: 56, left: 64, }; export function createViewport(config: ViewportConfig): ViewportTransform { const width = config.width ?? DEFAULT_WIDTH; const height = config.height ?? DEFAULT_HEIGHT; const padding = { top: config.padding?.top ?? DEFAULT_PADDING.top, right: config.padding?.right ?? DEFAULT_PADDING.right, bottom: config.padding?.bottom ?? DEFAULT_PADDING.bottom, left: config.padding?.left ?? DEFAULT_PADDING.left, }; const plotWidth = Math.max(1, width - padding.left - padding.right); const plotHeight = Math.max(1, height - padding.top - padding.bottom); const maxX = config.maxX > 0 ? config.maxX : 1; const maxY = config.maxY > 0 ? config.maxY : 1; const toScreenX = (x: number): number => { return padding.left + (x / maxX) * plotWidth; }; const toScreenY = (y: number): number => { return height - padding.bottom - (y / maxY) * plotHeight; }; const toModelX = (sx: number): number => { return ((sx - padding.left) / plotWidth) * maxX; }; const toModelY = (sy: number): number => { return ((height - padding.bottom - sy) / plotHeight) * maxY; }; return { width, height, padding, plotWidth, plotHeight, maxX, maxY, toScreenX, toScreenY, toModelX, toModelY, }; } export function useViewport(config: ViewportConfig): ViewportTransform { const maxX = config.maxX; const maxY = config.maxY; const width = config.width; const height = config.height; const pTop = config.padding?.top; const pRight = config.padding?.right; const pBottom = config.padding?.bottom; const pLeft = config.padding?.left; return useMemo(() => { return createViewport(config); }, [maxX, maxY, width, height, pTop, pRight, pBottom, pLeft, config]); }