UNPKG

@ue-too/board

Version:

<h1 align="center"> uē-tôo </h1> <p align="center"> pan, zoom, rotate, and more with your html canvas. </p>

373 lines (372 loc) 14.3 kB
import { Point } from "@ue-too/math"; import { TransformationMatrix } from "./matrix"; /** * Converts a viewport point to world space with respect to a hypothetical camera position. * "WRT" = "With Respect To" - calculates where a viewport point would be in world space * if the camera were at the target position. * * @param targetPosition - Hypothetical camera position in world coordinates * @param interestPoint - Point in canvas coordinates (origin at bottom-left) * @param viewPortWidth - Viewport width in CSS pixels * @param viewPortHeight - Viewport height in CSS pixels * @param cameraZoomLevel - Zoom level to apply * @param cameraRotation - Rotation to apply in radians * @returns World space coordinates of the interest point * * @remarks * This is useful for "what-if" calculations, such as: * - Predicting where a viewport corner would land if camera moves to a position * - Checking if moving to a position would show certain world objects * * The interest point uses canvas coordinates (bottom-left origin), not viewport coordinates (center origin). * * @example * ```typescript * // Where would the top-left viewport corner be in world space * // if camera moved to (100, 100)? * const worldCorner = convert2WorldSpaceWRT( * { x: 100, y: 100 }, // target camera position * { x: 0, y: 1080 }, // top-left in canvas coords * 1920, 1080, // viewport size * 1.0, // zoom * 0 // rotation * ); * ``` * * @category Camera */ export declare function convert2WorldSpaceWRT(targetPosition: Point, interestPoint: Point, viewPortWidth: number, viewPortHeight: number, cameraZoomLevel: number, cameraRotation: number): Point; /** * Converts a canvas point to world space using current camera state. * * @param point - Point in canvas coordinates (origin at bottom-left) * @param viewPortWidth - Viewport width in CSS pixels * @param viewPortHeight - Viewport height in CSS pixels * @param cameraPosition - Current camera position in world coordinates * @param cameraZoomLevel - Current camera zoom level * @param cameraRotation - Current camera rotation in radians * @returns World space coordinates of the point * * @remarks * Input coordinates use canvas space with origin at bottom-left. * This is useful when working with canvas element coordinates directly. * * For points already in viewport space (origin at center), use * {@link convert2WorldSpaceAnchorAtCenter} instead. * * @example * ```typescript * // Convert bottom-left corner of canvas to world coords * const worldPos = convert2WorldSpace( * { x: 0, y: 0 }, * 1920, 1080, * { x: 100, y: 200 }, // camera position * 1.5, // zoom * 0 // rotation * ); * ``` * * @category Camera */ export declare function convert2WorldSpace(point: Point, viewPortWidth: number, viewPortHeight: number, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Converts a viewport point (center-anchored) to world space. * This is the most commonly used viewport-to-world conversion function. * * @param point - Point in viewport coordinates (origin at viewport center) * @param cameraPosition - Camera position in world coordinates * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns World space coordinates of the point * * @remarks * Viewport coordinates have the origin at the center of the viewport, with: * - Positive x to the right * - Positive y upward * - Point (0, 0) is the center of the viewport * * This is the standard coordinate system for camera operations. * * @example * ```typescript * // Convert viewport center (0,0) to world space * const worldCenter = convert2WorldSpaceAnchorAtCenter( * { x: 0, y: 0 }, * { x: 500, y: 300 }, // camera at world (500, 300) * 1.0, * 0 * ); * // worldCenter will be { x: 500, y: 300 } * * // Convert point 100 pixels right of center * const rightPoint = convert2WorldSpaceAnchorAtCenter( * { x: 100, y: 0 }, * { x: 500, y: 300 }, * 2.0, // 2x zoom * 0 * ); * // At 2x zoom, 100 viewport pixels = 50 world units * // Result: { x: 550, y: 300 } * ``` * * @category Camera */ export declare function convert2WorldSpaceAnchorAtCenter(point: Point, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Converts a world point to viewport space (center-anchored). * Inverse of {@link convert2WorldSpaceAnchorAtCenter}. * * @param point - Point in world coordinates * @param cameraPosition - Camera position in world coordinates * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns Viewport coordinates (origin at center, in CSS pixels) * * @remarks * Use this to find where a world object appears on screen. * Result is in viewport space with origin at center, useful for: * - Positioning UI elements over world objects * - Checking if objects are on screen * - Converting click positions * * @example * ```typescript * // Where does world point (600, 300) appear in viewport? * const viewportPos = convert2ViewPortSpaceAnchorAtCenter( * { x: 600, y: 300 }, // world position * { x: 500, y: 300 }, // camera position * 1.0, * 0 * ); * // Result: { x: 100, y: 0 } (100 pixels right of center) * * // Position a DOM element at this world object * element.style.left = `${viewportPos.x + canvas.width/2}px`; * element.style.top = `${-viewportPos.y + canvas.height/2}px`; * ``` * * @category Camera */ export declare function convert2ViewPortSpaceAnchorAtCenter(point: Point, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Converts a world point to canvas coordinates (bottom-left origin). * * @param point - Point in world coordinates * @param viewPortWidth - Viewport width in CSS pixels * @param viewPortHeight - Viewport height in CSS pixels * @param cameraPosition - Camera position in world coordinates * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns Canvas coordinates (origin at bottom-left, in CSS pixels) * * @remarks * "Invert" in the function name refers to inverting the forward transformation * (world → viewport → canvas). The result uses canvas coordinates where: * - (0, 0) is at the bottom-left corner * - x increases to the right * - y increases upward * * @example * ```typescript * const canvasPos = invertFromWorldSpace( * { x: 500, y: 300 }, // world position * 1920, 1080, * { x: 500, y: 300 }, // camera at same position * 1.0, * 0 * ); * // Result: { x: 960, y: 540 } (center of 1920x1080 canvas) * ``` * * @category Camera */ export declare function invertFromWorldSpace(point: Point, viewPortWidth: number, viewPortHeight: number, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Checks if a world point is currently visible in the viewport. * * @param point - Point in world coordinates * @param viewPortWidth - Viewport width in CSS pixels * @param viewPortHeight - Viewport height in CSS pixels * @param cameraPosition - Camera position in world coordinates * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns True if point is visible in viewport, false otherwise * * @remarks * A point is visible if it falls within the rectangular viewport bounds. * This uses canvas coordinates for the visibility check (0 to width/height). * * @example * ```typescript * const isVisible = pointIsInViewPort( * { x: 550, y: 300 }, // world point * 1920, 1080, * { x: 500, y: 300 }, // camera position * 1.0, * 0 * ); * // Returns true if point is within viewport bounds * ``` * * @category Camera */ export declare function pointIsInViewPort(point: Point, viewPortWidth: number, viewPortHeight: number, cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): boolean; /** * Converts a displacement vector from viewport space to world space. * Use this for converting movement deltas, not absolute positions. * * @param delta - Displacement vector in viewport space (CSS pixels) * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns Displacement vector in world coordinates * * @remarks * This transforms a *relative* displacement, not an absolute point. * The conversion accounts for: * - Rotation: Delta is rotated by camera rotation * - Zoom: Delta is scaled by 1/zoom (viewport pixels → world units) * * Note: Camera position is NOT needed for delta transformations. * * @example * ```typescript * // User dragged 100 pixels to the right in viewport * const viewportDelta = { x: 100, y: 0 }; * const worldDelta = convertDeltaInViewPortToWorldSpace( * viewportDelta, * 2.0, // 2x zoom * 0 // no rotation * ); * // Result: { x: 50, y: 0 } (100 viewport pixels = 50 world units at 2x zoom) * ``` * * @category Camera */ export declare function convertDeltaInViewPortToWorldSpace(delta: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Converts a displacement vector from world space to viewport space. * Use this for converting movement deltas, not absolute positions. * Inverse of {@link convertDeltaInViewPortToWorldSpace}. * * @param delta - Displacement vector in world coordinates * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns Displacement vector in viewport space (CSS pixels) * * @remarks * This transforms a *relative* displacement, not an absolute point. * The conversion accounts for: * - Rotation: Delta is rotated by -camera rotation * - Zoom: Delta is scaled by zoom (world units → viewport pixels) * * @example * ```typescript * // Object moved 50 units right in world space * const worldDelta = { x: 50, y: 0 }; * const viewportDelta = convertDeltaInWorldToViewPortSpace( * worldDelta, * 2.0, // 2x zoom * 0 // no rotation * ); * // Result: { x: 100, y: 0 } (50 world units = 100 viewport pixels at 2x zoom) * ``` * * @category Camera */ export declare function convertDeltaInWorldToViewPortSpace(delta: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Calculates the camera position needed to place a world point at a specific viewport location. * Useful for implementing "zoom to point" or "focus on object" features. * * @param pointInWorld - The world point to focus on * @param toPointInViewPort - Where in the viewport this point should appear (origin at center) * @param cameraZoomLevel - Target zoom level * @param cameraRotation - Target rotation in radians * @returns Camera position that achieves the desired framing * * @remarks * This is particularly useful for: * - Zoom-to-cursor: Make clicked point stay under cursor while zooming * - Pan-and-zoom: Smoothly navigate to show a specific object * - Focus features: Center camera on a world object * * The viewport point is in viewport coordinates (center origin). * To center on a world point, use toPointInViewPort = {x: 0, y: 0}. * * @example * ```typescript * // Center camera on world point (1000, 500) * const newCameraPos = cameraPositionToGet( * { x: 1000, y: 500 }, // world point to focus on * { x: 0, y: 0 }, // center of viewport * 2.0, // zoom level * 0 // rotation * ); * camera.setPosition(newCameraPos); * * // Zoom to cursor position * // Keep world point under cursor at (viewportX, viewportY) * const cursorViewport = { * x: mouseX - canvas.width/2, * y: mouseY - canvas.height/2 * }; * const worldAtCursor = camera.convertFromViewPort2WorldSpace(cursorViewport); * const newPos = cameraPositionToGet(worldAtCursor, cursorViewport, newZoom, rotation); * camera.setPosition(newPos); * camera.setZoomLevel(newZoom); * ``` * * @category Camera */ export declare function cameraPositionToGet(pointInWorld: Point, toPointInViewPort: Point, cameraZoomLevel: number, cameraRotation: number): Point; /** * Creates a transformation matrix from camera parameters. * Combines position, zoom, and rotation into a single transform. * * @param cameraPosition - Camera position in world coordinates * @param cameraZoomLevel - Camera zoom level * @param cameraRotation - Camera rotation in radians * @returns Transformation matrix for viewport-to-world conversion * * @remarks * The resulting matrix can be used with {@link convert2WorldSpaceWithTransformationMatrix} * for efficient batch transformations when camera state doesn't change. * * Matrix composition order: Translation → Rotation → Scale(1/zoom) * * @category Camera */ export declare function transformationMatrixFromCamera(cameraPosition: Point, cameraZoomLevel: number, cameraRotation: number): TransformationMatrix; /** * Transforms a viewport point to world space using a precomputed transformation matrix. * Faster than repeated function calls when transforming many points with the same camera state. * * @param point - Point in viewport coordinates (origin at center) * @param transformationMatrix - Precomputed transformation matrix from {@link transformationMatrixFromCamera} * @returns World space coordinates of the point * * @remarks * Use this for batch transformations when the camera state is constant: * 1. Create matrix once with {@link transformationMatrixFromCamera} * 2. Transform many points with this function * * This avoids recalculating sin/cos and matrix operations for each point. * * @example * ```typescript * // Transform many points efficiently * const matrix = transformationMatrixFromCamera( * { x: 100, y: 200 }, * 1.5, * Math.PI / 4 * ); * * const worldPoints = viewportPoints.map(vp => * convert2WorldSpaceWithTransformationMatrix(vp, matrix) * ); * ``` * * @category Camera * @see {@link transformationMatrixFromCamera} to create the matrix */ export declare function convert2WorldSpaceWithTransformationMatrix(point: Point, transformationMatrix: TransformationMatrix): Point;