@ue-too/board
Version:
<h1 align="center"> uē-tôo </h1> <p align="center"> pan, zoom, rotate, and more with your html canvas. </p>
305 lines (304 loc) • 12.3 kB
TypeScript
import { CameraMux, CameraMuxPanOutput, CameraMuxZoomOutput, CameraMuxRotationOutput } from "../interface";
import { Point } from "@ue-too/math";
import { PanControlStateMachine } from "./pan-control-state-machine";
import { ZoomControlStateMachine } from "./zoom-control-state-machine";
import { RotateControlStateMachine, RotateControlOutputEvent } from "./rotation-control-state-machine";
/**
* Advanced camera input multiplexer with animation support and input locking via state machines.
*
* @remarks
* This {@link CameraMux} implementation provides sophisticated input flow control using
* separate state machines for pan, zoom, and rotation. Each state machine can:
* - Block user input during camera animations
* - Manage animation playback
* - Arbitrate between user input and programmatic camera control
* - Handle transitions between different camera control states
*
* **Key features:**
* - **Animation system**: Support for smooth camera animations (pan-to, zoom-to, rotate-to)
* - **Input locking**: Automatically block user input during animations
* - **State-based control**: Each camera operation (pan/zoom/rotate) has its own state machine
* - **Flexible transitions**: Initiate transitions to interrupt or chain animations
*
* **Architecture:**
* - Three independent state machines: {@link PanControlStateMachine}, {@link ZoomControlStateMachine}, {@link RotateControlStateMachine}
* - Each state machine decides whether to allow or block input based on current state
* - State machines receive events and produce output events for camera operations
*
* **When to use:**
* - Applications requiring smooth camera animations (e.g., "focus on object", "zoom to region")
* - UI where user input should be blocked during programmatic camera movements
* - Games or interactive experiences with scripted camera sequences
*
* **Alternatives:**
* - Use {@link Relay} for simple passthrough without animation support
* - Implement custom {@link CameraMux} for different state management approaches
*
* @example
* ```typescript
* const camera = new DefaultBoardCamera();
* const mux = createCameraMuxWithAnimationAndLock(camera);
*
* // Start a pan animation - user input will be blocked
* mux.notifyPanToAnimationInput({ x: 1000, y: 500 });
*
* // User tries to pan during animation - will be blocked
* const result = mux.notifyPanInput({ x: 50, y: 30 });
* // result.allowPassThrough = false (blocked during animation)
*
* // After animation completes, user input allowed again
* ```
*
* @category Input Flow Control
* @see {@link CameraMux} for the interface definition
* @see {@link Relay} for simpler passthrough implementation
* @see {@link createCameraMuxWithAnimationAndLock} for factory function
*/
export declare class CameraMuxWithAnimationAndLock implements CameraMux {
private _panStateMachine;
private _zoomStateMachine;
private _rotateStateMachine;
/**
* Creates a new camera mux with animation and locking capabilities.
*
* @param panStateMachine - State machine controlling pan operations and animations
* @param zoomStateMachine - State machine controlling zoom operations and animations
* @param rotateStateMachine - State machine controlling rotation operations and animations
*
* @remarks
* Typically created via factory functions like {@link createCameraMuxWithAnimationAndLock}
* rather than direct instantiation.
*/
constructor(panStateMachine: PanControlStateMachine, zoomStateMachine: ZoomControlStateMachine, rotateStateMachine: RotateControlStateMachine);
/**
* Initiates a pan animation to a target position.
*
* @param target - Target position in world coordinates
* @returns Pan output indicating whether animation was initiated
*
* @remarks
* This method starts a camera pan animation to the specified world position.
* The state machine handles:
* - Starting the animation
* - Blocking user input during animation
* - Producing incremental pan deltas each frame
*
* The animation continues until the camera reaches the target or is interrupted.
*
* @example
* ```typescript
* // Animate camera to world position
* mux.notifyPanToAnimationInput({ x: 1000, y: 500 });
* ```
*/
notifyPanToAnimationInput(target: Point): CameraMuxPanOutput;
/**
* Processes user pan input (implements {@link CameraMux}).
*
* @param delta - Pan delta in viewport coordinates
* @returns Output indicating whether pan is allowed
*
* @remarks
* This method is called when the user attempts to pan the camera (e.g., mouse drag).
* The pan state machine determines whether to allow the input based on current state:
* - **Allowed**: When in idle state or user control state
* - **Blocked**: When camera animation is playing
*
* @example
* ```typescript
* // User drags mouse
* const result = mux.notifyPanInput({ x: 50, y: 30 });
* if (result.allowPassThrough) {
* // Apply pan to camera
* cameraRig.panByViewPort(result.delta);
* }
* ```
*/
notifyPanInput(delta: Point): CameraMuxPanOutput;
/**
* Processes user zoom input (implements {@link CameraMux}).
*
* @param delta - Zoom delta (change in zoom level)
* @param at - Anchor point in viewport coordinates
* @returns Output indicating whether zoom is allowed
*
* @remarks
* This method is called when the user attempts to zoom (e.g., mouse wheel).
* The zoom state machine determines whether to allow the input based on current state:
* - **Allowed**: When in idle state or user control state
* - **Blocked**: When zoom animation is playing
*
* @example
* ```typescript
* // User scrolls mouse wheel
* const result = mux.notifyZoomInput(0.1, mousePosition);
* if (result.allowPassThrough) {
* // Apply zoom to camera
* cameraRig.zoomByAt(result.delta, result.anchorPoint);
* }
* ```
*/
notifyZoomInput(delta: number, at: Point): CameraMuxZoomOutput;
/**
* Processes user rotation input (rotate-by variant).
*
* @param delta - Rotation delta in radians
* @returns Output from rotation state machine
*
* @remarks
* Delegates to the rotation state machine's rotate-by handler.
* The state machine determines whether to allow rotation based on current state.
*/
notifyRotateByInput(delta: number): import("@ue-too/being").EventResult<import("./rotation-control-state-machine").RotateControlStates, RotateControlOutputEvent>;
/**
* Initiates a rotation animation to a target angle.
*
* @param target - Target rotation angle in radians
* @returns Output from rotation state machine
*
* @remarks
* Starts a camera rotation animation to the specified angle.
* User input will be blocked during the animation.
*/
notifyRotateToAnimationInput(target: number): import("@ue-too/being").EventResult<import("./rotation-control-state-machine").RotateControlStates, RotateControlOutputEvent>;
/**
* Initiates a zoom animation to a target level at a viewport position.
*
* @param targetZoom - Target zoom level
* @param at - Anchor point in viewport coordinates (defaults to origin)
*
* @remarks
* Starts a zoom animation that zooms to the specified level while keeping
* the anchor point stationary (zoom-to-cursor behavior).
* User input will be blocked during the animation.
*/
notifyZoomInputAnimation(targetZoom: number, at?: Point): void;
/**
* Initiates a zoom animation to a target level at a world position.
*
* @param targetZoom - Target zoom level
* @param at - Anchor point in world coordinates (defaults to origin)
*
* @remarks
* Similar to {@link notifyZoomInputAnimation} but accepts world-space coordinates
* for the anchor point instead of viewport coordinates.
*/
notifyZoomInputAnimationWorld(targetZoom: number, at?: Point): void;
/**
* Processes user rotation input (implements {@link CameraMux}).
*
* @param delta - Rotation delta in radians
* @returns Output indicating whether rotation is allowed
*
* @remarks
* This method is called when the user attempts to rotate the camera.
* The rotation state machine determines whether to allow the input based on current state:
* - **Allowed**: When in idle state or user control state
* - **Blocked**: When rotation animation is playing
*
* @example
* ```typescript
* // User rotates camera
* const result = mux.notifyRotationInput(0.1);
* if (result.allowPassThrough) {
* cameraRig.rotateBy(result.delta);
* }
* ```
*/
notifyRotationInput(delta: number): CameraMuxRotationOutput;
/**
* Initiates a transition in the pan state machine.
*
* @remarks
* This method forces the pan state machine to transition to its next state.
* Can be used to interrupt animations or force state changes.
*/
initatePanTransition(): void;
/**
* Initiates a transition in the zoom state machine.
*
* @remarks
* This method forces the zoom state machine to transition to its next state.
* Can be used to interrupt animations or force state changes.
*/
initateZoomTransition(): void;
/**
* Initiates a transition in the rotation state machine.
*
* @remarks
* This method forces the rotation state machine to transition to its next state.
* Can be used to interrupt animations or force state changes.
*/
initateRotateTransition(): void;
/**
* Gets the rotation state machine.
*
* @returns The rotation state machine instance
*
* @remarks
* Provides direct access to the rotation state machine for advanced control
* or state inspection.
*/
get rotateStateMachine(): RotateControlStateMachine;
/**
* Gets the pan state machine.
*
* @returns The pan state machine instance
*
* @remarks
* Provides direct access to the pan state machine for advanced control
* or state inspection.
*/
get panStateMachine(): PanControlStateMachine;
/**
* Gets the zoom state machine.
*
* @returns The zoom state machine instance
*
* @remarks
* Provides direct access to the zoom state machine for advanced control
* or state inspection.
*/
get zoomStateMachine(): ZoomControlStateMachine;
}
/**
* Creates a camera mux with animation and locking capabilities from a camera instance.
*
* @param camera - Observable camera to control
* @returns Configured camera mux with animation support
*
* @remarks
* This factory function creates a complete camera input flow control system with:
* 1. A default {@link CameraRig} wrapping the provided camera
* 2. Three state machines (pan, zoom, rotation) for animation control
* 3. A {@link CameraMuxWithAnimationAndLock} coordinating the state machines
*
* **What you get:**
* - Smooth camera animations (pan-to, zoom-to, rotate-to)
* - Automatic input blocking during animations
* - State-based input arbitration
* - All with sensible default configurations
*
* **Use this when:**
* - You have a camera and want animation support out-of-the-box
* - You don't need custom camera rig configuration
* - You want the simplest setup for animated camera control
*
* @example
* ```typescript
* const camera = new DefaultBoardCamera(1920, 1080);
* const mux = createCameraMuxWithAnimationAndLock(camera);
*
* // Start a pan animation
* mux.notifyPanToAnimationInput({ x: 1000, y: 500 });
*
* // User input is blocked during animation
* const result = mux.notifyPanInput({ x: 50, y: 30 });
* console.log(result.allowPassThrough); // false during animation
* ```
*
* @category Input Flow Control
* @see {@link CameraMuxWithAnimationAndLock} for the implementation
* @see {@link createCameraMuxWithAnimationAndLockWithCameraRig} for custom rig version
*/
export declare function createCameraMuxWithAnimationAndLock(): CameraMux;