import { Brush } from "./Brush"; import type { BrushConfig } from "./types/config"; import { MousePressure } from "./utils"; import { type CreateLayerOptions, type UpdateLayerOptions } from "./LayerManager"; import { Layer } from "./Layer"; import { type FuderuDocument, type ExportDocumentOptions, type ExportPNGOptions } from "./types/document"; import type { CanvasEventMap, CanvasSnapshot } from "./types/events"; import type { CanvasAction, ReplayOptions } from "./types/actions"; import type { DrawRectangleOptions, DrawEllipseOptions, DrawLineOptions, TextStyleOptions, ColorSample } from "./types/commands"; import { HistoryManager, type HistoryContext } from "./HistoryManager"; export interface CanvasOptions { canvas: HTMLCanvasElement | string; /** * The logical drawing resolution. * This is the size of the internal pixel buffer, independent of how * the canvas element is sized on screen via CSS. * Defaults to the displayed canvas size multiplied by devicePixelRatio. */ document?: { width: number; height: number; }; brush?: BrushConfig; pressureSimulation?: boolean; } export declare class Canvas implements HistoryContext { private canvas; brush: Brush; private layers; history: HistoryManager; private isDrawing; private activePointerId; private currentStrokeBeforeCanvas; private currentStrokeLayerId; private strokeMinX; private strokeMinY; private strokeMaxX; private strokeMaxY; private cacheBelowCanvas; private cacheBelowValid; private listeners; private currentStrokePoints; /** The logical drawing resolution width (internal pixel buffer) */ documentWidth: number; /** The logical drawing resolution height (internal pixel buffer) */ documentHeight: number; /** whether the caller provided an explicit document size */ private documentProvided; /** * The underlying pressure simulator. * Replace at runtime to change K / minRange / maxRange. */ mousePressure: MousePressure; /** * When true, mouse/touch events with no real stylus pressure * will use simulated pressure based on movement speed. */ pressureSimulation: boolean; /** * The last pressure value sent to the brush. * Read this in the playground's pressure meter instead of calling * getPressure() again, avoiding double-advancing the simulator state. */ lastPressure: number; private actionLog; private isReplaying; constructor(options: CanvasOptions); renderLayers(): void; private setupCanvas; /** * Resize the internal drawing buffer to match the element's display size. * Also reinitialises the brush context so the brush's offscreen canvases * match the new pixel buffer. */ resize(): void; /** * Subscribe to canvas events (change, stroke:start, stroke:end, history:change, layer:change). * Returns an unsubscribe callback for easy cleanup. */ on(event: K, listener: CanvasEventMap[K]): () => void; /** * Unsubscribe a listener from canvas events. */ off(event: K, listener: CanvasEventMap[K]): void; private emit; /** * Returns a synchronous snapshot of the current canvas state suitable for * reactive bindings like useSyncExternalStore. */ getSnapshot(): CanvasSnapshot; private emitHistoryChange; private emitStateChange; private bindEvents; private getPoint; private updateStrokeBounds; /** * Returns the part of a drawing operation that intersects the document. * Keeping history patches inside the canvas prevents getImageData from * throwing for commands positioned completely outside the document. */ private getPatchBounds; private handlePointerDown; private handlePointerMove; private commitStroke; private handlePointerUp; private handlePointerCancel; setActiveLayer(layerId: string): void; getLayers(): readonly Layer[]; getActiveLayer(): Layer; getLayerById(id: string): Layer | undefined; reorderLayers(ids: string[]): void; createLayer(options?: CreateLayerOptions | string): Layer; deleteLayer(layerId: string): void; duplicateLayer(layerId: string): Layer; moveLayer(layerId: string, targetIndex: number): void; updateLayer(layerId: string, options: UpdateLayerOptions): Layer; clear(): void; undo(): void; redo(): void; getLayer(layerId: string): Layer | undefined; getBrush(): Brush; deleteLayerOnly(layerId: string): void; insertLayerOnly(layer: Layer, index: number): void; moveLayerOnly(layerId: string, index: number): void; setSmooth(enabled: boolean): void; setSpacing(enabled: boolean): void; setEraser(enabled: boolean): void; loadConfig(config: BrushConfig): void; loadImage(img: HTMLImageElement | HTMLCanvasElement | string): Promise; /** * Change the logical document size. * * By default, this preserves existing layer artwork (lossless crop/pad) but resets the undo stack * because previous undo/redo states will no longer match the new canvas dimensions. * If `clearArtwork` is set to true, it will additionally clear all artwork on the layers. * * It does NOT change any CSS on the canvas element; * sizing the element on screen is the caller's responsibility. * * @example * painter.setDocumentSize(768, 1024); // crops/pads existing layers, clears undo stack * painter.setDocumentSize(768, 1024, true); // clears all artwork completely, clears undo stack */ setDocumentSize(width: number, height: number, clearArtwork?: boolean): void; /** * Export the complete canvas document state including width, height, * layer metadata, and serialized layer bitmaps. */ exportDocument(options?: ExportDocumentOptions): Promise; /** * Import and atomically load a complete canvas document. * Recreates all layers, loads bitmap graphics asynchronously, and sets active layer. */ importDocument(rawDocument: FuderuDocument | unknown): Promise; /** * Export a flattened composite PNG image of the artwork. */ exportPNG(options?: ExportPNGOptions): Promise; clearActiveLayer(): void; fillActiveLayer(color: string): void; getColorAt(x: number, y: number, scope?: "activeLayer" | "composite"): ColorSample; floodFill(x: number, y: number, color: string, tolerance?: number): void; drawRectangle(options: DrawRectangleOptions): void; drawEllipse(options: DrawEllipseOptions): void; drawLine(options: DrawLineOptions): void; drawText(text: string, x: number, y: number, style?: TextStyleOptions): void; /** * Appends a serializable action to the canvas operation log and emits "action:record" * (and "stroke:record" if the action is a stroke). */ recordAction(action: CanvasAction): void; /** * Returns a copy of the serializable canvas action log recorded so far. */ getActionLog(): CanvasAction[]; /** * Clears the internal action log. */ clearActionLog(): void; /** * Replays a single serializable CanvasAction onto the canvas. */ replayAction(action: CanvasAction): Promise; /** * Replays an array of serializable CanvasActions onto the canvas. */ replay(actionLog: CanvasAction[], options?: ReplayOptions): Promise; destroy(): void; } //# sourceMappingURL=Canvas.d.ts.map