import * as THREE from "three"; import type { KeyMappingConfig } from "../utils/utils.js"; import { Slider } from "./slider.js"; import { Toolbar, Button, ClickButton } from "./toolbar.js"; import type { MeasurementPanelElements, FilterDropdownElements } from "../tools/cad_tools/tools.js"; import { FilterByDropDownMenu } from "../tools/cad_tools/ui.js"; import { Info } from "./info.js"; import type { Viewer } from "../core/viewer.js"; import type { ViewerState } from "../core/viewer-state.js"; import type { Vector3Tuple } from "three"; import type { ThemeInput, ClipIndex } from "../core/types.js"; /** * Options for Display constructor */ export interface DisplayOptions { measureTools: boolean; measurementDebug: boolean; selectTool: boolean; explodeTool: boolean; zscaleTool: boolean; zebraTool: boolean; studioTool: boolean; glass: boolean; tools: boolean; cadWidth: number; height: number; treeWidth: number; treeHeight?: number; theme: ThemeInput; pinning: boolean; canvas?: HTMLCanvasElement; gl?: WebGLRenderingContext | WebGL2RenderingContext; } /** * Options for setSizes method */ interface SizeOptions { cadWidth?: number; height?: number; treeWidth?: number; treeHeight?: number; glass?: boolean; tools?: boolean; } /** * Options for canvas capture */ interface CaptureOptions { taskId: string; render: () => void; onComplete?: () => void; } /** * Result of canvas capture */ interface CaptureResult { task: string; dataUrl: string | ArrayBuffer | null; } /** * Stored event for cleanup */ type StoredEvent = [string, string, EventListener]; /** * Main entry point for three-cad-viewer. Creates the UI and manages the viewer. * * Display handles: * - DOM structure (toolbar, tree view, tabs, sliders) * - User interaction (button clicks, slider changes) * - State subscriptions (UI updates when viewer state changes) * - Theme management (light/dark/browser preference) * * ## Usage * ```typescript * import { Display } from 'three-cad-viewer'; * * const container = document.getElementById('viewer'); * const display = new Display(container, { * cadWidth: 800, * height: 600, * theme: 'light' * }); * * // Load and render CAD shapes * display.render(shapesData, states, renderOptions); * * // Access viewer for programmatic control * display.viewer.setAxes(true); * * // Cleanup when done * display.dispose(); * ``` * * ## Options * @see DisplayOptions for all configuration options * * @public */ declare class Display { container: HTMLElement; cadBody: HTMLElement; cadView: HTMLElement; cadTree: HTMLElement; cadTreeScrollContainer: HTMLElement; cadTreeToggles: HTMLElement; cadClipToggles: HTMLElement; cadMaterialToggles: HTMLElement; cadZebraToggles: HTMLElement; cadStudioToggles: HTMLElement; cadClip: HTMLElement; cadMaterial: HTMLElement; cadZebra: HTMLElement; cadStudio: HTMLElement; private _spinnerEl; private _warningBannerEl; private _warningBannerTimer; private _spinnerCount; private _matEditorPath; private _matEditorClones; private _savedMatEditorChanges; private _matEditorDragAbort; private _matEditorInputAbort; cadInfo: HTMLElement; cadAnim: HTMLElement; private _animWasVisible; cadTools: HTMLElement; cadHelp: HTMLElement; tabTree: HTMLElement; tabClip: HTMLElement; tabMaterial: HTMLElement; tabZebra: HTMLElement; tabStudio: HTMLElement; tickValueElement: HTMLElement; tickInfoElement: HTMLElement; distanceMeasurementPanel: HTMLElement; propertiesMeasurementPanel: HTMLElement; planeLabels: HTMLElement[]; animationSlider: HTMLInputElement | null; measurementPanels: MeasurementPanelElements; filterDropdown: FilterDropdownElements; cadTool: Toolbar; clickButtons: Record; buttons: Record; clipSliders: Slider[] | null; ambientlightSlider: Slider | undefined; directionallightSlider: Slider | undefined; metalnessSlider: Slider | undefined; roughnessSlider: Slider | undefined; zebraCountSlider: Slider | undefined; zebraOpacitySlider: Slider | undefined; zebraDirectionSlider: Slider | undefined; studioEnvIntensitySlider: Slider | undefined; studioExposureSlider: Slider | undefined; studioEnvRotationSlider: Slider | undefined; studioShadowIntensitySlider: Slider | undefined; studioShadowSoftnessSlider: Slider | undefined; studioAOIntensitySlider: Slider | undefined; viewer: Viewer; state: ViewerState; measureTools: boolean; measurementDebug: boolean; selectTool: boolean; explodeTool: boolean; zscaleTool: boolean; zScale: number; glass: boolean; tools: boolean; cadWidth: number; height: number; treeWidth: number; theme: ThemeInput; lastPlaneState: boolean; help_shown: boolean; info_shown: boolean; tools_shown: boolean; _info: Info; _events: StoredEvent[]; _unsubscribers: (() => void)[]; shapeFilterDropDownMenu: FilterByDropDownMenu; mediaQuery: MediaQueryList | undefined; /** * Create Display. * @param container - the DOM element that should contain the Display * @param options - display options * @public */ constructor(container: HTMLElement, options: DisplayOptions); setButtonBackground(): void; /** * Calculate the width threshold for toolbar collapse. * @returns The threshold width in pixels. */ private _widthThreshold; /** * Update toolbar collapse state based on available width. * Maximizes toolbar if width is sufficient, minimizes otherwise. * @param availableWidth - The available width in pixels. */ updateToolbarCollapse(availableWidth: number): void; private setupCheckEvent; private setupClickEvent; private setupRadioEvent; /** * Wire a select element's change event */ private setupSelectEvent; /** * Get a DOM element by class name (internal use only). * @param name - Name of the DOM element class * @returns The DOM element */ private getElement; /** * Get an input element by class name (internal use only). * @param name - Name of the DOM element class * @returns The input element */ private getInputElement; /** * Dispose of all resources. Call when done with the viewer. * * Disposes: * - All state subscriptions * - Event listeners * - Toolbar and buttons * - Sliders * - DOM content * * After dispose(), the Display instance should not be used. * * @public */ dispose(): void; /** * Add HTML content to the info panel. * @param html - The HTML string to add. */ addInfoHtml(html: string): void; /** * Display the ready message with viewer version and control mode. * @param version - Viewer version string. * @param control - Control mode name (e.g., "orbit", "trackball"). */ showReadyMessage(version: string, control: string): void; /** * Display camera target center information. * @param center - The center coordinates [x, y, z]. */ showCenterInfo(center: Vector3Tuple): void; /** * Display bounding box information for a selected object. * @param path - The object's path in the tree. * @param name - The object's name. * @param bb - The bounding box to display. */ showBoundingBoxInfo(path: string, name: string, bb: THREE.Box3): void; /** * Capture the canvas as a data URL. * @param options - Capture options. * @returns Promise resolving to task ID and data URL. */ captureCanvas(options: CaptureOptions): Promise; /** * Set the width and height of the different UI elements (tree, canvas and info box). * @param options - Size options * @public */ setSizes(options: SizeOptions): void; /** * Set up the UI and attach the canvas element. * Called by Viewer constructor, not intended for direct use. * @param viewer - The viewer instance for this UI. * @param canvasElement - The Three.js renderer canvas to attach. * @internal */ setupUI(viewer: Viewer, canvasElement: HTMLCanvasElement): void; /** * Subscribe to ViewerState changes to keep UI in sync. * Stores unsubscribe functions for cleanup in dispose(). * @internal */ private subscribeToStateChanges; /** * Initialize UI elements from current state. * Called once during initialization. Subsequent updates happen via state subscriptions. * @internal */ updateUI(): void; /** * Check or uncheck a checkbox * @param name - name of the check box, see getElement * @param flag - whether to check or uncheck */ checkElement(name: string, flag: boolean): void; /** * Attach the canvas element to the CAD view container. * @param canvasElement - The canvas to attach. */ private attachCanvas; /** * Get the DOM canvas element */ getCanvas(): Element; /** * Clear the Cad tree */ clearCadTree(): void; /** * Add the Cad tree and other UI elements like Clipping * @param cadTree - the DOM element that contains the cadTree */ addCadTree(cadTree: HTMLElement): void; /** * Checkbox Handler for setting the axes parameter */ setAxes: (_name: string, flag: boolean) => void; /** * Checkbox Handler for setting the grid parameter */ setGrid: (name: string, flag: boolean) => void; /** * Checkbox Handler for setting the axes0 parameter */ setAxes0: (_name: string, flag: boolean) => void; /** * Checkbox Handler for setting the ortho parameter */ setOrtho: (_name: string, flag: boolean) => void; /** * Checkbox Handler for setting the transparent parameter */ setTransparent: (_name: string, flag: boolean) => void; /** * Checkbox Handler for setting the black edges parameter */ setBlackEdges: (_name: string, flag: boolean) => void; /** * Handler for the explode button */ setExplode: (_name: string, flag: boolean) => void; /** * Show or hide the Explode checkbox */ showExplode: (flag: boolean) => void; /** * Checkbox Handler for setting the zscale mode */ setZScale: (_name: string, flag: boolean) => void; /** * Show or hide the ZScale slider */ showZScale: (flag: boolean) => void; /** * Checkbox Handler for setting the tools mode. * Delegates state mutations to Viewer.activateTool() to maintain unidirectional data flow. */ setTool: (name: string, flag: boolean) => void; /** * Show or hide the CAD tools (UI update only). * This method only updates the visual state - it does not modify ViewerState. */ showTools: (flag: boolean) => void; /** * Show or hides measurement tools, measurement tools needs a backend to be used. */ showMeasureTools: (flag: boolean) => void; /** * Show or hides select tool */ showSelectTool: (flag: boolean) => void; /** * Show or hides explode tool */ showExplodeTool: (flag: boolean) => void; /** * Show or hides ZScale tool */ showZScaleTool: (flag: boolean) => void; /** * Deactivate any running tool and hide tool buttons for Studio mode. * Called when entering Studio mode. * @internal */ private _deactivateToolsForStudio; /** * Restore tool button visibility after leaving Studio mode. * Respects original feature flags (measureTools, selectTool). * Does not auto-activate any tool. * @internal */ private _restoreToolsAfterStudio; /** * Checkbox Handler for setting the clip planes parameter */ setClipPlaneHelpers: (e: Event) => void; /** * Checkbox Handler for setting the clip intersection parameter */ setClipIntersection: (e: Event) => void; /** * Checkbox Handler for toggling the clip caps */ setObjectColorCaps: (e: Event) => void; /** * Set the normal at index to the current viewing direction */ setClipNormalFromPosition: (e: Event) => void; /** * Handler to set the label of a clipping normal widget */ setNormalLabel: (index: ClipIndex, normal: [number, number, number]) => void; /** * Handler to reset position, zoom and up of the camera */ reset: () => void; /** * Handler to reset zoom of the camera */ resize: () => void; /** * Handler to set camera to a predefined position. * Called by Button callback which passes the button name as string. */ setView: (direction: string, focus?: boolean) => void; /** * Show/hide pinning button */ showPinning(flag: boolean): void; /** * Pin screenshot of canvas as PNG */ pinAsPng: (_name: string, _shift: boolean) => void; /** * Handler to activate a UI tab (tree / clipping / material / zebra) */ selectTab: (e: Event) => void; /** * Switch to a tab (internal, called by activeTab subscription). */ private switchToTab; /** Show the toolbar spinner (ref-counted for overlapping async ops). */ private _showSpinner; /** Hide the toolbar spinner (only when all pending ops complete). */ private _hideSpinner; /** Show a warning banner in the viewport. Auto-hides after 8 seconds. */ private _showWarningBanner; /** Hide the warning banner. */ private _hideWarningBanner; /** * Toggle visibility of the clipping tab */ toggleClippingTab: (flag: boolean) => void; /** * Collapse nodes handler (event handler) * Translates button codes to CollapseState and calls viewer */ handleCollapseNodes: (e: Event) => void; /** * Reset clip planes to default normals and slider positions */ handleClipReset: (_e: Event) => void; /** * Reset material values to original values */ handleMaterialReset: (_e: Event) => void; /** * Reset zebra tool to default settings */ handleZebraReset: (_e: Event) => void; /** * Handler for Studio environment dropdown change */ handleStudioEnvironment: (e: Event) => void; /** * Handler for Studio env intensity slider change. * Slider range 0-200 with percentage=true, so value arrives as 0-2. */ handleStudioEnvIntensity: (value: number) => void; handleStudioEnvRotation: (value: number) => void; /** * Handler for Studio background dropdown change. * Validates against the StudioBackground union before setting state. */ handleStudioBackground: (e: Event) => void; /** * Handler for Studio tone mapping dropdown change. * Validates against the StudioToneMapping union before setting state. */ handleStudioToneMapping: (e: Event) => void; /** * Handler for Studio exposure slider change. * Slider range 0-200 with percentage=true, so value arrives as 0-2. */ handleStudioTextureMapping: (e: Event) => void; handleStudioExposure: (value: number) => void; handleStudioShadowIntensity: (value: number) => void; handleStudioShadowSoftness: (value: number) => void; /** * Handler for Studio AO intensity slider change. * Slider range 0-30, divided by 10 → state gets 0-3.0. * A value of 0 disables AO. */ handleStudioAOIntensity: (value: number) => void; /** * Handler for Studio 4K env maps checkbox change. * Shows a "Loading…" indicator while the new resolution downloads. */ handleStudio4kEnvMaps: (e: Event) => void; /** * Reset Studio tab values to defaults. * Delegates to viewer.resetStudio() (same pattern as handleMaterialReset -> resetMaterial()). */ handleStudioReset: (_e: Event) => void; handleMatEditorToggle: (_e: Event) => void; private _showMatEditorHint; private openMatEditor; closeMatEditor(): void; /** Dispose all cloned materials, restoring originals first (call on Studio mode exit) */ disposeMatEditorClones(): void; /** * Outer-cycle boundary: discard saved Material Editor deltas so they don't * replay on the next Studio entry in a new scene. Unlike viewer preferences * (transparent, axes, grid) which persist across render cycles, Material * Editor edits are per-scene PBR authoring and must reset on scene rebuild. * Mid-cycle (Studio tab leave/enter) and inner-cycle (editor close/reopen) * behavior is unaffected — this is only called from viewer.clear(). */ clearMaterialEditorSession(): void; /** Save material editor property deltas so they survive a Studio mode leave/enter cycle. */ private _saveMatEditorChanges; /** Reapply saved material editor changes after re-entering Studio mode. */ private _reapplyMatEditorChanges; /** * Called by viewer.ts when the selected object changes. * Updates or closes the material editor if it's open. */ onSelectionChanged(newObjectId: string | null): void; handleMatEditorReset: (_e: Event) => void; /** Make the material editor dialog draggable by its titlebar */ private _initMatEditorDrag; private _buildMatEditorContent; private _buildMatEditorRow; /** * Set zebra stripe count in the UI */ setZebraCount: (val: number) => void; /** * Set zebra stripe opacity in the UI */ setZebraOpacity: (val: number) => void; /** * Set zebra stripe direction in the UI */ setZebraDirection: (val: number) => void; /** * Handler for setting the zebra color scheme */ setZebraColorScheme: (e: Event) => void; /** * Set zebra color scheme radio button in the UI */ setZebraColorSchemeSelect: (value: string) => void; /** * Handler for setting the zebra mapping mode */ setZebraMappingMode: (e: Event) => void; /** * Set zebra mapping mode radio button in the UI */ setZebraMappingModeSelect: (value: string) => void; /** * Set minimum and maximum of the clipping sliders */ setSliderLimits(limit: number): void; /** * Sync clip slider UI from current state values. * Called after setSliderLimits to apply initial values with correct limits. */ syncClipSlidersFromState(): void; /** * Sync material slider UI from current state values. * Called from updateUI after render options are applied to state. * State stores values in 0-1 range, sliders display 0-100 (or 0-400 for lights). */ syncMaterialSlidersFromState(): void; /** * Sync zebra slider UI from current state values. * Called from updateUI after viewer options are applied to state. */ syncZebraSlidersFromState(): void; /** * Sync Studio slider/control UI from current state values. */ syncStudioSlidersFromState(): void; /** * Ensure the environment dropdown can display a custom HDR URL. * If envName isn't already an option, adds a "Custom HDR" entry. * Removes stale custom entries when switching back to a built-in preset. */ private _syncEnvDropdown; /** * Enable/disable the 4K checkbox based on whether the current environment * is a Poly Haven preset (resolution-switchable) or a custom URL / "studio". */ private _update4kCheckboxEnabled; /** * Refresh clipping plane position */ refreshPlane: (uiIndex: number, value: string) => void; /** * Handle animation control by button name */ controlAnimationByName(btn: string): void; /** * Handler for the animation control buttons */ controlAnimation: (e: Event) => void; /** * Handler for the animation slider */ animationChange: (e: Event) => void; /** * Handle keyboard shortcut events on the container. */ private _handleKeyboardShortcut; /** * Dispatch a keyboard shortcut action. * Returns "propagate" if the event should not be suppressed. */ private _dispatchAction; /** * Programmatically toggle a ClickButton by name. */ private _toggleClickButton; /** * Update tooltips with keyboard shortcut suffixes. */ updateTooltips(): void; /** * Show or hide help dialog */ showHelp: (flag: boolean) => void; /** * Toggle help dialog visibility */ toggleHelp: () => void; /** * Replace container content with a static image */ replaceWithImage(image: HTMLImageElement): void; /** * Show or hide the distance measurement panel */ showDistancePanel: (flag: boolean) => void; /** * Show or hide the properties measurement panel */ showPropertiesPanel: (flag: boolean) => void; /** * Show or hide info dialog */ showInfo: (flag: boolean) => void; /** * Toggle info dialog visibility */ toggleInfo: () => void; /** * Show or hide tools panel (tabs + content) in glass mode. * Also toggles the orientation marker and animation/explode slider. */ showToolsPanel: (flag: boolean) => void; /** * Toggle tools panel visibility */ toggleToolsPanel: () => void; /** * Auto collapse tree nodes when cad width < 600 */ autoCollapse(): void; /** * Enable/disable glass mode (UI update only). */ glassMode(flag: boolean): void; /** * Update help dialog with new key mappings */ updateHelp(before: KeyMappingConfig, after: Partial): void; /** * Set the UI theme. * @param theme - "light", "dark", or "browser" for auto-detection * @returns The resolved theme ("light" or "dark") * @public */ setTheme(theme: ThemeInput): string; } export { Display };