@ue-too/board
Version:
<h1 align="center"> uē-tôo </h1> <p align="center"> pan, zoom, rotate, and more with your html canvas. </p>
263 lines (262 loc) • 8.3 kB
TypeScript
import { Point } from "@ue-too/math";
import { SubscriptionOptions } from "../utils/observable";
/**
* Payload for camera pan (position change) events.
*
* @property diff - The displacement vector from previous to new position
*
* @category Camera
*/
export type CameraPanEventPayload = {
/** Movement delta in world coordinates */
diff: Point;
};
/**
* Payload for camera zoom (scale change) events.
*
* @property deltaZoomAmount - Change in zoom level (positive = zoom in, negative = zoom out)
*
* @category Camera
*/
export type CameraZoomEventPayload = {
/** Change in zoom level from previous value */
deltaZoomAmount: number;
};
/**
* Payload for camera rotation events.
*
* @property deltaRotation - Change in rotation angle in radians
*
* @category Camera
*/
export type CameraRotateEventPayload = {
/** Change in rotation from previous value, in radians */
deltaRotation: number;
};
/**
* Mapping of camera event names to their payload types.
* Used for type-safe event subscription.
*
* @category Camera
*/
export type CameraEventMap = {
/** Position change event */
"pan": CameraPanEventPayload;
/** Zoom level change event */
"zoom": CameraZoomEventPayload;
/** Rotation change event */
"rotate": CameraRotateEventPayload;
/** Any camera change event (union of pan, zoom, rotate) */
"all": AllCameraEventPayload;
};
/**
* Rotation event with discriminated type field for 'all' event handling.
* Includes type discriminator and rotation payload.
*
* @category Camera
*/
export type CameraRotateEvent = {
/** Event type discriminator */
type: "rotate";
} & CameraRotateEventPayload;
/**
* Pan event with discriminated type field for 'all' event handling.
* Includes type discriminator and pan payload.
*
* @category Camera
*/
export type CameraPanEvent = {
/** Event type discriminator */
type: "pan";
} & CameraPanEventPayload;
/**
* Zoom event with discriminated type field for 'all' event handling.
* Includes type discriminator and zoom payload.
*
* @category Camera
*/
export type CameraZoomEvent = {
/** Event type discriminator */
type: "zoom";
} & CameraZoomEventPayload;
/**
* Snapshot of camera state at the time an event occurs.
* Passed to all event callbacks alongside the event payload.
*
* @category Camera
*/
export type CameraState = {
/** Camera position in world coordinates */
position: Point;
/** Current zoom level */
zoomLevel: number;
/** Current rotation in radians */
rotation: number;
};
/**
* Union type of all camera event payloads with type discriminators.
* Used for the 'all' event which fires for any camera change.
*
* @category Camera
*/
export type AllCameraEventPayload = CameraRotateEvent | CameraPanEvent | CameraZoomEvent;
/**
* Generic callback function type for camera events.
*
* @typeParam K - The event type key from CameraEventMap
* @param event - The event payload specific to this event type
* @param cameraState - Current camera state snapshot at the time of the event
*
* @category Camera
*/
export type Callback<K extends keyof CameraEventMap> = (event: CameraEventMap[K], cameraState: CameraState) => void;
/**
* Callback function type specifically for the 'all' camera event.
* Receives a discriminated union of all camera events.
*
* @category Camera
*/
export type ConslidateCallback = (payload: AllCameraEventPayload, cameraState: CameraState) => void;
/**
* Function returned by event subscriptions that unsubscribes the callback when called.
*
* @category Camera
*/
export type UnSubscribe = () => void;
/**
* Callback type for pan (position change) events.
*
* @category Camera
*/
export type PanObserver = Callback<"pan">;
/**
* Callback type for zoom (scale change) events.
*
* @category Camera
*/
export type ZoomObserver = Callback<"zoom">;
/**
* Callback type for rotation events.
*
* @category Camera
*/
export type RotateObserver = Callback<"rotate">;
/**
* Callback type for the 'all' event that fires on any camera change.
*
* @category Camera
*/
export type AllObserver = Callback<"all">;
/**
* Event publisher for camera state changes using the Observable pattern.
* Manages subscriptions and notifications for pan, zoom, and rotate events.
*
* @remarks
* This class is used internally by {@link DefaultBoardCamera} to implement the event system.
* You typically don't instantiate this directly unless building custom camera implementations.
*
* Each specific event (pan, zoom, rotate) also triggers the 'all' event, allowing
* listeners to subscribe to any camera change with a single handler.
*
* @example
* ```typescript
* const publisher = new CameraUpdatePublisher();
*
* // Subscribe to pan events
* publisher.on('pan', (event, state) => {
* console.log('Camera panned:', event.diff);
* });
*
* // Notify subscribers of a pan event
* publisher.notifyPan(
* { diff: { x: 10, y: 20 } },
* { position: { x: 100, y: 200 }, zoomLevel: 1, rotation: 0 }
* );
* ```
*
* @category Camera
* @see {@link DefaultBoardCamera} for the primary consumer of this class
*/
export declare class CameraUpdatePublisher {
private pan;
private zoom;
private rotate;
private all;
/**
* Creates a new camera event publisher with async observables for each event type.
*/
constructor();
/**
* Notifies all pan event subscribers.
* Also triggers the 'all' event with type discrimination.
*
* @param event - Pan event payload containing position delta
* @param cameraState - Current camera state snapshot
*/
notifyPan(event: CameraEventMap["pan"], cameraState: CameraState): void;
/**
* Notifies all zoom event subscribers.
* Also triggers the 'all' event with type discrimination.
*
* @param event - Zoom event payload containing zoom delta
* @param cameraState - Current camera state snapshot
*/
notifyZoom(event: CameraEventMap["zoom"], cameraState: CameraState): void;
/**
* Notifies all rotation event subscribers.
* Also triggers the 'all' event with type discrimination.
*
* @param event - Rotation event payload containing rotation delta
* @param cameraState - Current camera state snapshot
*/
notifyRotate(event: CameraEventMap["rotate"], cameraState: CameraState): void;
/**
* Subscribes to camera events with type-safe callbacks and optional AbortController support.
*
* @typeParam K - The event type key from CameraEventMap
* @param eventName - Event type to subscribe to ('pan', 'zoom', 'rotate', or 'all')
* @param callback - Function called when the event occurs
* @param options - Optional subscription options including AbortController signal
* @returns Function that unsubscribes this callback when called
*
* @throws Error if an invalid event name is provided
*
* @remarks
* Use the AbortController pattern for managing multiple subscriptions:
*
* @example
* ```typescript
* // Basic subscription
* const unsubscribe = publisher.on('pan', (event, state) => {
* console.log(`Panned by (${event.diff.x}, ${event.diff.y})`);
* });
*
* // Later: unsubscribe
* unsubscribe();
*
* // Using AbortController for batch management
* const controller = new AbortController();
* publisher.on('pan', handlePan, { signal: controller.signal });
* publisher.on('zoom', handleZoom, { signal: controller.signal });
*
* // Unsubscribe all at once
* controller.abort();
*
* // Subscribe to all events with type discrimination
* publisher.on('all', (event, state) => {
* switch (event.type) {
* case 'pan':
* console.log('Pan:', event.diff);
* break;
* case 'zoom':
* console.log('Zoom:', event.deltaZoomAmount);
* break;
* case 'rotate':
* console.log('Rotate:', event.deltaRotation);
* break;
* }
* });
* ```
*/
on<K extends keyof CameraEventMap>(eventName: K, callback: (event: CameraEventMap[K], cameraState: CameraState) => void, options?: SubscriptionOptions): UnSubscribe;
}