import type { PanelExtent as Extent, PanelView, PanelPoint as Point } from "#types/panel.types"; import { PANEL_MAX_SCALE, PANEL_MIN_SCALE } from "#configuration/constants/panel.constants"; export const ORIGIN_VIEW: PanelView = { scale: 1, x: 0, y: 0 }; const HALF = 2; const clamp = function clamp(value: number, low: number, high: number): number { return Math.min(Math.max(value, low), high); }; export const extentOf = function extentOf(element: Element): Extent { const rect = element.getBoundingClientRect(); return { height: rect.height, width: rect.width }; }; export const contentExtentOf = function contentExtentOf(stage: Element, scale: number): Extent { const rect = extentOf(stage); return { height: rect.height / scale, width: rect.width / scale }; }; export const boundedView = function boundedView(view: PanelView, viewport: Extent, content: Extent): PanelView { const spanX = viewport.width - content.width * view.scale; const spanY = viewport.height - content.height * view.scale; return { scale: view.scale, x: clamp(view.x, Math.min(0, spanX), Math.max(0, spanX)), y: clamp(view.y, Math.min(0, spanY), Math.max(0, spanY)), }; }; export const zoomedView = function zoomedView(view: PanelView, factor: number, anchor: Point): PanelView { const scale = clamp(view.scale * factor, PANEL_MIN_SCALE, PANEL_MAX_SCALE); const ratio = scale / view.scale; return { scale, x: anchor.x - (anchor.x - view.x) * ratio, y: anchor.y - (anchor.y - view.y) * ratio }; }; export const fittedView = function fittedView(viewport: Extent, content: Extent, ceiling = 1): PanelView { if (content.width === 0 || content.height === 0) { return ORIGIN_VIEW; } const scale = clamp( Math.min(viewport.width / content.width, viewport.height / content.height, ceiling), PANEL_MIN_SCALE, ceiling, ); return { scale, x: (viewport.width - content.width * scale) / HALF, y: (viewport.height - content.height * scale) / HALF, }; }; export const centerOf = function centerOf(extent: Extent): Point { return { x: extent.width / HALF, y: extent.height / HALF }; }; export const distanceBetween = function distanceBetween(a: Point, b: Point): number { return Math.hypot(a.x - b.x, a.y - b.y); }; export const midpointOf = function midpointOf(a: Point, b: Point): Point { return { x: (a.x + b.x) / HALF, y: (a.y + b.y) / HALF }; };