import { AcCmEventManager, AcDbEntity, AcDbLayerTableRecord, AcDbLayerTableRecordAttrs, AcDbLayout, AcDbObjectId, AcGeBox2d, AcGeBox3d, AcGePoint2d, AcGePoint2dLike } from '@mlightcad/data-model'; import { AcEdCorsorType, AcEdSelectionSet } from '../input'; import { AcEditor } from '../input/AcEditor'; import { AcEdSelectionAction } from './AcEdSelectionAction'; import { AcEdSpatialQueryResultItemEx } from './AcEdSpatialQueryResult'; /** * Interface to define arguments of mouse event events. */ export interface AcEdMouseEventArgs { /** * X coordinate value of current mouse in the world coordinate system */ x: number; /** * Y coordinate value of current mouse in the world coordinate system */ y: number; } /** * Interface to define arguments of view resized events. */ export interface AcEdViewResizedEventArgs { /** * New width of the resized view. */ width: number; /** * New height of the resized view. */ height: number; } /** * Interface to define arguments of hover events. */ export interface AcEdViewHoverEventArgs { /** * X coordinate value of current mouse in the screen coordinate system */ x: number; /** * Y coordinate value of current mouse in the screen coordinate system */ y: number; /** * Object id of the hovered entity */ id: AcDbObjectId; } /** * Interface to define arguments of render frame events. */ export interface AcEdViewRenderFrameEventArgs { /** * The renderer used for rendering the frame */ render: unknown; /** * The camera used for rendering the frame */ camera: unknown; } /** * Enumeration of view interaction modes. * * The view mode determines how the view responds to user mouse interactions: * - In SELECTION mode, clicks select entities * - In PAN mode, clicks and drags pan the view * * @example * ```typescript * // Set to selection mode for entity picking * view.mode = AcEdViewMode.SELECTION; * * // Set to pan mode for view navigation * view.mode = AcEdViewMode.PAN; * ``` */ export declare enum AcEdViewMode { /** * Selection mode - mouse clicks select entities. * * In this mode: * - Single clicks select individual entities * - Drag operations can create selection boxes * - Selected entities are highlighted with grip points */ SELECTION = 0, /** * Pan mode - mouse interactions pan the view. * * In this mode: * - Click and drag operations move the view * - The cursor typically changes to indicate pan mode * - Entity selection is disabled */ PAN = 1 } /** * Selection box interaction mode. */ export type AcEdSelectionMode = 'window' | 'crossing'; export type { AcEdSelectionAction } from './AcEdSelectionAction'; export { resolvePointerSelectionAction, resolveSelectionActionFromEvent } from './AcEdSelectionAction'; /** * Represents missed data when rendering entities in the drawing */ export interface AcEdMissedData { fonts: Record; images: Map; } /** * Type of callback function used to calculate size of canvas when window resized */ export type AcEdCalculateSizeCallback = () => { width: number; height: number; }; /** * Abstract base class for all CAD view implementations. * * This class provides the foundation for rendering and interacting with CAD drawings. * It manages: * - Canvas and viewport dimensions * - Mouse event handling and coordinate conversion * - Entity selection and highlighting * - View modes (selection, pan, etc.) * - Spatial queries for entity picking * - Hover/unhover detection with timing * * Concrete implementations must provide specific rendering logic and coordinate * transformations appropriate for their rendering technology (e.g., Three.js, SVG). * * ## Key Responsibilities * - **Input Management**: Handles mouse events and user interactions * - **Selection**: Manages selected entities and visual feedback * - **Coordinate Systems**: Converts between screen and world coordinates * - **Spatial Queries**: Finds entities at specific locations * - **View State**: Tracks current position, zoom, and view mode * * @example * ```typescript * class MyView extends AcEdBaseView { * // Implement required abstract methods * get missedData() { return { fonts: {}, images: new Map() }; } * get mode() { return this._mode; } * set mode(value) { this._mode = value; } * // ... other abstract methods * } * * const view = new MyView(canvasElement); * view.events.mouseMove.addEventListener(args => { * console.log('Mouse at world coords:', args.x, args.y); * }); * ``` */ export declare abstract class AcEdBaseView { /** Current viewport width in pixels */ private _width; /** Current viewport height in pixels */ private _height; /** Optional callback to calculate canvas size on resize */ private _calculateSizeCallback?; /** Bounding box of all entities in the view */ private _bbox; /** Current mouse position in world coordinates */ private _curPos; /** * Current mouse position in canvas-local screen coordinates (pixels). * * This value is derived from viewport/client mouse coordinates by subtracting * the canvas bounding-rect origin (`viewportToCanvas`). */ private _curMousePos; /** Set of currently selected entities */ private _selectionSet; /** Input manager for handling user interactions */ private _editor; /** Size of selection box in pixels for entity picking */ private _selectionBoxSize; /** * Controller responsible for all hover-related behavior in this view. * * This includes: * - Delayed hover detection while the mouse is stationary * - Pause-based hover confirmation * - Tracking the currently hovered entity * - Dispatching hover and unhover events * * Extracted into a separate class to keep `AcEdBaseView` focused on * view lifecycle and input routing rather than interaction timing logic. */ private _hoverController; /** The HTML canvas element for rendering */ protected _canvas: HTMLCanvasElement; /** The HTML element to contain this view */ protected _container: HTMLElement; /** Events fired by the view for various interactions */ readonly events: { /** Fired when mouse moves over the view */ mouseMove: AcCmEventManager; /** Fired when the view is resized */ viewResize: AcCmEventManager; /** Fired when the view camera is changed */ viewChanged: AcCmEventManager; /** Fired when mouse hovers over an entity */ hover: AcCmEventManager; /** Fired when mouse stops hovering over an entity */ unhover: AcCmEventManager; /** Fired when a frame is rendered */ renderFrame: AcCmEventManager; }; /** * Creates a new base view instance. * * Sets up the canvas, initializes internal state, and registers event listeners * for mouse interactions and container resize events. * * @param canvas - The HTML canvas element to render into * @param container - The HTML element to contain this viewer. The canvas element * must be children element of container element. */ constructor(canvas: HTMLCanvasElement, container: HTMLElement); /** * Gets the input manager for handling user interactions. * * The editor provides high-level methods for getting user input like * point selection, entity selection, and cursor management. * * @returns The editor instance */ get editor(): AcEditor; /** * Gets the size of the selection box used for entity picking. * * This determines how close the mouse needs to be to an entity * to select it, measured in screen pixels. * * @returns Selection box size in pixels */ get selectionBoxSize(): number; /** * Sets the size of the selection box used for entity picking. * * @param value - Selection box size in pixels */ set selectionBoxSize(value: number); /** * Gets information about missing data during rendering. * * This includes fonts that couldn't be loaded and images that are * missing or inaccessible. Implementations should track and report * this information to help users understand rendering issues. * * @returns Object containing missing fonts and images */ abstract get missedData(): AcEdMissedData; /** * Gets the current view mode. * * The view mode determines how the view responds to user interactions: * - SELECTION: Click to select entities * - PAN: Click and drag to pan the view * * @returns The current view mode */ abstract get mode(): AcEdViewMode; /** * Sets the current view mode. * * @param value - The view mode to set */ abstract set mode(value: AcEdViewMode); /** * Gets the center point of the current view in world coordinates. * * @returns The view center point */ abstract get center(): AcGePoint2d; /** * Sets the center point of the current view in world coordinates. * * @param value - The new center point */ abstract set center(value: AcGePoint2d); /** * Converts a point from screen coordinates to world coordinates. * * The screen coordinate system has its origin at the top-left corner * of the canvas, with Y increasing downward. World coordinates use the * CAD coordinate system with Y typically increasing upward. * * @param point - Point in screen coordinates * @returns Point in world coordinates * * @example * ```typescript * const screenPoint = { x: 100, y: 200 }; // 100px right, 200px down * const worldPoint = view.screenToWorld(screenPoint); * console.log('World coordinates:', worldPoint.x, worldPoint.y); * ``` */ abstract screenToWorld(point: AcGePoint2dLike): AcGePoint2d; /** * Converts a point from world coordinates to screen coordinates. * * This is the inverse of `screenToWorld()`, converting from the CAD world * coordinate system to screen pixel coordinates. * * @param point - Point in world coordinates * @returns Point in screen coordinates * * @example * ```typescript * const worldPoint = new AcGePoint2d(10, 20); // CAD coordinates * const screenPoint = view.worldToScreen(worldPoint); * console.log('Screen position:', screenPoint.x, screenPoint.y); * ``` */ abstract worldToScreen(point: AcGePoint2dLike): AcGePoint2d; /** * Zooms the view to fit the specified bounding box with optional margin. * * This method adjusts the view's center and zoom level so that the entire * specified bounding box is visible within the viewport. The margin parameter * adds extra space around the bounding box to provide visual padding. * * @param box - The bounding box to zoom to, in world coordinates * @param margin - Additional margin around the bounding box (in world units) */ abstract zoomTo(box: AcGeBox2d, margin: number): void; /** * Zooms the view to fit all visible entities in the current drawing. * * This method automatically calculates the bounding box of all entities * currently displayed in the view and adjusts the view's center and zoom * level to show the entire scene. This is useful for getting an overview * of the entire drawing or after loading new content. * * This function takes effect only if the current view has finished rendering * all entities. When opening a file, progressive Rendering is used to render * entities incrementally. So this function will wait until all of entities * rendered or a timeout occurs. * * @param timeout - Maximum time (ms) to wait before executing zoom to fit * action. Default: 0 (no timeout). */ abstract zoomToFitDrawing(timeout?: number): void; /** * Zooms the view to fit all visible entities in the current scene. * * This method automatically calculates the bounding box of all entities * currently displayed in the specified layer and adjusts the view's center * and zoom level to show the entire layer. This is useful for getting an * overview of the entire layer of one drawing or after loading new content. * * @param layerName - The layer name * * @return - Return true if zoomed to the layer successfully. */ abstract zoomToFitLayer(layerName: string): boolean; /** * Moves the current view to the specified 2D point at the given scale. * * @param point - Target location in world coordinates to fly the view to. * @param scale - The optional target zoom scale to apply after the transition. * If not specified, the scale will not change. */ abstract flyTo(point: AcGePoint2dLike, scale?: number): void; /** * Gets the background color of the view. * * The color is represented as a 24-bit hexadecimal RGB number, for example * `0x000000` for black or `0xffffff` for white. */ abstract get backgroundColor(): number; /** * Sets the background color of the view. * * @param value - The background color as a 24-bit hexadecimal RGB number */ abstract set backgroundColor(value: number); /** * Search entities intersected or contained in the specified bounding box. * @param box Input the query bounding box * @returns Return query results */ abstract search(box: AcGeBox2d | AcGeBox3d): AcEdSpatialQueryResultItemEx[]; /** * Picks entities that intersect a hit-region centered at the specified point * in world coordinates. * * The hit-region is defined as a square (or bounding box) centered at the * input point, whose half-size is determined by the `hitRadius` parameter. * Only entities whose geometry intersects this region are returned. * * @param point The center point of the hit-region in world coordinates. * If omitted, the current cursor position is used. * * @param hitRadius The half-width (in pixel size) of the hit-region around * the point. It will be converted on one value in the world * coordinate 'wcsHitRadius' and creates a square bounding box: * [point.x ± wcsHitRadius, point.y ± wcsHitRadius]. * A larger value increases the pick sensitivity. If omitted, a reasonable * default is used. * * @returns Return query results representing the entities that intersect * the hit-region. */ abstract pick(point?: AcGePoint2dLike, hitRadius?: number, pickOneOnly?: boolean): AcEdSpatialQueryResultItemEx[]; /** * Select entities intersected with the specified bounding box in the world * coordinate system, add them to the current selection set, and highlight * them. * @param box Input one bounding box in the world coordinate system. */ abstract selectByBox(box: AcGeBox2d): void; /** * Select entities intersected with the specified point in the world coordinate * system, add them to the current selection set, and highlight them. * @param box Input one point in the world coordinate system. */ abstract select(point?: AcGePoint2dLike): void; /** * Clear the scene */ abstract clear(): void; /** * Add the specified layer in drawing database into the current scene * @param layer Input the layer to add into the current scene */ abstract addLayer(layer: AcDbLayerTableRecord): void; /** * Update the specified layer in the current scene * @param layer - The layer to update * @param changes - Changes made to the layer */ abstract updateLayer(layer: AcDbLayerTableRecord, changes: Partial): void; /** * Add the specified transient entity or entities in the current scene. * @param entity Input one or multiple transient entities */ abstract addTransientEntity(entity: AcDbEntity | AcDbEntity[]): void; /** * Remove the specified transient entity or entities in the current scene. * @param entity Input the object id of one transient entity */ abstract removeTransientEntity(objectId: AcDbObjectId): void; /** * Add the specified entity or entities in drawing database into the current scene * and draw it or them * @param entity Input one or multiple entities to add into the current scene */ abstract addEntity(entity: AcDbEntity | AcDbEntity[]): void; /** * Remove the specified entity or entities from current drawing database and current scene * and draw it or them * @param entity Input one or multiple entities to remove */ abstract removeEntity(entity: AcDbEntity | AcDbEntity[]): void; /** * Update the specified entity or entities * @param entity Input the entity or entities to update */ abstract updateEntity(entity: AcDbEntity | AcDbEntity[]): void; /** * Add the specified layout in drawing database into the current scene * @param layout Input the layout to add into the current scene */ abstract addLayout(layout: AcDbLayout): void; /** * Select the specified entities */ abstract highlight(ids: AcDbObjectId[]): void; /** * Unhighlight the specified entities */ abstract unhighlight(ids: AcDbObjectId[]): void; /** * Called when hovering the specified entity */ abstract onHover(id: AcDbObjectId): void; /** * Called when unhovering the specified entity */ abstract onUnhover(id: AcDbObjectId): void; /** * Temporarily switches the view mode, executes an action, then restores * the previous mode — even if the action throws. * * This is the mode-level counterpart of {@link AcEditor.withCursor} and * follows the same save → set → restore pattern. * * @param mode - The temporary view mode to apply * @param action - The async (or sync) action to run under the temporary mode * @returns The value returned by the action * * @example * ```typescript * await view.withMode(AcEdViewMode.SELECTION, async () => { * const pt = await view.editor.getPoint('Pick a point') * }) * // view.mode is restored to whatever it was before * ``` */ withMode(mode: AcEdViewMode, action: () => Promise | T): Promise; /** * Set cursor type of this view * @param cursorType Input cursor type */ setCursor(cursorType: AcEdCorsorType): void; /** * Returns selection mode based on drag direction in canvas coordinates. * Left-to-right = window selection, right-to-left = crossing selection. */ getSelectionMode(startCanvas: AcGePoint2dLike, endCanvas: AcGePoint2dLike): AcEdSelectionMode; /** * Returns the selection action based on modifier keys. * Shift: remove, Ctrl/Cmd: add, default: replace. */ getSelectionActionFromEvent(e: MouseEvent, defaultAction?: AcEdSelectionAction): AcEdSelectionAction; /** * Determine whether a drag is effectively a click. */ isSelectionClick(startCanvas: AcGePoint2dLike, endCanvas: AcGePoint2dLike, threshold?: number): boolean; /** * Returns preview styles for selection rectangle. */ getSelectionPreviewStyle(mode: AcEdSelectionMode, action: AcEdSelectionAction): { borderStyle: string; lineColor: string; background: string; }; /** * Applies selection based on action. */ applySelection(ids: AcDbObjectId[], action: AcEdSelectionAction): void; /** * Select entities by box with window/crossing behavior. */ selectByBoxWithMode(box: AcGeBox2d, mode: AcEdSelectionMode, action?: AcEdSelectionAction): void; /** * Collects ids using window or crossing selection rules. */ protected collectSelectionIdsByBox(box: AcGeBox2d, mode: AcEdSelectionMode): string[]; /** * Set callback function used to calculate size of canvas when window resized * @param value Input callback function */ setCalculateSizeCallback(value: AcEdCalculateSizeCallback): void; /** * Width of canvas (not width of window) in pixel */ get width(): number; set width(value: number); /** * Height of canvas (not height of window) in pixel */ get height(): number; set height(value: number); /** * The bounding box to include all entities in this viewer */ get bbox(): AcGeBox3d; /** * The canvas HTML element used by this view */ get canvas(): HTMLCanvasElement; /** * The HTML element to contain this view */ get container(): HTMLElement; /** * Converts a viewport/client-space point (e.g. MouseEvent.clientX/Y) * into canvas-local coordinates. */ viewportToCanvas(point: AcGePoint2dLike): AcGePoint2d; /** * Converts canvas-local coordinates into viewport/client-space coordinates. */ canvasToViewport(point: AcGePoint2dLike): AcGePoint2d; /** * Converts canvas-local coordinates into container-local coordinates. * * This is useful for DOM overlays mounted in `container` while CAD APIs * return screen points in canvas space. */ canvasToContainer(point: AcGePoint2dLike): AcGePoint2d; /** * Converts a viewport/client-space point into container-local coordinates. */ viewportToContainer(point: AcGePoint2dLike): AcGePoint2d; get aspect(): number; /** * Postion of current mouse in world coordinate system */ get curPos(): AcGePoint2d; /** * Current mouse position in canvas-local screen coordinates (pixels). * * Note: this is NOT viewport/client coordinates; use `canvasToViewport()` * when browser-viewport coordinates are required by DOM APIs. */ get curMousePos(): AcGePoint2d; /** * The selection set in current view. */ get selectionSet(): AcEdSelectionSet; protected onWindowResize(): void; /** * Clears the current hover state and cancels all hover-related timers. */ protected clearHover(): void; /** * Mouse move event handler. * @param event Input mouse event argument */ private onMouseMove; } //# sourceMappingURL=AcEdBaseView.d.ts.map