chartgpu 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -8
- package/dist/ChartGPU.d.ts +23 -6
- package/dist/ChartGPU.d.ts.map +1 -1
- package/dist/config/OptionResolver.d.ts.map +1 -1
- package/dist/config/types.d.ts +26 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/core/GPUContext.d.ts +2 -2
- package/dist/core/GPUContext.d.ts.map +1 -1
- package/dist/core/createRenderCoordinator.d.ts +3 -2
- package/dist/core/createRenderCoordinator.d.ts.map +1 -1
- package/dist/core/renderCoordinator/data/computeVisibleSlice.d.ts +10 -12
- package/dist/core/renderCoordinator/data/computeVisibleSlice.d.ts.map +1 -1
- package/dist/core/renderCoordinator/render/renderAnnotationLabels.d.ts +1 -1
- package/dist/core/renderCoordinator/render/renderAnnotationLabels.d.ts.map +1 -1
- package/dist/core/renderCoordinator/render/renderAxisLabels.d.ts +1 -1
- package/dist/core/renderCoordinator/render/renderAxisLabels.d.ts.map +1 -1
- package/dist/core/renderCoordinator/render/renderSeries.d.ts.map +1 -1
- package/dist/core/renderCoordinator/utils/axisUtils.d.ts +1 -1
- package/dist/core/renderCoordinator/utils/boundsComputation.d.ts.map +1 -1
- package/dist/data/cartesianData.d.ts +67 -0
- package/dist/data/cartesianData.d.ts.map +1 -0
- package/dist/data/createDataStore.d.ts +4 -12
- package/dist/data/createDataStore.d.ts.map +1 -1
- package/dist/data/sampleSeries.d.ts +19 -2
- package/dist/data/sampleSeries.d.ts.map +1 -1
- package/dist/index.cjs +1270 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5171 -5125
- package/dist/index.js.map +1 -1
- package/dist/interaction/createAnnotationAuthoring.d.ts.map +1 -1
- package/dist/interaction/createAnnotationDragHandler.d.ts.map +1 -1
- package/dist/interaction/createAnnotationHitTester.d.ts.map +1 -1
- package/dist/interaction/createChartSync.d.ts +17 -2
- package/dist/interaction/createChartSync.d.ts.map +1 -1
- package/dist/interaction/findNearestPoint.d.ts.map +1 -1
- package/dist/interaction/findPointsAtX.d.ts.map +1 -1
- package/dist/renderers/createAreaRenderer.d.ts +2 -1
- package/dist/renderers/createAreaRenderer.d.ts.map +1 -1
- package/dist/renderers/createBarRenderer.d.ts.map +1 -1
- package/dist/renderers/createHighlightRenderer.d.ts +1 -1
- package/dist/renderers/createHighlightRenderer.d.ts.map +1 -1
- package/dist/renderers/createLineRenderer.d.ts.map +1 -1
- package/dist/renderers/createScatterRenderer.d.ts +2 -1
- package/dist/renderers/createScatterRenderer.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/core/GPUContext.ts","../src/data/packDataPoints.ts","../src/data/createDataStore.ts","../src/data/lttbSample.ts","../src/data/cartesianData.ts","../src/data/sampleSeries.ts","../src/data/ohlcSample.ts","../src/core/renderCoordinator/utils/canvasUtils.ts","../src/core/renderCoordinator/data/computeVisibleSlice.ts","../src/utils/colors.ts","../src/core/renderCoordinator/utils/dataPointUtils.ts","../src/core/renderCoordinator/utils/axisUtils.ts","../src/core/renderCoordinator/utils/timeAxisUtils.ts","../src/core/renderCoordinator/axis/computeAxisTicks.ts","../src/utils/axisLabelStyling.ts","../src/core/renderCoordinator/render/renderAxisLabels.ts","../src/core/renderCoordinator/render/renderAnnotationLabels.ts","../src/interaction/findNearestPoint.ts","../src/core/renderCoordinator/render/renderOverlays.ts","../src/core/renderCoordinator/annotations/processAnnotations.ts","../src/core/renderCoordinator/animation/animationHelpers.ts","../src/core/renderCoordinator/render/renderSeries.ts","../src/shaders/grid.wgsl?raw","../src/renderers/rendererUtils.ts","../src/renderers/createAxisRenderer.ts","../src/renderers/createGridRenderer.ts","../src/shaders/area.wgsl?raw","../src/renderers/createAreaRenderer.ts","../src/shaders/line.wgsl?raw","../src/renderers/createLineRenderer.ts","../src/shaders/bar.wgsl?raw","../src/renderers/createBarRenderer.ts","../src/shaders/scatter.wgsl?raw","../src/renderers/createScatterRenderer.ts","../src/shaders/scatterDensityBinning.wgsl?raw","../src/shaders/scatterDensityColormap.wgsl?raw","../src/renderers/createScatterDensityRenderer.ts","../src/shaders/pie.wgsl?raw","../src/renderers/createPieRenderer.ts","../src/shaders/candlestick.wgsl?raw","../src/renderers/createCandlestickRenderer.ts","../src/shaders/crosshair.wgsl?raw","../src/data/createStreamBuffer.ts","../src/renderers/createCrosshairRenderer.ts","../src/shaders/highlight.wgsl?raw","../src/renderers/createHighlightRenderer.ts","../src/shaders/referenceLine.wgsl?raw","../src/renderers/createReferenceLineRenderer.ts","../src/shaders/annotationMarker.wgsl?raw","../src/renderers/createAnnotationMarkerRenderer.ts","../src/interaction/createEventManager.ts","../src/interaction/createInsideZoom.ts","../src/interaction/createZoomState.ts","../src/interaction/findPointsAtX.ts","../src/interaction/findCandlestick.ts","../src/interaction/findPieSlice.ts","../src/utils/scales.ts","../src/components/createTextOverlay.ts","../src/components/createLegend.ts","../src/components/createTooltip.ts","../src/components/formatTooltip.ts","../src/core/createAnimationController.ts","../src/utils/easing.ts","../src/core/createRenderCoordinator.ts","../src/config/defaults.ts","../src/themes/darkTheme.ts","../src/themes/lightTheme.ts","../src/themes/index.ts","../src/config/OptionResolver.ts","../src/components/createDataZoomSlider.ts","../src/utils/checkWebGPU.ts","../src/ChartGPU.ts","../src/interaction/createChartSync.ts","../src/interaction/createAnnotationHitTester.ts","../src/interaction/createAnnotationDragHandler.ts","../src/components/createAnnotationConfigDialog.ts","../src/interaction/createAnnotationAuthoring.ts","../src/core/RenderScheduler.ts","../src/index.ts"],"sourcesContent":["/**\n * GPUContext - WebGPU device and adapter management\n * \n * Handles WebGPU initialization, adapter selection, and device creation\n * following WebGPU best practices for resource management and error handling.\n * \n * This module provides both functional and class-based APIs for maximum flexibility.\n */\n\n/** Canvas types supported by GPUContext. */\nexport type SupportedCanvas = HTMLCanvasElement;\n\n/** Options for GPU context initialization. */\nexport interface GPUContextOptions {\n /** DPR for high-DPI displays. Auto-detects on main thread, defaults to 1.0 in workers. */\n readonly devicePixelRatio?: number;\n /** Canvas alpha mode. Default: 'opaque' (faster, no transparency). */\n readonly alphaMode?: 'opaque' | 'premultiplied';\n /** GPU power preference for adapter selection. */\n readonly powerPreference?: 'low-power' | 'high-performance';\n}\n\n/**\n * Represents the state of a GPU context.\n * All properties are readonly to ensure immutability.\n */\nexport interface GPUContextState {\n readonly adapter: GPUAdapter | null;\n readonly device: GPUDevice | null;\n readonly initialized: boolean;\n readonly canvas: HTMLCanvasElement | null;\n readonly canvasContext: GPUCanvasContext | null;\n readonly preferredFormat: GPUTextureFormat | null;\n readonly devicePixelRatio: number;\n readonly alphaMode: 'opaque' | 'premultiplied';\n readonly powerPreference: 'low-power' | 'high-performance';\n}\n\n/** Reliable type guard - instanceof works in workers where HTMLCanvasElement is undefined. */\nexport function isHTMLCanvasElement(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement {\n return typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement;\n}\n\n/** Gets display dimensions - clientWidth/Height for HTMLCanvasElement */\nfunction getCanvasDimensions(canvas: HTMLCanvasElement): { width: number; height: number } {\n // Prefer clientWidth/clientHeight (CSS pixels) for HTMLCanvasElement as they reflect actual display size\n // Fall back to canvas.width/height (device pixels) if client dimensions are 0 or invalid\n const width = canvas.clientWidth || canvas.width || 0;\n const height = canvas.clientHeight || canvas.height || 0;\n \n // Validate dimensions are finite and non-negative\n // Note: 0 dimensions are allowed here - they'll be clamped to 1 during GPUContext initialization\n if (!Number.isFinite(width) || !Number.isFinite(height)) {\n throw new Error(\n `GPUContext: Invalid canvas dimensions detected: width=${canvas.clientWidth || canvas.width}, ` +\n `height=${canvas.clientHeight || canvas.height}. ` +\n `Canvas must have finite dimensions. Ensure canvas is properly sized before initialization.`\n );\n }\n \n return { width, height };\n\n}\n\n/**\n * Creates a new GPUContext state with initial values.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n * @returns A new GPUContextState instance\n */\nexport function createGPUContext(\n canvas?: HTMLCanvasElement,\n options?: GPUContextOptions\n): GPUContextState {\n // Auto-detect DPR on main thread, default to 1.0 in workers\n const dprRaw =\n options?.devicePixelRatio ?? (typeof window !== 'undefined' ? window.devicePixelRatio : 1.0);\n // Be resilient: callers may pass 0/NaN/Infinity. Fall back to 1 instead of throwing.\n const dpr = Number.isFinite(dprRaw) && dprRaw > 0 ? dprRaw : 1.0;\n const alphaMode = options?.alphaMode ?? 'opaque';\n const powerPreference = options?.powerPreference ?? 'high-performance';\n \n return {\n adapter: null,\n device: null,\n initialized: false,\n canvas: canvas || null,\n canvasContext: null,\n preferredFormat: null,\n devicePixelRatio: dpr,\n alphaMode,\n powerPreference,\n };\n}\n\n/**\n * Initializes the WebGPU context by requesting an adapter and device.\n * Returns a new state object with initialized values.\n * \n * @param context - The GPU context state to initialize\n * @returns A new GPUContextState with initialized adapter and device\n * @throws {Error} If WebGPU is not available in the browser\n * @throws {Error} If adapter request fails\n * @throws {Error} If device request fails\n * @throws {Error} If already initialized\n */\nexport async function initializeGPUContext(\n context: GPUContextState\n): Promise<GPUContextState> {\n if (context.initialized) {\n throw new Error('GPUContext is already initialized. Call destroyGPUContext() before reinitializing.');\n }\n\n // Be resilient: callers may construct GPUContextState manually.\n const sanitizedDevicePixelRatio =\n Number.isFinite(context.devicePixelRatio) && context.devicePixelRatio > 0 ? context.devicePixelRatio : 1.0;\n\n // Check for WebGPU support\n if (!navigator.gpu) {\n throw new Error(\n 'WebGPU is not available in this browser. ' +\n 'Please use a browser that supports WebGPU (Chrome 113+, Edge 113+, or Safari 18+). ' +\n 'Ensure WebGPU is enabled in browser flags if needed.'\n );\n }\n\n let device: GPUDevice | null = null;\n\n try {\n // Request adapter with power preference from context\n const adapter = await navigator.gpu.requestAdapter({\n powerPreference: context.powerPreference,\n });\n\n if (!adapter) {\n throw new Error(\n 'Failed to request WebGPU adapter. ' +\n 'No compatible adapter found. This may occur if no GPU is available or WebGPU is disabled.'\n );\n }\n\n // Request device from adapter\n device = await adapter.requestDevice();\n\n if (!device) {\n throw new Error('Failed to request WebGPU device from adapter.');\n }\n\n // Set up device lost handler for error recovery\n device.addEventListener('uncapturederror', (event: GPUUncapturedErrorEvent) => {\n console.error('WebGPU uncaptured error:', event.error);\n });\n\n let canvasContext: GPUCanvasContext | null = null;\n let preferredFormat: GPUTextureFormat | null = null;\n\n // Configure canvas if provided\n if (context.canvas) {\n const webgpuContext = context.canvas.getContext('webgpu') as GPUCanvasContext | null;\n \n if (!webgpuContext) {\n // Clean up device before throwing\n try {\n device.destroy();\n } catch (error) {\n console.warn('Error destroying device during canvas setup failure:', error);\n }\n throw new Error('Failed to get WebGPU context from canvas.');\n }\n\n // Use DPR from context state (set at context creation)\n const { width, height } = getCanvasDimensions(context.canvas);\n const dpr = sanitizedDevicePixelRatio;\n \n // Calculate target dimensions in device pixels\n // Note: width/height from getCanvasDimensions are in CSS pixels for HTMLCanvasElement,\n // or device pixels (already set by main thread)\n const targetWidth = Math.floor(width * dpr);\n const targetHeight = Math.floor(height * dpr);\n\n // Clamp to device limits (must happen after device creation)\n const maxDim = device.limits.maxTextureDimension2D;\n const finalWidth = Math.max(1, Math.min(targetWidth, maxDim));\n const finalHeight = Math.max(1, Math.min(targetHeight, maxDim));\n \n context.canvas.width = finalWidth;\n context.canvas.height = finalHeight;\n\n // Get preferred format from navigator.gpu, fallback to bgra8unorm\n preferredFormat = navigator.gpu.getPreferredCanvasFormat?.() || 'bgra8unorm';\n\n // Configure the canvas context with alpha mode from context state\n webgpuContext.configure({\n device: device,\n format: preferredFormat,\n alphaMode: context.alphaMode,\n });\n\n canvasContext = webgpuContext;\n }\n\n return {\n adapter,\n device,\n initialized: true,\n canvas: context.canvas,\n canvasContext,\n preferredFormat,\n devicePixelRatio: sanitizedDevicePixelRatio,\n alphaMode: context.alphaMode,\n powerPreference: context.powerPreference,\n };\n } catch (error) {\n // If a device was created but initialization failed, destroy it to avoid leaks.\n if (device) {\n try {\n device.destroy();\n } catch (destroyError) {\n console.warn('Error destroying device during initialization failure:', destroyError);\n }\n }\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to initialize GPUContext: ${String(error)}`);\n }\n}\n\n/**\n * Gets the current texture from the canvas context.\n * \n * @param context - The GPU context state\n * @returns The current canvas texture\n * @throws {Error} If canvas is not configured or context is not initialized\n * \n * @example\n * ```typescript\n * const texture = getCanvasTexture(context);\n * // Use texture in render pass\n * ```\n */\nexport function getCanvasTexture(context: GPUContextState): GPUTexture {\n if (!context.canvas) {\n throw new Error('Canvas is not configured. Provide a canvas element when creating the context.');\n }\n\n if (!context.initialized || !context.canvasContext) {\n throw new Error('GPUContext is not initialized. Call initializeGPUContext() first.');\n }\n\n return context.canvasContext.getCurrentTexture();\n}\n\n/**\n * Clears the canvas to a solid color.\n * Creates a command encoder, begins a render pass with the specified clear color,\n * ends the pass, and submits it to the queue.\n * \n * @param context - The GPU context state\n * @param r - Red component (0.0 to 1.0)\n * @param g - Green component (0.0 to 1.0)\n * @param b - Blue component (0.0 to 1.0)\n * @param a - Alpha component (0.0 to 1.0)\n * @throws {Error} If canvas is not configured or context is not initialized\n * @throws {Error} If device is not available\n * \n * @example\n * ```typescript\n * // Clear to dark purple (#1a1a2e)\n * clearScreen(context, 0x1a / 255, 0x1a / 255, 0x2e / 255, 1.0);\n * ```\n */\nexport function clearScreen(\n context: GPUContextState,\n r: number,\n g: number,\n b: number,\n a: number\n): void {\n // Validate color component ranges\n if (r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1 || a < 0 || a > 1) {\n throw new Error('Color components must be in the range [0.0, 1.0]');\n }\n\n if (!context.canvas) {\n throw new Error('Canvas is not configured. Provide a canvas element when creating the context.');\n }\n\n if (!context.initialized || !context.device || !context.canvasContext) {\n throw new Error('GPUContext is not initialized. Call initializeGPUContext() first.');\n }\n\n // Get the current texture from the canvas\n const texture = getCanvasTexture(context);\n\n // Create command encoder\n const encoder = context.device.createCommandEncoder();\n\n // Begin render pass with clear color\n const renderPass = encoder.beginRenderPass({\n colorAttachments: [\n {\n view: texture.createView(),\n clearValue: { r, g, b, a },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n });\n\n // End render pass\n renderPass.end();\n\n // Submit command buffer to queue\n context.device.queue.submit([encoder.finish()]);\n}\n\n/**\n * Destroys the WebGPU device and cleans up resources.\n * Returns a new state object with reset values.\n * After calling this, the context must be reinitialized before use.\n * \n * @param context - The GPU context state to destroy\n * @returns A new GPUContextState with reset values\n */\nexport function destroyGPUContext(context: GPUContextState): GPUContextState {\n if (context.device) {\n try {\n context.device.destroy();\n } catch (error) {\n console.warn('Error destroying GPU device:', error);\n }\n }\n\n return {\n adapter: null,\n device: null,\n initialized: false,\n canvas: context.canvas,\n canvasContext: null,\n preferredFormat: null,\n devicePixelRatio: context.devicePixelRatio,\n alphaMode: context.alphaMode,\n powerPreference: context.powerPreference,\n };\n}\n\n/**\n * Convenience function that creates and initializes a GPU context in one step.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n * @returns A fully initialized GPUContextState\n * @throws {Error} If initialization fails\n * \n * @example\n * ```typescript\n * const context = await createGPUContextAsync();\n * const device = context.device;\n * ```\n * \n * @example\n * ```typescript\n * const canvas = document.querySelector('canvas');\n * const context = await createGPUContextAsync(canvas);\n * const texture = getCanvasTexture(context);\n * ```\n */\nexport async function createGPUContextAsync(\n canvas?: HTMLCanvasElement,\n options?: GPUContextOptions\n): Promise<GPUContextState> {\n const context = createGPUContext(canvas, options);\n return initializeGPUContext(context);\n}\n\n/**\n * GPUContext class wrapper for backward compatibility.\n * \n * This class provides a class-based API that internally uses the functional implementation.\n * Use the functional API directly for better type safety and immutability.\n */\nexport class GPUContext {\n private _state: GPUContextState;\n\n /**\n * Gets the WebGPU adapter, or null if not initialized.\n */\n get adapter(): GPUAdapter | null {\n return this._state.adapter;\n }\n\n /**\n * Gets the WebGPU device, or null if not initialized.\n */\n get device(): GPUDevice | null {\n return this._state.device;\n }\n\n /**\n * Checks if the context has been initialized.\n */\n get initialized(): boolean {\n return this._state.initialized;\n }\n\n /**\n * Gets the canvas element, or null if not provided.\n */\n get canvas(): SupportedCanvas | null {\n return this._state.canvas;\n }\n\n /**\n * Gets the WebGPU canvas context, or null if canvas is not configured.\n */\n get canvasContext(): GPUCanvasContext | null {\n return this._state.canvasContext;\n }\n\n /**\n * Gets the preferred canvas format, or null if canvas is not configured.\n */\n get preferredFormat(): GPUTextureFormat | null {\n return this._state.preferredFormat;\n }\n\n /**\n * Gets the device pixel ratio used for canvas sizing.\n */\n get devicePixelRatio(): number {\n return this._state.devicePixelRatio;\n }\n\n /**\n * Gets the canvas alpha mode.\n */\n get alphaMode(): 'opaque' | 'premultiplied' {\n return this._state.alphaMode;\n }\n\n /**\n * Gets the GPU power preference.\n */\n get powerPreference(): 'low-power' | 'high-performance' {\n return this._state.powerPreference;\n }\n\n /**\n * Creates a new GPUContext instance.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n */\n constructor(canvas?: HTMLCanvasElement, options?: GPUContextOptions) {\n this._state = createGPUContext(canvas, options);\n }\n\n /**\n * Initializes the WebGPU context by requesting an adapter and device.\n * \n * @throws {Error} If WebGPU is not available in the browser\n * @throws {Error} If adapter request fails\n * @throws {Error} If device request fails\n * @throws {Error} If already initialized\n */\n async initialize(): Promise<void> {\n this._state = await initializeGPUContext(this._state);\n }\n\n /**\n * Static factory method to create and initialize a GPUContext instance.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n * @returns A fully initialized GPUContext instance\n * @throws {Error} If initialization fails\n * \n * @example\n * ```typescript\n * const context = await GPUContext.create();\n * const device = context.device;\n * ```\n * \n * @example\n * ```typescript\n * const canvas = document.querySelector('canvas');\n * const context = await GPUContext.create(canvas);\n * const texture = context.getCanvasTexture();\n * ```\n */\n static async create(canvas?: HTMLCanvasElement, options?: GPUContextOptions): Promise<GPUContext> {\n const context = new GPUContext(canvas, options);\n await context.initialize();\n return context;\n }\n\n /**\n * Gets the current texture from the canvas context.\n * \n * @returns The current canvas texture\n * @throws {Error} If canvas is not configured or context is not initialized\n * \n * @example\n * ```typescript\n * const texture = context.getCanvasTexture();\n * // Use texture in render pass\n * ```\n */\n getCanvasTexture(): GPUTexture {\n return getCanvasTexture(this._state);\n }\n\n /**\n * Clears the canvas to a solid color.\n * Creates a command encoder, begins a render pass with the specified clear color,\n * ends the pass, and submits it to the queue.\n * \n * @param r - Red component (0.0 to 1.0)\n * @param g - Green component (0.0 to 1.0)\n * @param b - Blue component (0.0 to 1.0)\n * @param a - Alpha component (0.0 to 1.0)\n * @throws {Error} If canvas is not configured or context is not initialized\n * @throws {Error} If device is not available\n * \n * @example\n * ```typescript\n * // Clear to dark purple (#1a1a2e)\n * context.clearScreen(0x1a / 255, 0x1a / 255, 0x2e / 255, 1.0);\n * ```\n */\n clearScreen(r: number, g: number, b: number, a: number): void {\n clearScreen(this._state, r, g, b, a);\n }\n\n /**\n * Destroys the WebGPU device and cleans up resources.\n * After calling destroy(), the context must be reinitialized before use.\n */\n destroy(): void {\n this._state = destroyGPUContext(this._state);\n }\n}\n","/**\n * Data point packing utilities for GPU buffer uploads.\n * \n * Internal utilities that convert high-level DataPoint/OHLCDataPoint arrays into\n * interleaved Float32Array buffers suitable for direct GPU buffer uploads via\n * `queue.writeBuffer()`.\n * \n * @module packDataPoints\n * @internal\n */\n\nimport type { DataPoint, OHLCDataPoint, DataPointTuple } from '../config/types';\nimport type { OHLCDataPointTuple, OHLCDataPointObject } from '../config/types';\n\n/**\n * Type guard to check if a DataPoint is in tuple form.\n */\nfunction isTupleDataPoint(point: DataPoint): point is DataPointTuple {\n return Array.isArray(point);\n}\n\n/**\n * Type guard to check if an OHLCDataPoint is in tuple form.\n */\nfunction isOHLCTuple(point: OHLCDataPoint): point is OHLCDataPointTuple {\n return Array.isArray(point);\n}\n\n/**\n * Packs DataPoint array into an interleaved Float32Array for GPU buffer uploads.\n * \n * **Internal utility** used by data store for efficient GPU buffer management.\n * \n * **Format**: `[x0, y0, x1, y1, x2, y2, ...]` (2 floats per point = 8 bytes stride)\n * \n * @param points - Array of data points (tuple or object form)\n * @returns Interleaved Float32Array [x0,y0,x1,y1,...] for GPU vertex buffer upload\n * @throws {TypeError} If points is null, undefined, or not an array\n * @throws {RangeError} If points array is empty or contains invalid values\n * @internal\n * \n * @example\n * ```typescript\n * const points = [{ x: 0, y: 10 }, { x: 1, y: 20 }];\n * const packed = packDataPoints(points);\n * // packed = Float32Array[0, 10, 1, 20]\n * \n * // Upload to GPU buffer:\n * device.queue.writeBuffer(vertexBuffer, 0, packed.buffer);\n * ```\n */\nexport function packDataPoints(points: ReadonlyArray<DataPoint>): Float32Array {\n // Input validation\n if (!points) {\n throw new TypeError('packDataPoints: points parameter is required');\n }\n \n if (!Array.isArray(points)) {\n throw new TypeError('packDataPoints: points must be an array');\n }\n \n if (points.length === 0) {\n // Return empty array for empty input (valid case)\n return new Float32Array(0);\n }\n \n // Validate array length doesn't exceed safe limits\n // Max safe array size: ~2GB / 8 bytes = 268M points\n const MAX_POINTS = 268_435_456; // 2^28 points = 2GB buffer\n if (points.length > MAX_POINTS) {\n throw new RangeError(\n `packDataPoints: points array too large (${points.length} points). ` +\n `Maximum supported: ${MAX_POINTS.toLocaleString()} points (2GB buffer limit)`\n );\n }\n\n // Allocate buffer: 2 floats per point × 4 bytes per float = 8 bytes per point\n const buffer = new ArrayBuffer(points.length * 2 * 4);\n const f32 = new Float32Array(buffer);\n\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n \n // Validate point is not null/undefined\n if (point === null || point === undefined) {\n throw new TypeError(\n `packDataPoints: Invalid point at index ${i}. ` +\n `Expected DataPoint (tuple or object), got ${point}`\n );\n }\n \n const x = isTupleDataPoint(point) ? point[0] : point.x;\n const y = isTupleDataPoint(point) ? point[1] : point.y;\n \n // Validate numeric values (catches NaN, undefined properties)\n if (typeof x !== 'number' || typeof y !== 'number') {\n throw new TypeError(\n `packDataPoints: Invalid coordinate values at index ${i}. ` +\n `Expected numbers, got x=${typeof x}, y=${typeof y}`\n );\n }\n \n // Note: NaN and Infinity are valid Float32 values and will be preserved\n // If you need to reject them, add additional checks here\n \n f32[i * 2 + 0] = x;\n f32[i * 2 + 1] = y;\n }\n\n return f32;\n}\n\n/**\n * Packs OHLCDataPoint array into an interleaved Float32Array for GPU buffer uploads.\n * \n * **Internal utility** used by data store for efficient candlestick GPU buffer management.\n * \n * **Format**: `[t0, o0, h0, l0, c0, t1, o1, h1, l1, c1, ...]` (5 floats per point = 20 bytes stride)\n * \n * Order follows ECharts convention: timestamp, open, high, low, close (t, o, h, l, c).\n * \n * @param points - Array of OHLC data points (tuple or object form)\n * @returns Interleaved Float32Array [t0,o0,h0,l0,c0,t1,...] for GPU vertex buffer upload\n * @throws {TypeError} If points is null, undefined, or not an array\n * @throws {RangeError} If points array is empty or contains invalid values\n * @internal\n * \n * @example\n * ```typescript\n * const ohlcPoints = [\n * { timestamp: 1000, open: 100, high: 110, low: 95, close: 105 },\n * { timestamp: 2000, open: 105, high: 115, low: 100, close: 110 }\n * ];\n * const packed = packOHLCDataPoints(ohlcPoints);\n * // packed = Float32Array[1000, 100, 110, 95, 105, 2000, 105, 115, 100, 110]\n * \n * // Upload to GPU buffer:\n * device.queue.writeBuffer(vertexBuffer, 0, packed.buffer);\n * ```\n */\nexport function packOHLCDataPoints(points: ReadonlyArray<OHLCDataPoint>): Float32Array {\n // Input validation\n if (!points) {\n throw new TypeError('packOHLCDataPoints: points parameter is required');\n }\n \n if (!Array.isArray(points)) {\n throw new TypeError('packOHLCDataPoints: points must be an array');\n }\n \n if (points.length === 0) {\n // Return empty array for empty input (valid case)\n return new Float32Array(0);\n }\n \n // Validate array length doesn't exceed safe limits\n // Max safe array size: ~2GB / 20 bytes = 107M points\n const MAX_POINTS = 107_374_182; // 2^30 / 10 points = ~2GB buffer\n if (points.length > MAX_POINTS) {\n throw new RangeError(\n `packOHLCDataPoints: points array too large (${points.length} points). ` +\n `Maximum supported: ${MAX_POINTS.toLocaleString()} points (2GB buffer limit)`\n );\n }\n\n // Allocate buffer: 5 floats per point × 4 bytes per float = 20 bytes per point\n const buffer = new ArrayBuffer(points.length * 5 * 4);\n const f32 = new Float32Array(buffer);\n\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n \n // Validate point is not null/undefined\n if (point === null || point === undefined) {\n throw new TypeError(\n `packOHLCDataPoints: Invalid point at index ${i}. ` +\n `Expected OHLCDataPoint (tuple or object), got ${point}`\n );\n }\n \n if (isOHLCTuple(point)) {\n // Tuple form: [timestamp, open, close, low, high]\n // NOTE: ECharts convention is [t, o, c, l, h] but we store as [t, o, h, l, c]\n \n // Validate tuple has 5 elements\n if (point.length !== 5) {\n throw new TypeError(\n `packOHLCDataPoints: Invalid OHLC tuple at index ${i}. ` +\n `Expected 5 elements [timestamp, open, close, low, high], got ${point.length}`\n );\n }\n \n const timestamp = point[0];\n const open = point[1];\n const close = point[2];\n const low = point[3];\n const high = point[4];\n \n // Validate all values are numbers\n if (typeof timestamp !== 'number' || typeof open !== 'number' || \n typeof close !== 'number' || typeof low !== 'number' || typeof high !== 'number') {\n throw new TypeError(\n `packOHLCDataPoints: Invalid OHLC values at index ${i}. ` +\n `All values must be numbers, got [${typeof timestamp}, ${typeof open}, ${typeof close}, ${typeof low}, ${typeof high}]`\n );\n }\n \n f32[i * 5 + 0] = timestamp;\n f32[i * 5 + 1] = open;\n f32[i * 5 + 2] = high; // Reorder: high comes from index 4\n f32[i * 5 + 3] = low; // Reorder: low from index 3\n f32[i * 5 + 4] = close; // Reorder: close from index 2\n } else {\n // Object form: { timestamp, open, close, low, high }\n const ohlcObj = point as OHLCDataPointObject;\n \n const { timestamp, open, high, low, close } = ohlcObj;\n \n // Validate all required properties exist and are numbers\n if (typeof timestamp !== 'number' || typeof open !== 'number' || \n typeof high !== 'number' || typeof low !== 'number' || typeof close !== 'number') {\n throw new TypeError(\n `packOHLCDataPoints: Invalid OHLC object at index ${i}. ` +\n `All properties (timestamp, open, high, low, close) must be numbers, got ` +\n `{timestamp: ${typeof timestamp}, open: ${typeof open}, high: ${typeof high}, low: ${typeof low}, close: ${typeof close}}`\n );\n }\n \n f32[i * 5 + 0] = timestamp;\n f32[i * 5 + 1] = open;\n f32[i * 5 + 2] = high;\n f32[i * 5 + 3] = low;\n f32[i * 5 + 4] = close;\n }\n }\n\n return f32;\n}\n","import type { DataPoint, DataPointTuple } from '../config/types';\nimport { packDataPoints } from './packDataPoints';\n\nexport interface DataStore {\n setSeries(\n index: number,\n data: ReadonlyArray<DataPoint>,\n options?: Readonly<{ xOffset?: number }>\n ): void;\n /**\n * Appends new points to an existing series without re-uploading the entire buffer when possible.\n *\n * - Reuses the same geometric growth policy as `setSeries`.\n * - When no reallocation is needed, writes only the appended byte range via `queue.writeBuffer(...)`.\n * - Maintains `pointCount` and a CPU-side combined data array so `getSeriesData(...)` remains correct.\n *\n * Throws if the series has not been set yet.\n */\n appendSeries(index: number, newPoints: ReadonlyArray<DataPoint>): void;\n removeSeries(index: number): void;\n getSeriesBuffer(index: number): GPUBuffer;\n /**\n * Returns the number of points last set for the given series index.\n *\n * Throws if the series has not been set yet.\n */\n getSeriesPointCount(index: number): number;\n /**\n * Returns the last CPU-side data set for the given series index.\n *\n * This is intended for internal metadata/hit-testing paths that need the same\n * input array that was packed into the GPU buffer (without re-threading it\n * through other state). Throws if the series has not been set yet.\n */\n getSeriesData(index: number): ReadonlyArray<DataPoint>;\n dispose(): void;\n}\n\ntype SeriesEntry = {\n readonly buffer: GPUBuffer;\n readonly capacityBytes: number;\n readonly pointCount: number;\n readonly hash32: number;\n /**\n * X-origin subtracted during packing to preserve Float32 precision for large-magnitude domains\n * (e.g. epoch-ms time axes). Stored so appendSeries can pack consistently.\n */\n readonly xOffset: number;\n // Store a mutable array so streaming append can update in-place.\n readonly data: DataPoint[];\n};\n\nconst MIN_BUFFER_BYTES = 4;\n\nfunction roundUpToMultipleOf4(bytes: number): number {\n return (bytes + 3) & ~3;\n}\n\nfunction nextPow2(bytes: number): number {\n if (!Number.isFinite(bytes) || bytes <= 0) return 1;\n const n = Math.ceil(bytes);\n return 2 ** Math.ceil(Math.log2(n));\n}\n\nfunction computeGrownCapacityBytes(currentCapacityBytes: number, requiredBytes: number): number {\n // Grow geometrically to reduce buffer churn (power-of-two policy).\n // Enforce 4-byte alignment via MIN_BUFFER_BYTES (>= 4) and power-of-two growth.\n const required = Math.max(MIN_BUFFER_BYTES, roundUpToMultipleOf4(requiredBytes));\n const grown = Math.max(MIN_BUFFER_BYTES, nextPow2(required));\n return Math.max(currentCapacityBytes, grown);\n}\n\nfunction fnv1aUpdate(hash: number, words: Uint32Array): number {\n let h = hash >>> 0;\n for (let i = 0; i < words.length; i++) {\n h ^= words[i]!;\n h = Math.imul(h, 0x01000193) >>> 0; // FNV prime\n }\n return h >>> 0;\n}\n\n/**\n * Computes a stable 32-bit hash of the Float32 contents using their IEEE-754\n * bit patterns (not numeric equality), to cheaply detect changes.\n */\nfunction hashFloat32ArrayBits(data: Float32Array): number {\n const u32 = new Uint32Array(data.buffer, data.byteOffset, data.byteLength / 4);\n return fnv1aUpdate(0x811c9dc5, u32); // FNV-1a offset basis\n}\n\nexport function createDataStore(device: GPUDevice): DataStore {\n const series = new Map<number, SeriesEntry>();\n let disposed = false;\n\n // Type guard (avoid relying on Array.isArray narrowing for readonly tuples in strict TS configs).\n const isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\n const packDataPointsWithXOffset = (points: ReadonlyArray<DataPoint>, xOffset: number): Float32Array => {\n if (!points || points.length === 0) return new Float32Array(0);\n\n const buffer = new ArrayBuffer(points.length * 2 * 4);\n const f32 = new Float32Array(buffer);\n\n // Hot path: keep logic minimal (validation happens elsewhere in option resolution).\n for (let i = 0; i < points.length; i++) {\n const p = points[i]!;\n const x = isTupleDataPoint(p) ? p[0] : p.x;\n const y = isTupleDataPoint(p) ? p[1] : p.y;\n\n // Subtracting before the Float32 cast preserves sub-ULP deltas for large x magnitudes.\n f32[i * 2 + 0] = x - xOffset;\n f32[i * 2 + 1] = y;\n }\n\n return f32;\n };\n\n const assertNotDisposed = (): void => {\n if (disposed) {\n throw new Error('DataStore is disposed.');\n }\n };\n\n const getSeriesEntry = (index: number): SeriesEntry => {\n assertNotDisposed();\n const entry = series.get(index);\n if (!entry) {\n throw new Error(`Series ${index} has no data. Call setSeries(${index}, data) first.`);\n }\n return entry;\n };\n\n const setSeries = (index: number, data: ReadonlyArray<DataPoint>, options?: Readonly<{ xOffset?: number }>): void => {\n assertNotDisposed();\n\n const xOffset = options?.xOffset ?? 0;\n const packed = xOffset === 0 ? packDataPoints(data) : packDataPointsWithXOffset(data, xOffset);\n const pointCount = data.length;\n const hash32 = hashFloat32ArrayBits(packed);\n\n const requiredBytes = roundUpToMultipleOf4(packed.byteLength);\n const targetBytes = Math.max(MIN_BUFFER_BYTES, requiredBytes);\n\n const existing = series.get(index);\n const unchanged = existing && existing.pointCount === pointCount && existing.hash32 === hash32;\n if (unchanged) return;\n\n let buffer = existing?.buffer ?? null;\n let capacityBytes = existing?.capacityBytes ?? 0;\n\n if (!buffer || targetBytes > capacityBytes) {\n const maxBufferSize = device.limits.maxBufferSize;\n if (targetBytes > maxBufferSize) {\n throw new Error(\n `DataStore.setSeries(${index}): required buffer size ${targetBytes} exceeds device.limits.maxBufferSize (${maxBufferSize}).`\n );\n }\n\n if (buffer) {\n try {\n buffer.destroy();\n } catch {\n // Ignore destroy errors; we are replacing the buffer anyway.\n }\n }\n\n const grownCapacityBytes = computeGrownCapacityBytes(capacityBytes, targetBytes);\n if (grownCapacityBytes > maxBufferSize) {\n // If geometric growth would exceed the limit, fall back to the exact required size.\n // (Still no shrink: if current capacity was already larger, we'd keep it above.)\n // NOTE: targetBytes is already checked against maxBufferSize above.\n capacityBytes = targetBytes;\n } else {\n capacityBytes = grownCapacityBytes;\n }\n\n buffer = device.createBuffer({\n size: capacityBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n }\n\n // Avoid 0-byte writes (empty series). The buffer is still valid for binding.\n if (packed.byteLength > 0) {\n device.queue.writeBuffer(buffer, 0, packed.buffer);\n }\n\n series.set(index, {\n buffer,\n capacityBytes,\n pointCount,\n hash32,\n xOffset,\n data: data.length === 0 ? [] : data.slice(),\n });\n };\n\n const appendSeries = (index: number, newPoints: ReadonlyArray<DataPoint>): void => {\n assertNotDisposed();\n if (!newPoints || newPoints.length === 0) return;\n\n const existing = getSeriesEntry(index);\n const prevPointCount = existing.pointCount;\n const nextPointCount = prevPointCount + newPoints.length;\n\n const appendPacked =\n existing.xOffset === 0 ? packDataPoints(newPoints) : packDataPointsWithXOffset(newPoints, existing.xOffset);\n const appendBytes = appendPacked.byteLength;\n\n // Each point is 2 floats (x, y) = 8 bytes.\n const requiredBytes = roundUpToMultipleOf4(nextPointCount * 2 * 4);\n const targetBytes = Math.max(MIN_BUFFER_BYTES, requiredBytes);\n\n let buffer = existing.buffer;\n let capacityBytes = existing.capacityBytes;\n\n // Ensure the CPU-side store is updated regardless of GPU growth path.\n const nextData = existing.data;\n nextData.push(...newPoints);\n\n const maxBufferSize = device.limits.maxBufferSize;\n\n if (targetBytes > capacityBytes) {\n if (targetBytes > maxBufferSize) {\n throw new Error(\n `DataStore.appendSeries(${index}): required buffer size ${targetBytes} exceeds device.limits.maxBufferSize (${maxBufferSize}).`\n );\n }\n\n // Replace buffer (no shrink). This is the slow path; we re-upload the full series.\n try {\n buffer.destroy();\n } catch {\n // Ignore destroy errors; we are replacing the buffer anyway.\n }\n\n const grownCapacityBytes = computeGrownCapacityBytes(capacityBytes, targetBytes);\n capacityBytes = grownCapacityBytes > maxBufferSize ? targetBytes : grownCapacityBytes;\n\n buffer = device.createBuffer({\n size: capacityBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n\n const fullPacked =\n existing.xOffset === 0 ? packDataPoints(nextData) : packDataPointsWithXOffset(nextData, existing.xOffset);\n if (fullPacked.byteLength > 0) {\n device.queue.writeBuffer(buffer, 0, fullPacked.buffer);\n }\n\n series.set(index, {\n buffer,\n capacityBytes,\n pointCount: nextPointCount,\n hash32: hashFloat32ArrayBits(fullPacked),\n xOffset: existing.xOffset,\n data: nextData,\n });\n return;\n }\n\n // Fast path: write only the appended range into the existing buffer.\n if (appendBytes > 0) {\n const byteOffset = prevPointCount * 2 * 4;\n device.queue.writeBuffer(buffer, byteOffset, appendPacked.buffer);\n }\n\n // Incremental FNV-1a update over the appended IEEE-754 bit patterns.\n const appendWords = new Uint32Array(appendPacked.buffer, appendPacked.byteOffset, appendPacked.byteLength / 4);\n const nextHash32 = fnv1aUpdate(existing.hash32, appendWords);\n\n series.set(index, {\n buffer,\n capacityBytes,\n pointCount: nextPointCount,\n hash32: nextHash32,\n xOffset: existing.xOffset,\n data: nextData,\n });\n };\n\n const removeSeries = (index: number): void => {\n assertNotDisposed();\n\n const entry = series.get(index);\n if (!entry) return;\n\n try {\n entry.buffer.destroy();\n } catch {\n // Ignore destroy errors; removal should be best-effort.\n }\n series.delete(index);\n };\n\n const getSeriesBuffer = (index: number): GPUBuffer => {\n return getSeriesEntry(index).buffer;\n };\n\n const getSeriesPointCount = (index: number): number => {\n return getSeriesEntry(index).pointCount;\n };\n\n const getSeriesData = (index: number): ReadonlyArray<DataPoint> => {\n return getSeriesEntry(index).data;\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n\n for (const entry of series.values()) {\n try {\n entry.buffer.destroy();\n } catch {\n // Ignore destroy errors; disposal should be best-effort.\n }\n }\n series.clear();\n };\n\n return {\n setSeries,\n appendSeries,\n removeSeries,\n getSeriesBuffer,\n getSeriesPointCount,\n getSeriesData,\n dispose,\n };\n}\n\n","import type { DataPoint, DataPointTuple } from '../config/types';\n\nfunction isTupleDataPoint(point: DataPoint): point is DataPointTuple {\n // `DataPoint` uses a readonly tuple; `Array.isArray` doesn't narrow it well without a predicate.\n return Array.isArray(point);\n}\n\nfunction lttbIndicesForInterleavedXY(data: Float32Array, targetPoints: number): Int32Array {\n const n = data.length >>> 1; // floor(length / 2)\n const lastIndex = n - 1;\n\n if (targetPoints <= 0 || n === 0) return new Int32Array(0);\n if (targetPoints === 1) return new Int32Array([0]);\n if (targetPoints === 2) return n >= 2 ? new Int32Array([0, lastIndex]) : new Int32Array([0]);\n if (n <= targetPoints) {\n const indices = new Int32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n return indices;\n }\n\n const indices = new Int32Array(targetPoints);\n indices[0] = 0;\n indices[targetPoints - 1] = lastIndex;\n\n const bucketSize = (n - 2) / (targetPoints - 2);\n\n let a = 0;\n let out = 1;\n\n const lastX = data[lastIndex * 2 + 0];\n const lastY = data[lastIndex * 2 + 1];\n\n for (let bucket = 0; bucket < targetPoints - 2; bucket++) {\n // Current bucket: candidate points are [rangeStart, rangeEndExclusive) and never include lastIndex.\n let rangeStart = Math.floor(bucketSize * bucket) + 1;\n let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, lastIndex);\n if (rangeStart >= rangeEndExclusive) {\n // Defensive: ensure at least one candidate point.\n rangeStart = Math.min(rangeStart, lastIndex - 1);\n rangeEndExclusive = Math.min(rangeStart + 1, lastIndex);\n }\n\n // Next bucket for average: [nextRangeStart, nextRangeEndExclusive)\n const nextRangeStart = Math.floor(bucketSize * (bucket + 1)) + 1;\n const nextRangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 2)) + 1, lastIndex);\n\n // If there are no points in the next bucket, use the last point as the average.\n let avgX = lastX;\n let avgY = lastY;\n if (nextRangeStart < nextRangeEndExclusive) {\n let sumX = 0;\n let sumY = 0;\n let avgCount = 0;\n for (let i = nextRangeStart; i < nextRangeEndExclusive; i++) {\n sumX += data[i * 2 + 0];\n sumY += data[i * 2 + 1];\n avgCount++;\n }\n if (avgCount > 0) {\n avgX = sumX / avgCount;\n avgY = sumY / avgCount;\n }\n }\n\n const ax = data[a * 2 + 0];\n const ay = data[a * 2 + 1];\n\n let maxArea = -1;\n let maxIndex = rangeStart;\n for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const bx = data[i * 2 + 0];\n const by = data[i * 2 + 1];\n const area2 = (ax - avgX) * (by - ay) - (ax - bx) * (avgY - ay);\n const absArea2 = area2 < 0 ? -area2 : area2;\n if (absArea2 > maxArea) {\n maxArea = absArea2;\n maxIndex = i;\n }\n }\n\n indices[out++] = maxIndex;\n a = maxIndex;\n }\n\n return indices;\n}\n\nfunction lttbIndicesForDataPoints(data: ReadonlyArray<DataPoint>, targetPoints: number): Int32Array {\n const n = data.length;\n const lastIndex = n - 1;\n\n if (targetPoints <= 0 || n === 0) return new Int32Array(0);\n if (targetPoints === 1) return new Int32Array([0]);\n if (targetPoints === 2) return n >= 2 ? new Int32Array([0, lastIndex]) : new Int32Array([0]);\n if (n <= targetPoints) {\n const indices = new Int32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n return indices;\n }\n\n const indices = new Int32Array(targetPoints);\n indices[0] = 0;\n indices[targetPoints - 1] = lastIndex;\n\n const bucketSize = (n - 2) / (targetPoints - 2);\n\n let a = 0;\n let out = 1;\n\n const pLast = data[lastIndex]!;\n const lastX = isTupleDataPoint(pLast) ? pLast[0] : pLast.x;\n const lastY = isTupleDataPoint(pLast) ? pLast[1] : pLast.y;\n\n for (let bucket = 0; bucket < targetPoints - 2; bucket++) {\n // Current bucket: candidate points are [rangeStart, rangeEndExclusive) and never include lastIndex.\n let rangeStart = Math.floor(bucketSize * bucket) + 1;\n let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, lastIndex);\n if (rangeStart >= rangeEndExclusive) {\n // Defensive: ensure at least one candidate point.\n rangeStart = Math.min(rangeStart, lastIndex - 1);\n rangeEndExclusive = Math.min(rangeStart + 1, lastIndex);\n }\n\n // Next bucket for average: [nextRangeStart, nextRangeEndExclusive)\n const nextRangeStart = Math.floor(bucketSize * (bucket + 1)) + 1;\n const nextRangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 2)) + 1, lastIndex);\n\n // If there are no points in the next bucket, use the last point as the average.\n let avgX = lastX;\n let avgY = lastY;\n if (nextRangeStart < nextRangeEndExclusive) {\n let sumX = 0;\n let sumY = 0;\n let avgCount = 0;\n for (let i = nextRangeStart; i < nextRangeEndExclusive; i++) {\n const p = data[i]!;\n const x = isTupleDataPoint(p) ? p[0] : p.x;\n const y = isTupleDataPoint(p) ? p[1] : p.y;\n sumX += x;\n sumY += y;\n avgCount++;\n }\n if (avgCount > 0) {\n avgX = sumX / avgCount;\n avgY = sumY / avgCount;\n }\n }\n\n const pa = data[a]!;\n const ax = isTupleDataPoint(pa) ? pa[0] : pa.x;\n const ay = isTupleDataPoint(pa) ? pa[1] : pa.y;\n\n let maxArea = -1;\n let maxIndex = rangeStart;\n for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const pb = data[i]!;\n const bx = isTupleDataPoint(pb) ? pb[0] : pb.x;\n const by = isTupleDataPoint(pb) ? pb[1] : pb.y;\n const area2 = (ax - avgX) * (by - ay) - (ax - bx) * (avgY - ay);\n const absArea2 = area2 < 0 ? -area2 : area2;\n if (absArea2 > maxArea) {\n maxArea = absArea2;\n maxIndex = i;\n }\n }\n\n indices[out++] = maxIndex;\n a = maxIndex;\n }\n\n return indices;\n}\n\nexport function lttbSample(data: Float32Array, targetPoints: number): Float32Array;\nexport function lttbSample(data: DataPoint[], targetPoints: number): DataPoint[];\nexport function lttbSample(data: ReadonlyArray<DataPoint>, targetPoints: number): ReadonlyArray<DataPoint>;\nexport function lttbSample(\n data: ReadonlyArray<DataPoint> | Float32Array,\n targetPoints: number\n): ReadonlyArray<DataPoint> | Float32Array {\n const threshold = Math.floor(targetPoints);\n\n if (data instanceof Float32Array) {\n const n = data.length >>> 1;\n if (threshold <= 0 || n === 0) return new Float32Array(0);\n\n // If we're already under the target, avoid copying.\n if (n <= threshold) return data;\n\n const indices = lttbIndicesForInterleavedXY(data, threshold);\n const out = new Float32Array(indices.length * 2);\n for (let i = 0; i < indices.length; i++) {\n const idx = indices[i]!;\n out[i * 2 + 0] = data[idx * 2 + 0];\n out[i * 2 + 1] = data[idx * 2 + 1];\n }\n return out;\n }\n\n const n = data.length;\n if (threshold <= 0 || n === 0) return [];\n\n // Story requirement: when data is shorter than the target, return original.\n if (n <= threshold) return data;\n\n const indices = lttbIndicesForDataPoints(data, threshold);\n const out = new Array<DataPoint>(indices.length);\n for (let i = 0; i < indices.length; i++) {\n out[i] = data[indices[i]!]!;\n }\n return out;\n}\n\n","/**\n * Internal cartesian data abstraction for CartesianSeriesData.\n *\n * Provides high-performance, allocation-minimizing primitives to support all three cartesian formats:\n * - ReadonlyArray<DataPoint> (tuple or object)\n * - XYArraysData (separate x/y/size arrays)\n * - InterleavedXYData (typed array view with [x0,y0,x1,y1,...] layout)\n *\n * DO NOT export from public entrypoint (src/index.ts). This is internal-only.\n *\n * @module cartesianData\n * @internal\n */\n\nimport type { CartesianSeriesData, DataPoint, XYArraysData, InterleavedXYData } from '../config/types';\n\n/**\n * Bounds type for min/max x and y values.\n */\nexport type Bounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\n/**\n * Type for typed arrays with numeric indexing (excluding DataView and BigInt arrays).\n * BigInt arrays are excluded because coordinates must be numbers, not bigints.\n */\ntype TypedArray = \n | Int8Array\n | Uint8Array\n | Uint8ClampedArray\n | Int16Array\n | Uint16Array\n | Int32Array\n | Uint32Array\n | Float32Array\n | Float64Array;\n\n/**\n * Type guard for XYArraysData format.\n */\nfunction isXYArraysData(data: CartesianSeriesData): data is XYArraysData {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n 'x' in data &&\n 'y' in data &&\n typeof (data as any).x === 'object' &&\n typeof (data as any).y === 'object' &&\n 'length' in (data as any).x &&\n 'length' in (data as any).y\n );\n}\n\n/**\n * Type guard for InterleavedXYData format (ArrayBufferView).\n */\nfunction isInterleavedXYData(data: CartesianSeriesData): data is InterleavedXYData {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n ArrayBuffer.isView(data)\n );\n}\n\n/**\n * Type guard for tuple DataPoint format.\n */\nfunction isTupleDataPoint(p: DataPoint): p is readonly [number, number, number?] {\n return Array.isArray(p);\n}\n\n/**\n * Returns the number of points in the CartesianSeriesData.\n */\nexport function getPointCount(data: CartesianSeriesData): number {\n if (isXYArraysData(data)) {\n // Use minimum of x and y array lengths for safety\n return Math.min(data.x.length, data.y.length);\n }\n \n if (isInterleavedXYData(data)) {\n // DataView is unsupported - throw clear error\n if (data instanceof DataView) {\n throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n }\n // Interpret pointCount as floor(length/2), tolerant of odd length\n // Cast to typed array with numeric indexing after DataView check\n const arr = data as TypedArray;\n return Math.floor(arr.length / 2);\n }\n \n // ReadonlyArray<DataPoint>\n return data.length;\n}\n\n/**\n * Returns the x-coordinate of the point at index i.\n */\nexport function getX(data: CartesianSeriesData, i: number): number {\n if (isXYArraysData(data)) {\n return data.x[i]!;\n }\n \n if (isInterleavedXYData(data)) {\n if (data instanceof DataView) {\n throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n }\n const arr = data as TypedArray;\n return arr[i * 2]!;\n }\n \n // ReadonlyArray<DataPoint>\n const p = data[i]!;\n return isTupleDataPoint(p) ? p[0] : p.x;\n}\n\n/**\n * Returns the y-coordinate of the point at index i.\n */\nexport function getY(data: CartesianSeriesData, i: number): number {\n if (isXYArraysData(data)) {\n return data.y[i]!;\n }\n \n if (isInterleavedXYData(data)) {\n if (data instanceof DataView) {\n throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n }\n const arr = data as TypedArray;\n return arr[i * 2 + 1]!;\n }\n \n // ReadonlyArray<DataPoint>\n const p = data[i]!;\n return isTupleDataPoint(p) ? p[1] : p.y;\n}\n\n/**\n * Returns the size value of the point at index i, or undefined if not available.\n * Note: InterleavedXYData does NOT support interleaved size (use XYArraysData.size if needed).\n */\nexport function getSize(data: CartesianSeriesData, i: number): number | undefined {\n if (isXYArraysData(data)) {\n return data.size?.[i];\n }\n \n if (isInterleavedXYData(data)) {\n // Size is not interleaved in InterleavedXYData format\n return undefined;\n }\n \n // ReadonlyArray<DataPoint>\n const p = data[i]!;\n return isTupleDataPoint(p) ? p[2] : p.size;\n}\n\n/**\n * Packs XY coordinates from CartesianSeriesData into a Float32Array in interleaved layout.\n * \n * Writes `pointCount` points starting at `srcPointOffset` in the source data\n * into `out` starting at `outFloatOffset` (measured in float32 elements, not bytes).\n * \n * Each point writes 2 floats: [x - xOffset, y].\n * Size dimension is NOT packed (use getSize() separately if needed).\n * \n * @param out - Target Float32Array to write into\n * @param outFloatOffset - Starting offset in `out` (in float32 elements)\n * @param src - Source CartesianSeriesData\n * @param srcPointOffset - Starting point index in source\n * @param pointCount - Number of points to pack\n * @param xOffset - Value to subtract from x coordinates (for Float32 precision preservation)\n */\nexport function packXYInto(\n out: Float32Array,\n outFloatOffset: number,\n src: CartesianSeriesData,\n srcPointOffset: number,\n pointCount: number,\n xOffset: number\n): void {\n const availablePoints = getPointCount(src) - srcPointOffset;\n const actualPointCount = Math.min(pointCount, availablePoints);\n \n if (actualPointCount <= 0) return;\n \n // Validate output buffer capacity\n const requiredOutLength = outFloatOffset + actualPointCount * 2;\n if (requiredOutLength > out.length) {\n throw new Error(\n `packXYInto: output buffer too small (need ${requiredOutLength} floats, have ${out.length})`\n );\n }\n \n if (isXYArraysData(src)) {\n // Fast path: bulk copy with xOffset adjustment\n for (let i = 0; i < actualPointCount; i++) {\n const srcIdx = srcPointOffset + i;\n const outIdx = outFloatOffset + i * 2;\n out[outIdx] = src.x[srcIdx]! - xOffset;\n out[outIdx + 1] = src.y[srcIdx]!;\n }\n return;\n }\n \n if (isInterleavedXYData(src)) {\n if (src instanceof DataView) {\n throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n }\n \n const arr = src as TypedArray;\n \n // Fast path: bulk copy with xOffset adjustment\n for (let i = 0; i < actualPointCount; i++) {\n const srcIdx = (srcPointOffset + i) * 2;\n const outIdx = outFloatOffset + i * 2;\n out[outIdx] = arr[srcIdx]! - xOffset;\n out[outIdx + 1] = arr[srcIdx + 1]!;\n }\n return;\n }\n \n // ReadonlyArray<DataPoint> path\n for (let i = 0; i < actualPointCount; i++) {\n const srcIdx = srcPointOffset + i;\n const outIdx = outFloatOffset + i * 2;\n const p = src[srcIdx]!;\n \n const x = isTupleDataPoint(p) ? p[0] : p.x;\n const y = isTupleDataPoint(p) ? p[1] : p.y;\n \n out[outIdx] = x - xOffset;\n out[outIdx + 1] = y;\n }\n}\n\n/**\n * Computes xMin/xMax/yMin/yMax bounds from CartesianSeriesData.\n * Skips non-finite x or y values. Returns null if no finite points found.\n * Ensures xMin !== xMax and yMin !== yMax for scale derivation (expands max by +1 if needed).\n *\n * @param data - CartesianSeriesData in any supported format\n * @returns Bounds object or null if no finite points\n */\nexport function computeRawBoundsFromCartesianData(data: CartesianSeriesData): Bounds | null {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n \n const count = getPointCount(data);\n \n for (let i = 0; i < count; i++) {\n const x = getX(data, i);\n const y = getY(data, i);\n \n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n \n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n \n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return null;\n }\n \n // Preserve existing behavior: if min==max, expand max by +1 for usability\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n \n return { xMin, xMax, yMin, yMax };\n}\n","import type { CartesianSeriesData, DataPointTuple, SeriesSampling } from '../config/types';\nimport { lttbSample } from './lttbSample';\nimport { getPointCount, getX, getY, getSize as getPointSize } from './cartesianData';\n\n\nfunction clampTargetPoints(targetPoints: number): number {\n const t = Math.floor(targetPoints);\n return Number.isFinite(t) ? t : 0;\n}\n\n/**\n * Type guard for XYArraysData format.\n */\nfunction isXYArraysData(data: CartesianSeriesData): data is import('../config/types').XYArraysData {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n 'x' in data &&\n 'y' in data &&\n typeof (data as any).x === 'object' &&\n typeof (data as any).y === 'object' &&\n 'length' in (data as any).x &&\n 'length' in (data as any).y\n );\n}\n\n/**\n * Type guard for InterleavedXYData format (ArrayBufferView).\n */\nfunction isInterleavedXYData(data: CartesianSeriesData): data is import('../config/types').InterleavedXYData {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n ArrayBuffer.isView(data)\n );\n}\n\n/**\n * Packs CartesianSeriesData into a Float32Array for LTTB sampling.\n * Returns the packed Float32Array.\n */\nfunction packToFloat32Array(data: CartesianSeriesData): Float32Array {\n const count = getPointCount(data);\n const out = new Float32Array(count * 2);\n \n for (let i = 0; i < count; i++) {\n out[i * 2] = getX(data, i);\n out[i * 2 + 1] = getY(data, i);\n }\n \n return out;\n}\n\ntype BucketMode = 'average' | 'max' | 'min';\n\n/**\n * Samples CartesianSeriesData using bucket-based strategies (average, max, min).\n * Always returns DataPointTuple[] for newly allocated data.\n * Preserves size semantics when available.\n */\nfunction sampleByBucketsFromCartesian(\n data: CartesianSeriesData,\n targetPoints: number,\n mode: BucketMode\n): DataPointTuple[] {\n const n = getPointCount(data);\n const threshold = clampTargetPoints(targetPoints);\n\n if (threshold <= 0 || n === 0) return [];\n if (threshold === 1) {\n const x = getX(data, 0);\n const y = getY(data, 0);\n const size = getPointSize(data, 0);\n return size !== undefined ? [[x, y, size]] : [[x, y]];\n }\n if (threshold === 2) {\n if (n >= 2) {\n const x0 = getX(data, 0);\n const y0 = getY(data, 0);\n const size0 = getPointSize(data, 0);\n const xLast = getX(data, n - 1);\n const yLast = getY(data, n - 1);\n const sizeLast = getPointSize(data, n - 1);\n return [\n size0 !== undefined ? [x0, y0, size0] : [x0, y0],\n sizeLast !== undefined ? [xLast, yLast, sizeLast] : [xLast, yLast],\n ];\n } else {\n const x = getX(data, 0);\n const y = getY(data, 0);\n const size = getPointSize(data, 0);\n return size !== undefined ? [[x, y, size]] : [[x, y]];\n }\n }\n\n const lastIndex = n - 1;\n const out: DataPointTuple[] = new Array(threshold);\n \n // First and last points\n {\n const x0 = getX(data, 0);\n const y0 = getY(data, 0);\n const size0 = getPointSize(data, 0);\n out[0] = size0 !== undefined ? [x0, y0, size0] : [x0, y0];\n \n const xLast = getX(data, lastIndex);\n const yLast = getY(data, lastIndex);\n const sizeLast = getPointSize(data, lastIndex);\n out[threshold - 1] = sizeLast !== undefined ? [xLast, yLast, sizeLast] : [xLast, yLast];\n }\n\n const bucketSize = (n - 2) / (threshold - 2);\n\n for (let bucket = 0; bucket < threshold - 2; bucket++) {\n let rangeStart = Math.floor(bucketSize * bucket) + 1;\n let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, lastIndex);\n\n if (rangeStart >= rangeEndExclusive) {\n rangeStart = Math.min(rangeStart, lastIndex - 1);\n rangeEndExclusive = Math.min(rangeStart + 1, lastIndex);\n }\n\n let chosen: DataPointTuple | null = null;\n\n if (mode === 'average') {\n let sumX = 0;\n let sumY = 0;\n let sumSize = 0;\n let count = 0;\n let sizeCount = 0;\n for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const x = getX(data, i);\n const y = getY(data, i);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n sumX += x;\n sumY += y;\n count++;\n\n const size = getPointSize(data, i);\n if (typeof size === 'number' && Number.isFinite(size)) {\n sumSize += size;\n sizeCount++;\n }\n }\n\n if (count > 0) {\n const avgX = sumX / count;\n const avgY = sumY / count;\n if (sizeCount > 0) {\n chosen = [avgX, avgY, sumSize / sizeCount];\n } else {\n chosen = [avgX, avgY];\n }\n }\n } else {\n let bestY = mode === 'max' ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;\n let bestIndex = rangeStart;\n for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const y = getY(data, i);\n if (!Number.isFinite(y)) continue;\n if (mode === 'max') {\n if (y > bestY) {\n bestY = y;\n bestIndex = i;\n }\n } else {\n if (y < bestY) {\n bestY = y;\n bestIndex = i;\n }\n }\n }\n // Return the best point found\n const x = getX(data, bestIndex);\n const y = getY(data, bestIndex);\n const size = getPointSize(data, bestIndex);\n chosen = size !== undefined ? [x, y, size] : [x, y];\n }\n\n if (chosen === null) {\n // Fallback to first point in range\n const x = getX(data, rangeStart);\n const y = getY(data, rangeStart);\n const size = getPointSize(data, rangeStart);\n chosen = size !== undefined ? [x, y, size] : [x, y];\n }\n\n out[bucket + 1] = chosen;\n }\n\n return out;\n}\n\n\n/**\n * Samples CartesianSeriesData using the specified sampling strategy.\n * \n * Returns the ORIGINAL data reference when:\n * - `sampling === 'none'`\n * - `samplingThreshold` is invalid/non-positive\n * - Point count <= threshold\n * \n * When sampling occurs:\n * - For `lttb`:\n * - Float32Array interleaved → returns sampled Float32Array\n * - Other interleaved typed array → packs to Float32Array, returns sampled Float32Array\n * - DataPoint[] → returns sampled DataPoint[]\n * - XYArraysData → packs to Float32Array, returns sampled Float32Array\n * - For `average`/`max`/`min`:\n * - Returns DataPointTuple[] for all input formats\n */\nexport function sampleSeriesDataPoints(\n data: CartesianSeriesData,\n sampling: SeriesSampling,\n samplingThreshold: number\n): CartesianSeriesData {\n const threshold = clampTargetPoints(samplingThreshold);\n const pointCount = getPointCount(data);\n\n // Disabled or already under threshold: keep original reference (avoid extra allocations).\n if (sampling === 'none') return data;\n if (!(threshold > 0)) return data;\n if (pointCount <= threshold) return data;\n\n switch (sampling) {\n case 'lttb': {\n // Float32Array fast path\n if (data instanceof Float32Array) {\n return lttbSample(data, threshold);\n }\n \n // Other interleaved typed arrays: pack to Float32Array and sample\n if (isInterleavedXYData(data)) {\n const packed = packToFloat32Array(data);\n return lttbSample(packed, threshold);\n }\n \n // XYArraysData: pack to Float32Array and sample\n if (isXYArraysData(data)) {\n const packed = packToFloat32Array(data);\n return lttbSample(packed, threshold);\n }\n \n // DataPoint[] path (existing behavior)\n return lttbSample(data, threshold);\n }\n \n case 'average':\n return sampleByBucketsFromCartesian(data, threshold, 'average');\n \n case 'max':\n return sampleByBucketsFromCartesian(data, threshold, 'max');\n \n case 'min':\n return sampleByBucketsFromCartesian(data, threshold, 'min');\n \n default: {\n // Defensive for JS callers / widened types.\n return data;\n }\n }\n}\n\n","import type { OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\n\nfunction isTupleOHLCDataPoint(point: OHLCDataPoint): point is OHLCDataPointTuple {\n return Array.isArray(point);\n}\n\n/**\n * Downsamples OHLC (candlestick) data to a target number of points using bucket aggregation.\n *\n * Each bucket aggregates candles preserving OHLC semantics:\n * - timestamp and open from the first candle in the bucket\n * - close from the last candle in the bucket\n * - high as the maximum of all highs in the bucket\n * - low as the minimum of all lows in the bucket\n *\n * @param data - Array of OHLC data points (tuples or objects)\n * @param targetPoints - Desired number of output points\n * @returns Downsampled array; same reference if no sampling needed\n *\n * Edge cases:\n * - If `data.length <= targetPoints` or `targetPoints < 2`, returns the original array (same reference)\n * - First and last candles are always preserved exactly (same element references)\n * - Output shape matches input shape (tuples → tuples, objects → objects)\n */\nexport function ohlcSample(\n data: ReadonlyArray<OHLCDataPoint>,\n targetPoints: number,\n): ReadonlyArray<OHLCDataPoint> {\n const threshold = Math.floor(targetPoints);\n const n = data.length;\n\n // Return original if already under target or insufficient target.\n if (threshold < 2 || n <= threshold) return data;\n\n const out = new Array<OHLCDataPoint>(threshold);\n\n // Preserve first and last candles exactly.\n out[0] = data[0]!;\n out[threshold - 1] = data[n - 1]!;\n\n if (threshold === 2) return out;\n\n // Hoist tuple-vs-object detection once (assume homogeneous arrays).\n const isTuple = isTupleOHLCDataPoint(data[0]!);\n\n // Bucket size for interior points: (n - 2) interior input points → (threshold - 2) interior output points.\n const bucketSize = (n - 2) / (threshold - 2);\n\n if (isTuple) {\n // Tuple format path: [timestamp, open, close, low, high]\n const dataAsTuples = data as ReadonlyArray<OHLCDataPointTuple>;\n\n for (let bucket = 0; bucket < threshold - 2; bucket++) {\n // Bucket range: [rangeStart, rangeEndExclusive)\n let rangeStart = Math.floor(bucketSize * bucket) + 1;\n let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, n - 1);\n\n // Defensive: ensure at least one candidate point.\n if (rangeStart >= rangeEndExclusive) {\n rangeStart = Math.min(rangeStart, n - 2);\n rangeEndExclusive = Math.min(rangeStart + 1, n - 1);\n }\n\n // Extract first and last candles in bucket.\n const firstCandle = dataAsTuples[rangeStart]!;\n const lastCandle = dataAsTuples[rangeEndExclusive - 1]!;\n\n const timestamp = firstCandle[0];\n const open = firstCandle[1];\n const close = lastCandle[2];\n\n // Aggregate high and low across the bucket.\n let high = -Infinity;\n let low = Infinity;\n for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const candle = dataAsTuples[i]!;\n const candleLow = candle[3];\n const candleHigh = candle[4];\n if (candleHigh > high) high = candleHigh;\n if (candleLow < low) low = candleLow;\n }\n\n out[bucket + 1] = [timestamp, open, close, low, high];\n }\n } else {\n // Object format path: { timestamp, open, close, low, high }\n const dataAsObjects = data as ReadonlyArray<Exclude<OHLCDataPoint, OHLCDataPointTuple>>;\n\n for (let bucket = 0; bucket < threshold - 2; bucket++) {\n // Bucket range: [rangeStart, rangeEndExclusive)\n let rangeStart = Math.floor(bucketSize * bucket) + 1;\n let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, n - 1);\n\n // Defensive: ensure at least one candidate point.\n if (rangeStart >= rangeEndExclusive) {\n rangeStart = Math.min(rangeStart, n - 2);\n rangeEndExclusive = Math.min(rangeStart + 1, n - 1);\n }\n\n // Extract first and last candles in bucket.\n const firstCandle = dataAsObjects[rangeStart]!;\n const lastCandle = dataAsObjects[rangeEndExclusive - 1]!;\n\n const timestamp = firstCandle.timestamp;\n const open = firstCandle.open;\n const close = lastCandle.close;\n\n // Aggregate high and low across the bucket.\n let high = -Infinity;\n let low = Infinity;\n for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const candle = dataAsObjects[i]!;\n const candleHigh = candle.high;\n const candleLow = candle.low;\n if (candleHigh > high) high = candleHigh;\n if (candleLow < low) low = candleLow;\n }\n\n out[bucket + 1] = { timestamp, open, close, low, high };\n }\n }\n\n return out;\n}\n","/**\n * Canvas sizing and measurement utilities for the RenderCoordinator.\n *\n * These pure functions handle canvas dimension retrieval with special handling\n * for device pixel ratio and GPU overlay coordinate conversions.\n *\n * @module canvasUtils\n */\n\n/**\n * Gets canvas CSS width - clientWidth for HTMLCanvasElement.\n *\n * @param canvas - The canvas element to measure, or null\n * @returns CSS width in pixels, or 0 if canvas is null\n */\nexport function getCanvasCssWidth(canvas: HTMLCanvasElement | null): number {\n if (!canvas) {\n return 0;\n }\n\n return canvas.clientWidth;\n}\n\n/**\n * Gets canvas CSS height - clientHeight for HTMLCanvasElement.\n *\n * @param canvas - The canvas element to measure, or null\n * @returns CSS height in pixels, or 0 if canvas is null\n */\nexport function getCanvasCssHeight(canvas: HTMLCanvasElement | null): number {\n if (!canvas) {\n return 0;\n }\n\n return canvas.clientHeight;\n}\n\n/**\n * Gets canvas CSS size derived strictly from device-pixel dimensions and DPR.\n *\n * This is intentionally different from `getCanvasCssWidth/Height(...)`:\n * - HTMLCanvasElement: `clientWidth/clientHeight` reflect DOM layout and can diverge (rounding, zoom, async resize)\n * from the WebGPU render target size (`canvas.width/height` in device pixels).\n * - For GPU overlays that round-trip CSS↔device pixels in-shader, we must derive CSS size from\n * `canvas.width/height` + DPR to keep transforms consistent with the render target.\n *\n * NOTE: Use this for GPU overlay coordinate conversion only (reference lines, markers).\n * Keep DOM overlays (labels/tooltips) using `clientWidth/clientHeight` for layout correctness.\n *\n * @param canvas - The canvas element to measure, or null\n * @param devicePixelRatio - The device pixel ratio (defaults to window.devicePixelRatio or 1)\n * @returns Object with width and height in CSS pixels derived from device pixels\n */\nexport function getCanvasCssSizeFromDevicePixels(\n canvas: HTMLCanvasElement | null,\n devicePixelRatio: number = typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n): Readonly<{ width: number; height: number }> {\n if (!canvas) return { width: 0, height: 0 };\n const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n // HTMLCanvasElement exposes `.width/.height` in device pixels.\n return { width: canvas.width / dpr, height: canvas.height / dpr };\n}\n\n/**\n * Clamps a value to an integer within [lo, hi] range.\n *\n * @param v - Value to clamp\n * @param lo - Lower bound (inclusive)\n * @param hi - Upper bound (inclusive)\n * @returns Clamped integer value\n */\nexport function clampInt(v: number, lo: number, hi: number): number {\n return Math.min(hi, Math.max(lo, v | 0));\n}\n","/**\n * Visible Slice Computation Utilities\n *\n * Provides efficient data slicing for zoom operations using binary search\n * when data is monotonic, with fallback to linear filtering.\n *\n * Key features:\n * - Binary search slicing for O(log n) performance on sorted data\n * - WeakMap caching of monotonicity checks to avoid O(n) scans\n * - Separate implementations for cartesian (x-based) and OHLC (timestamp-based) data\n * - Support for DataPoint[], XYArraysData, and InterleavedXYData formats\n */\n\nimport type {\n CartesianSeriesData,\n DataPoint,\n OHLCDataPoint,\n OHLCDataPointTuple,\n OHLCDataPointObject,\n XYArraysData,\n InterleavedXYData,\n} from '../../../config/types';\nimport { getPointCount, getX, getY } from '../../../data/cartesianData';\nimport { clampInt } from '../utils/canvasUtils';\n\n// Type guards for OHLC data\nexport function isTupleOHLCDataPoint(p: OHLCDataPoint): p is OHLCDataPointTuple {\n return Array.isArray(p);\n}\n\n// Cache monotonicity checks to avoid O(n) scans on every zoom operation\n// WeakMap works for arrays, typed arrays, and object references (XYArraysData)\nconst monotonicXCache = new WeakMap<object, boolean>();\nconst monotonicTimestampCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, boolean>();\n\n/**\n * Checks if cartesian data is monotonic non-decreasing by X coordinate with all finite values.\n * Results are cached in a WeakMap to avoid repeated O(n) scans.\n * \n * Supports all CartesianSeriesData formats: DataPoint[], XYArraysData, InterleavedXYData.\n */\nexport function isMonotonicNonDecreasingFiniteX(data: CartesianSeriesData): boolean {\n // For primitive arrays and typed arrays, we can cache by object reference\n // For XYArraysData, we cache by the object itself\n const cacheKey = typeof data === 'object' && data !== null ? data : null;\n if (cacheKey) {\n const cached = monotonicXCache.get(cacheKey);\n if (cached !== undefined) return cached;\n }\n\n let prevX = Number.NEGATIVE_INFINITY;\n const n = getPointCount(data);\n\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n if (!Number.isFinite(x)) {\n if (cacheKey) monotonicXCache.set(cacheKey, false);\n return false;\n }\n if (x < prevX) {\n if (cacheKey) monotonicXCache.set(cacheKey, false);\n return false;\n }\n prevX = x;\n }\n\n if (cacheKey) monotonicXCache.set(cacheKey, true);\n return true;\n}\n\n/**\n * Checks if OHLC data is monotonic non-decreasing by timestamp with all finite values.\n * Results are cached in a WeakMap to avoid repeated O(n) scans.\n */\nexport function isMonotonicNonDecreasingFiniteTimestamp(data: ReadonlyArray<OHLCDataPoint>): boolean {\n const cached = monotonicTimestampCache.get(data);\n if (cached !== undefined) return cached;\n\n let prevTimestamp = Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < data.length; i++) {\n const p = data[i]!;\n const timestamp = isTupleOHLCDataPoint(p) ? p[0] : p.timestamp;\n if (!Number.isFinite(timestamp)) {\n monotonicTimestampCache.set(data, false);\n return false;\n }\n if (timestamp < prevTimestamp) {\n monotonicTimestampCache.set(data, false);\n return false;\n }\n prevTimestamp = timestamp;\n }\n monotonicTimestampCache.set(data, true);\n return true;\n}\n\n// Binary search: lower bound (first element >= target) for CartesianSeriesData\nfunction lowerBoundX(data: CartesianSeriesData, xTarget: number): number {\n let lo = 0;\n let hi = getPointCount(data);\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = getX(data, mid);\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\n// Binary search: upper bound (first element > target) for CartesianSeriesData\nfunction upperBoundX(data: CartesianSeriesData, xTarget: number): number {\n let lo = 0;\n let hi = getPointCount(data);\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = getX(data, mid);\n if (x <= xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nfunction lowerBoundTimestampTuple(data: ReadonlyArray<OHLCDataPointTuple>, timestampTarget: number): number {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const timestamp = data[mid][0];\n if (timestamp < timestampTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nfunction upperBoundTimestampTuple(data: ReadonlyArray<OHLCDataPointTuple>, timestampTarget: number): number {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const timestamp = data[mid][0];\n if (timestamp <= timestampTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nfunction lowerBoundTimestampObject(data: ReadonlyArray<OHLCDataPointObject>, timestampTarget: number): number {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const timestamp = data[mid].timestamp;\n if (timestamp < timestampTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nfunction upperBoundTimestampObject(data: ReadonlyArray<OHLCDataPointObject>, timestampTarget: number): number {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const timestamp = data[mid].timestamp;\n if (timestamp <= timestampTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\n/**\n * Helper: Check if data is XYArraysData format.\n */\nfunction isXYArraysData(data: CartesianSeriesData): data is XYArraysData {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n 'x' in data &&\n 'y' in data &&\n typeof (data as any).x === 'object' &&\n typeof (data as any).y === 'object' &&\n 'length' in (data as any).x &&\n 'length' in (data as any).y\n );\n}\n\n/**\n * Helper: Check if data is InterleavedXYData format (ArrayBufferView).\n */\nfunction isInterleavedXYData(data: CartesianSeriesData): data is InterleavedXYData {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n ArrayBuffer.isView(data)\n );\n}\n\n/**\n * Helper: Slice CartesianSeriesData to index range [start, end).\n * Returns appropriate view/slice for each format.\n */\nfunction sliceCartesianData(\n data: CartesianSeriesData,\n start: number,\n end: number\n): CartesianSeriesData {\n // Clamp indices\n const n = getPointCount(data);\n const s = Math.max(0, Math.min(start, n));\n const e = Math.max(s, Math.min(end, n));\n\n if (s === 0 && e === n) return data;\n if (e <= s) {\n // Return empty data in appropriate format\n if (isXYArraysData(data)) {\n return { x: [], y: [], ...(data.size ? { size: [] } : {}) };\n }\n if (isInterleavedXYData(data)) {\n // Return empty view of same type\n if (data instanceof DataView) {\n throw new Error('DataView is not supported for InterleavedXYData');\n }\n const TypedArrayConstructor = (data as any).constructor;\n return new TypedArrayConstructor(0);\n }\n return [];\n }\n\n // XYArraysData: slice x, y, and optional size arrays\n if (isXYArraysData(data)) {\n const xSliced = Array.isArray(data.x)\n ? data.x.slice(s, e)\n : 'subarray' in data.x\n ? (data.x as any).subarray(s, e)\n : Array.from(data.x).slice(s, e);\n\n const ySliced = Array.isArray(data.y)\n ? data.y.slice(s, e)\n : 'subarray' in data.y\n ? (data.y as any).subarray(s, e)\n : Array.from(data.y).slice(s, e);\n\n const result: XYArraysData = { x: xSliced, y: ySliced };\n\n if (data.size) {\n const sizeSliced = Array.isArray(data.size)\n ? data.size.slice(s, e)\n : 'subarray' in data.size\n ? (data.size as any).subarray(s, e)\n : Array.from(data.size).slice(s, e);\n (result as any).size = sizeSliced;\n }\n\n return result;\n }\n\n // InterleavedXYData: return subarray view (start*2, end*2)\n if (isInterleavedXYData(data)) {\n if (data instanceof DataView) {\n throw new Error('DataView is not supported for InterleavedXYData');\n }\n return (data as any).subarray(s * 2, e * 2);\n }\n\n // ReadonlyArray<DataPoint>: standard slice\n return (data as ReadonlyArray<DataPoint>).slice(s, e);\n}\n\n/**\n * Slices cartesian data to the visible X range [xMin, xMax].\n *\n * Uses binary search (O(log n)) when data is monotonic by X;\n * otherwise falls back to linear filtering (O(n)).\n *\n * @param data - Cartesian data in any supported format\n * @param xMin - Minimum X value (inclusive)\n * @param xMax - Maximum X value (inclusive)\n * @returns Sliced data in the same format as input\n */\nexport function sliceVisibleRangeByX(\n data: CartesianSeriesData,\n xMin: number,\n xMax: number\n): CartesianSeriesData {\n const n = getPointCount(data);\n if (n === 0) return data;\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return data;\n\n const canBinarySearch = isMonotonicNonDecreasingFiniteX(data);\n\n if (canBinarySearch) {\n const lo = lowerBoundX(data, xMin);\n const hi = upperBoundX(data, xMax);\n\n if (lo <= 0 && hi >= n) return data;\n return sliceCartesianData(data, lo, hi);\n }\n\n // Safe fallback: linear filter (preserves order, ignores non-finite x)\n // For non-monotonic data, we must return a filtered array\n const out: DataPoint[] = [];\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n if (!Number.isFinite(x)) continue;\n if (x >= xMin && x <= xMax) {\n const y = getY(data, i);\n out.push([x, y]);\n }\n }\n return out;\n}\n\n/**\n * Finds the index range of visible points in cartesian data.\n *\n * Returns { start, end } indices suitable for slicing or iteration.\n * Only works correctly when data is monotonic; returns full range otherwise.\n *\n * @param data - Cartesian data in any supported format\n * @param xMin - Minimum X value (inclusive)\n * @param xMax - Maximum X value (inclusive)\n * @returns Index range { start, end } for visible data\n */\nexport function findVisibleRangeIndicesByX(\n data: CartesianSeriesData,\n xMin: number,\n xMax: number\n): { readonly start: number; readonly end: number } {\n const n = getPointCount(data);\n if (n === 0) return { start: 0, end: 0 };\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return { start: 0, end: n };\n\n const canBinarySearch = isMonotonicNonDecreasingFiniteX(data);\n if (!canBinarySearch) {\n // Data is not monotonic by x; we can't represent the visible set as a contiguous index range\n // Fall back to processing the full series for correctness\n return { start: 0, end: n };\n }\n\n const start = lowerBoundX(data, xMin);\n const end = upperBoundX(data, xMax);\n\n const s = clampInt(start, 0, n);\n const e = clampInt(end, 0, n);\n return e <= s ? { start: s, end: s } : { start: s, end: e };\n}\n\n/**\n * Slices OHLC/candlestick data to the visible timestamp range [xMin, xMax].\n *\n * Uses binary search (O(log n)) when timestamps are monotonic;\n * otherwise falls back to linear filtering (O(n)).\n *\n * @param data - OHLC data points (tuple or object format)\n * @param xMin - Minimum timestamp (inclusive)\n * @param xMax - Maximum timestamp (inclusive)\n * @returns Sliced data array containing only points within [xMin, xMax]\n */\nexport function sliceVisibleRangeByOHLC(\n data: ReadonlyArray<OHLCDataPoint>,\n xMin: number,\n xMax: number\n): ReadonlyArray<OHLCDataPoint> {\n const n = data.length;\n if (n === 0) return data;\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return data;\n\n const canBinarySearch = isMonotonicNonDecreasingFiniteTimestamp(data);\n const isTuple = n > 0 && isTupleOHLCDataPoint(data[0]!);\n\n if (canBinarySearch) {\n const lo = isTuple\n ? lowerBoundTimestampTuple(data as ReadonlyArray<OHLCDataPointTuple>, xMin)\n : lowerBoundTimestampObject(data as ReadonlyArray<OHLCDataPointObject>, xMin);\n const hi = isTuple\n ? upperBoundTimestampTuple(data as ReadonlyArray<OHLCDataPointTuple>, xMax)\n : upperBoundTimestampObject(data as ReadonlyArray<OHLCDataPointObject>, xMax);\n\n if (lo <= 0 && hi >= n) return data;\n if (hi <= lo) return [];\n return data.slice(lo, hi);\n }\n\n // Safe fallback: linear filter (preserves order, ignores non-finite timestamp)\n const out: OHLCDataPoint[] = [];\n for (let i = 0; i < n; i++) {\n const p = data[i]!;\n const timestamp = isTupleOHLCDataPoint(p) ? p[0] : p.timestamp;\n if (!Number.isFinite(timestamp)) continue;\n if (timestamp >= xMin && timestamp <= xMax) out.push(p);\n }\n return out;\n}\n","export type Rgba01 = readonly [r: number, g: number, b: number, a: number];\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clamp255 = (v: number): number => Math.min(255, Math.max(0, v));\n\nconst parseHexNibble = (hex: string): number => {\n const n = Number.parseInt(hex, 16);\n return Number.isFinite(n) ? n : 0;\n};\n\nconst parseHexByte = (hex: string): number => {\n const n = Number.parseInt(hex, 16);\n return Number.isFinite(n) ? n : 0;\n};\n\nconst parseHexColorToRgba01 = (color: string): Rgba01 | null => {\n const c = color.trim();\n if (!c.startsWith('#')) return null;\n\n const hex = c.slice(1);\n\n // #rgb\n if (hex.length === 3) {\n const r = parseHexNibble(hex[0]);\n const g = parseHexNibble(hex[1]);\n const b = parseHexNibble(hex[2]);\n return [(r * 17) / 255, (g * 17) / 255, (b * 17) / 255, 1];\n }\n\n // #rgba\n if (hex.length === 4) {\n const r = parseHexNibble(hex[0]);\n const g = parseHexNibble(hex[1]);\n const b = parseHexNibble(hex[2]);\n const a = parseHexNibble(hex[3]);\n return [(r * 17) / 255, (g * 17) / 255, (b * 17) / 255, (a * 17) / 255];\n }\n\n // #rrggbb\n if (hex.length === 6) {\n const r = parseHexByte(hex.slice(0, 2));\n const g = parseHexByte(hex.slice(2, 4));\n const b = parseHexByte(hex.slice(4, 6));\n return [r / 255, g / 255, b / 255, 1];\n }\n\n // #rrggbbaa\n if (hex.length === 8) {\n const r = parseHexByte(hex.slice(0, 2));\n const g = parseHexByte(hex.slice(2, 4));\n const b = parseHexByte(hex.slice(4, 6));\n const a = parseHexByte(hex.slice(6, 8));\n return [r / 255, g / 255, b / 255, a / 255];\n }\n\n return null;\n};\n\nconst parseRgbNumberOrPercent = (token: string): number | null => {\n const t = token.trim();\n if (t.length === 0) return null;\n\n if (t.endsWith('%')) {\n const n = Number.parseFloat(t.slice(0, -1));\n if (!Number.isFinite(n)) return null;\n return clamp255((n / 100) * 255);\n }\n\n const n = Number.parseFloat(t);\n if (!Number.isFinite(n)) return null;\n return clamp255(n);\n};\n\nconst parseAlphaNumberOrPercent = (token: string): number | null => {\n const t = token.trim();\n if (t.length === 0) return null;\n\n if (t.endsWith('%')) {\n const n = Number.parseFloat(t.slice(0, -1));\n if (!Number.isFinite(n)) return null;\n return clamp01(n / 100);\n }\n\n const n = Number.parseFloat(t);\n if (!Number.isFinite(n)) return null;\n return clamp01(n);\n};\n\nconst parseRgbFuncToRgba01 = (color: string): Rgba01 | null => {\n const c = color.trim();\n const m = /^(rgba?|RGBA?)\\(\\s*([^\\)]*)\\s*\\)$/.exec(c);\n if (!m) return null;\n\n const fn = m[1].toLowerCase();\n const argsRaw = m[2];\n\n // Requirement scope: support comma-separated rgb()/rgba().\n // (We intentionally do not attempt full CSS Color 4 space-separated syntax here.)\n const parts = argsRaw.split(',').map((p) => p.trim());\n if (fn === 'rgb') {\n if (parts.length !== 3) return null;\n const r = parseRgbNumberOrPercent(parts[0]);\n const g = parseRgbNumberOrPercent(parts[1]);\n const b = parseRgbNumberOrPercent(parts[2]);\n if (r == null || g == null || b == null) return null;\n return [r / 255, g / 255, b / 255, 1];\n }\n\n if (fn === 'rgba') {\n if (parts.length !== 4) return null;\n const r = parseRgbNumberOrPercent(parts[0]);\n const g = parseRgbNumberOrPercent(parts[1]);\n const b = parseRgbNumberOrPercent(parts[2]);\n const a = parseAlphaNumberOrPercent(parts[3]);\n if (r == null || g == null || b == null || a == null) return null;\n return [r / 255, g / 255, b / 255, a];\n }\n\n return null;\n};\n\n/**\n * Parse a CSS color string into RGBA floats in [0..1].\n *\n * Supported:\n * - #rgb / #rgba / #rrggbb / #rrggbbaa\n * - rgb(r,g,b)\n * - rgba(r,g,b,a)\n *\n * Returns null when parsing fails.\n */\nexport const parseCssColorToRgba01 = (color: string): Rgba01 | null => {\n if (typeof color !== 'string') return null;\n const c = color.trim();\n if (c.length === 0) return null;\n\n const hex = parseHexColorToRgba01(c);\n if (hex) return hex;\n\n const rgb = parseRgbFuncToRgba01(c);\n if (rgb) return rgb;\n\n return null;\n};\n\nexport const parseCssColorToGPUColor = (\n color: string,\n fallback: GPUColor = { r: 0, g: 0, b: 0, a: 1 }\n): GPUColor => {\n const rgba = parseCssColorToRgba01(color);\n if (!rgba) return fallback;\n const [r, g, b, a] = rgba;\n return { r, g, b, a };\n};\n\n","/**\n * Data point type guards and utilities for the RenderCoordinator.\n *\n * These pure functions handle the dual data format system (tuple vs object)\n * and provide type-safe access to point coordinates.\n *\n * @module dataPointUtils\n */\n\nimport type { DataPoint, DataPointTuple, OHLCDataPoint, OHLCDataPointTuple } from '../../../config/types';\n\n/**\n * Validates that a number is finite, returning the number or null.\n *\n * @param v - Value to validate\n * @returns The number if finite, otherwise null\n */\nexport const finiteOrNull = (v: number | null | undefined): number | null =>\n typeof v === 'number' && Number.isFinite(v) ? v : null;\n\n/**\n * Validates that a number is finite, returning the number or undefined.\n *\n * @param v - Value to validate\n * @returns The number if finite, otherwise undefined\n */\nexport const finiteOrUndefined = (v: number | undefined): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n\n/**\n * Compile-time exhaustiveness check for error handling.\n * Used in switch statements to ensure all cases are handled.\n *\n * @param value - The value that should be of type `never` if all cases are handled\n * @throws Always throws an error if called\n */\nexport const assertUnreachable = (value: never): never => {\n // Intentionally minimal message: this is used for compile-time exhaustiveness.\n throw new Error(`RenderCoordinator: unreachable value: ${String(value)}`);\n};\n\n/**\n * Type guard: checks if a DataPoint is in tuple form `[x, y]`.\n *\n * @param p - The data point to check\n * @returns True if the point is a tuple, false if it's an object\n */\nexport const isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\n/**\n * Extracts x,y coordinates from either tuple or object point format.\n *\n * @param p - The data point (either tuple or object format)\n * @returns Object with x and y properties\n */\nexport const getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n return { x: p.x, y: p.y };\n};\n\n/**\n * Type guard: checks if a data point is in tuple OHLC form `[timestamp, open, high, low, close]`.\n *\n * @param p - The OHLC data point to check\n * @returns True if the point is a tuple, false if it's an object\n */\nexport const isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\n/**\n * Type guard: checks if a data point is in tuple form `[x, y]` (for individual points).\n *\n * @param p - The point to check\n * @returns True if the point is a tuple array\n */\nexport const isTuplePoint = (p: unknown): p is readonly [number, number] => Array.isArray(p);\n\n/**\n * Type guard: checks if entire data array is in tuple format.\n * Only checks the first element for performance.\n *\n * @param data - Array of data points to check\n * @returns True if first element (and therefore likely all) is a tuple\n */\nexport const isTupleDataArray = (data: ReadonlyArray<DataPoint>): data is ReadonlyArray<DataPointTuple> =>\n data.length > 0 && isTupleDataPoint(data[0]);\n","/**\n * Axis and grid utilities for the RenderCoordinator.\n *\n * These pure functions handle coordinate transformations between different spaces:\n * - CSS pixels (DOM layout)\n * - Device pixels (canvas.width/height)\n * - Normalized device coordinates / clip space (WebGPU [-1, 1])\n *\n * @module axisUtils\n */\n\nimport type { GPUContextLike } from '../types';\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { GridArea } from '../../../renderers/createGridRenderer';\nimport { parseCssColorToRgba01 } from '../../../utils/colors';\nimport { normalizeDomain } from './boundsComputation';\nimport { clampInt } from './canvasUtils';\n\n/**\n * Computes grid area with margins and canvas dimensions for rendering layout.\n * GridArea uses:\n * - Margins (left, right, top, bottom) in CSS pixels\n * - Canvas dimensions (canvasWidth, canvasHeight) in DEVICE pixels\n * - devicePixelRatio for CSS-to-device conversion (worker-compatible)\n *\n * @param gpuContext - GPU context with canvas and device pixel ratio\n * @param options - Resolved chart options with grid margins\n * @returns GridArea object with margins, canvas dimensions, and DPR\n * @throws If canvas is null or has invalid dimensions\n */\nexport const computeGridArea = (gpuContext: GPUContextLike, options: ResolvedChartGPUOptions): GridArea => {\n const canvas = gpuContext.canvas;\n if (!canvas) throw new Error('RenderCoordinator: gpuContext.canvas is required.');\n\n const dpr = gpuContext.devicePixelRatio ?? 1;\n const devicePixelRatio = (Number.isFinite(dpr) && dpr > 0) ? dpr : 1;\n\n // Validate and sanitize canvas dimensions (device pixels)\n const rawCanvasWidth = canvas.width;\n const rawCanvasHeight = canvas.height;\n\n if (!Number.isFinite(rawCanvasWidth) || !Number.isFinite(rawCanvasHeight)) {\n throw new Error(\n `RenderCoordinator: Invalid canvas dimensions: width=${rawCanvasWidth}, height=${rawCanvasHeight}. ` +\n `Canvas must be initialized with finite dimensions before rendering.`\n );\n }\n\n // Be resilient: charts may be mounted into 0-sized containers (e.g. display:none during init).\n // Renderers guard internally; clamping avoids hard crashes and allows future resize to recover.\n const canvasWidth = Math.max(1, Math.floor(rawCanvasWidth));\n const canvasHeight = Math.max(1, Math.floor(rawCanvasHeight));\n\n // Validate and sanitize grid margins (CSS pixels)\n const left = Number.isFinite(options.grid.left) ? options.grid.left : 0;\n const right = Number.isFinite(options.grid.right) ? options.grid.right : 0;\n const top = Number.isFinite(options.grid.top) ? options.grid.top : 0;\n const bottom = Number.isFinite(options.grid.bottom) ? options.grid.bottom : 0;\n\n // Ensure margins are non-negative (negative margins could cause rendering issues)\n const sanitizedLeft = Math.max(0, left);\n const sanitizedRight = Math.max(0, right);\n const sanitizedTop = Math.max(0, top);\n const sanitizedBottom = Math.max(0, bottom);\n\n return {\n left: sanitizedLeft,\n right: sanitizedRight,\n top: sanitizedTop,\n bottom: sanitizedBottom,\n canvasWidth, // Device pixels (clamped above)\n canvasHeight, // Device pixels (clamped above)\n devicePixelRatio, // Explicit DPR for worker compatibility (validated above)\n };\n};\n\n/**\n * Converts RGBA normalized [0-1] values to CSS rgba() string.\n *\n * @param rgba - Array of [r, g, b, a] in range [0, 1]\n * @returns CSS rgba() string\n */\nexport const rgba01ToCssRgba = (rgba: readonly [number, number, number, number]): string => {\n const r = Math.max(0, Math.min(255, Math.round(rgba[0] * 255)));\n const g = Math.max(0, Math.min(255, Math.round(rgba[1] * 255)));\n const b = Math.max(0, Math.min(255, Math.round(rgba[2] * 255)));\n const a = Math.max(0, Math.min(1, rgba[3]));\n return `rgba(${r},${g},${b},${a})`;\n};\n\n/**\n * Applies alpha multiplier to CSS color.\n * Parses color, multiplies alpha channel, and returns new CSS rgba() string.\n *\n * @param cssColor - CSS color string\n * @param alphaMultiplier - Alpha multiplier in range [0, 1]\n * @returns CSS rgba() string with modified alpha, or original color if parse fails\n */\nexport const withAlpha = (cssColor: string, alphaMultiplier: number): string => {\n const parsed = parseCssColorToRgba01(cssColor);\n if (!parsed) return cssColor;\n const a = Math.max(0, Math.min(1, parsed[3] * alphaMultiplier));\n return rgba01ToCssRgba([parsed[0], parsed[1], parsed[2], a]);\n};\n\n/**\n * Converts grid margins to normalized device clip coordinates for WebGPU.\n * Output is in WebGPU clip space: [-1, 1] for both x and y.\n * Y-axis is flipped (top is positive, bottom is negative).\n *\n * @param gridArea - Grid area with margins and canvas dimensions\n * @returns Clip rect with left, right, top, bottom in range [-1, 1]\n */\nexport const computePlotClipRect = (\n gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number } => {\n const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeft = left * devicePixelRatio;\n const plotRight = canvasWidth - right * devicePixelRatio;\n const plotTop = top * devicePixelRatio;\n const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n return {\n left: plotLeftClip,\n right: plotRightClip,\n top: plotTopClip,\n bottom: plotBottomClip,\n };\n};\n\n/**\n * Clamps value to [0, 1] range.\n *\n * @param v - Value to clamp\n * @returns Clamped value\n */\nexport const clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\n/**\n * Linear interpolation between two values with clamped t.\n *\n * @param a - Start value\n * @param b - End value\n * @param t01 - Interpolation parameter in range [0, 1]\n * @returns Interpolated value\n */\nexport const lerp = (a: number, b: number, t01: number): number => a + (b - a) * clamp01(t01);\n\n/**\n * Interpolates between two domains (min/max pairs).\n * Ensures result is a valid domain (min ≤ max, both finite).\n *\n * @param from - Start domain\n * @param to - End domain\n * @param t01 - Interpolation parameter in range [0, 1]\n * @returns Interpolated domain\n */\nexport const lerpDomain = (\n from: { readonly min: number; readonly max: number },\n to: { readonly min: number; readonly max: number },\n t01: number\n): { readonly min: number; readonly max: number } => {\n return normalizeDomain(lerp(from.min, to.min, t01), lerp(from.max, to.max, t01));\n};\n\n/**\n * Computes scissor rect in device pixels from grid margins.\n * Used for WebGPU scissor testing to clip rendering to plot area.\n *\n * @param gridArea - Grid area with margins and canvas dimensions\n * @returns Scissor rect with x, y, w, h in device pixels\n */\nexport const computePlotScissorDevicePx = (\n gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\n/**\n * Converts clip-space X to canvas CSS pixels (from normalized [-1, 1]).\n *\n * @param xClip - X coordinate in clip space [-1, 1]\n * @param canvasCssWidth - Canvas width in CSS pixels\n * @returns X coordinate in canvas CSS pixels\n */\nexport const clipXToCanvasCssPx = (xClip: number, canvasCssWidth: number): number => ((xClip + 1) / 2) * canvasCssWidth;\n\n/**\n * Converts clip-space Y to canvas CSS pixels (from normalized [-1, 1]).\n * Y-axis is flipped (1 is top, -1 is bottom).\n *\n * @param yClip - Y coordinate in clip space [-1, 1]\n * @param canvasCssHeight - Canvas height in CSS pixels\n * @returns Y coordinate in canvas CSS pixels\n */\nexport const clipYToCanvasCssPx = (yClip: number, canvasCssHeight: number): number => ((1 - yClip) / 2) * canvasCssHeight;\n","/**\n * Time axis and formatting utilities for the RenderCoordinator.\n *\n * These pure functions handle time-based tick generation, adaptive label formatting,\n * and number/percentage parsing for pie chart configuration.\n *\n * @module timeAxisUtils\n */\n\nimport type { LinearScale } from '../../../utils/scales';\nimport type { TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport type { PieCenter, PieRadius } from '../../../config/types';\nimport { clipXToCanvasCssPx } from './axisUtils';\nimport { finiteOrNull } from './dataPointUtils';\n\n/**\n * Time constants for axis formatting decisions.\n */\nexport const MS_PER_DAY = 24 * 60 * 60 * 1000;\nexport const MS_PER_MONTH_APPROX = 30 * MS_PER_DAY;\nexport const MS_PER_YEAR_APPROX = 365 * MS_PER_DAY;\n\n/**\n * Tick configuration constants.\n */\nexport const MAX_TIME_X_TICK_COUNT = 9;\nexport const MIN_TIME_X_TICK_COUNT = 1;\nexport const MIN_X_LABEL_GAP_CSS_PX = 6;\nexport const DEFAULT_MAX_TICK_FRACTION_DIGITS = 6;\nexport const DEFAULT_TICK_COUNT = 5;\n\n/**\n * English month abbreviations for time axis labels.\n */\nexport const MONTH_SHORT_EN: readonly string[] = [\n 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n];\n\n/**\n * Parses value as number or percentage string, returns null if invalid.\n * Used for pie chart center and radius configuration.\n *\n * @param value - Number or percentage string (e.g. \"50%\", \"120\", 120)\n * @param basis - Basis value for percentage calculation\n * @returns Parsed number or null if invalid\n */\nexport const parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (typeof value !== 'string') return null;\n\n const s = value.trim();\n if (s.length === 0) return null;\n\n if (s.endsWith('%')) {\n const pct = Number.parseFloat(s.slice(0, -1));\n if (!Number.isFinite(pct)) return null;\n return (pct / 100) * basis;\n }\n\n // Be permissive: allow numeric strings like \"120\".\n const n = Number.parseFloat(s);\n return Number.isFinite(n) ? n : null;\n};\n\n/**\n * Resolves pie center from mixed number/string/percent format.\n * Defaults to center of plot area (50%, 50%).\n *\n * @param center - Pie center configuration or undefined\n * @param plotWidthCss - Plot area width in CSS pixels\n * @param plotHeightCss - Plot area height in CSS pixels\n * @returns Resolved center coordinates in CSS pixels\n */\nexport const resolvePieCenterPlotCss = (\n center: PieCenter | undefined,\n plotWidthCss: number,\n plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n const xRaw = center?.[0] ?? '50%';\n const yRaw = center?.[1] ?? '50%';\n\n const x = parseNumberOrPercent(xRaw, plotWidthCss);\n const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n return {\n x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n };\n};\n\n/**\n * Type guard for pie radius tuple format `[inner, outer]`.\n *\n * @param radius - Pie radius configuration\n * @returns True if radius is a tuple\n */\nexport const isPieRadiusTuple = (\n radius: PieRadius\n): radius is readonly [inner: number | string, outer: number | string] => Array.isArray(radius);\n\n/**\n * Resolves pie inner/outer radii with defaults, bounds checking.\n * Default outer radius is 70% of max, inner radius is 0 (full pie).\n *\n * @param radius - Pie radius configuration or undefined\n * @param maxRadiusCss - Maximum radius in CSS pixels\n * @returns Resolved inner and outer radii in CSS pixels\n */\nexport const resolvePieRadiiCss = (\n radius: PieRadius | undefined,\n maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n // Default similar to common chart libs (mirrors `createPieRenderer.ts`).\n if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n if (isPieRadiusTuple(radius)) {\n const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n }\n\n const outer = parseNumberOrPercent(radius, maxRadiusCss);\n const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\n/**\n * Calculates decimal precision needed for clean tick formatting from tick step.\n * Prefers \"clean\" decimal representations (e.g. 2.5, 0.25, 0.125) without relying on magnitude alone.\n *\n * @param tickStep - Step size between ticks\n * @param cap - Maximum fraction digits to return (default 6)\n * @returns Number of fraction digits for formatting\n */\nexport const computeMaxFractionDigitsFromStep = (tickStep: number, cap: number = DEFAULT_MAX_TICK_FRACTION_DIGITS): number => {\n const stepAbs = Math.abs(tickStep);\n if (!Number.isFinite(stepAbs) || stepAbs === 0) return 0;\n\n // Prefer \"clean\" decimal representations (e.g. 2.5, 0.25, 0.125) without relying on magnitude alone.\n // We accept floating-point noise and cap the search to keep formatting reasonable.\n for (let d = 0; d <= cap; d++) {\n const scaled = stepAbs * 10 ** d;\n const rounded = Math.round(scaled);\n const err = Math.abs(scaled - rounded);\n const tol = 1e-9 * Math.max(1, Math.abs(scaled));\n if (err <= tol) return d;\n }\n\n // Fallback for repeating decimals (e.g. 1/3): show a small number of digits based on magnitude.\n // The +1 nudges values like 0.333.. towards 2 decimals rather than 1.\n return Math.max(0, Math.min(cap, Math.ceil(-Math.log10(stepAbs)) + 1));\n};\n\n/**\n * Creates Intl.NumberFormat instance for consistent tick formatting.\n * Automatically computes appropriate fraction digits from tick step.\n *\n * @param tickStep - Step size between ticks\n * @returns NumberFormat instance\n */\nexport const createTickFormatter = (tickStep: number): Intl.NumberFormat => {\n const maximumFractionDigits = computeMaxFractionDigitsFromStep(tickStep);\n return new Intl.NumberFormat(undefined, { maximumFractionDigits });\n};\n\n/**\n * Formats numeric value using NumberFormat, handles -0 and NaN edge cases.\n *\n * @param nf - NumberFormat instance\n * @param v - Value to format\n * @returns Formatted string or null if invalid\n */\nexport const formatTickValue = (nf: Intl.NumberFormat, v: number): string | null => {\n if (!Number.isFinite(v)) return null;\n // Avoid displaying \"-0\" from floating-point artifacts.\n const normalized = Math.abs(v) < 1e-12 ? 0 : v;\n const formatted = nf.format(normalized);\n // Guard against unexpected output like \"NaN\" even after the finite check (defensive).\n return formatted === 'NaN' ? null : formatted;\n};\n\n/**\n * Pads single-digit numbers with leading zero (used by time formatting).\n *\n * @param n - Number to pad\n * @returns Zero-padded string (minimum 2 digits)\n */\nexport const pad2 = (n: number): string => String(Math.trunc(n)).padStart(2, '0');\n\n/**\n * Formats millisecond timestamps with adaptive precision based on visible range.\n * Format tiers:\n * - < 1 day: HH:mm\n * - 1-7 days: MM/DD HH:mm\n * - 1-12 weeks (up to ~3 months): MM/DD\n * - 3-12 months: MMM DD\n * - > 1 year: YYYY/MM\n *\n * @param timestampMs - Timestamp in milliseconds\n * @param visibleRangeMs - Visible range width in milliseconds\n * @returns Formatted time string or null if invalid\n */\nexport const formatTimeTickValue = (timestampMs: number, visibleRangeMs: number): string | null => {\n if (!Number.isFinite(timestampMs)) return null;\n if (!Number.isFinite(visibleRangeMs) || visibleRangeMs < 0) visibleRangeMs = 0;\n\n const d = new Date(timestampMs);\n // Guard against out-of-range timestamps that produce an invalid Date.\n if (!Number.isFinite(d.getTime())) return null;\n const yyyy = d.getFullYear();\n const mm = d.getMonth() + 1; // 1-12\n const dd = d.getDate();\n const hh = d.getHours();\n const min = d.getMinutes();\n\n if (visibleRangeMs < MS_PER_DAY) {\n return `${pad2(hh)}:${pad2(min)}`;\n }\n // Treat the 7-day boundary as inclusive for the \"1–7 days\" tier.\n if (visibleRangeMs <= 7 * MS_PER_DAY) {\n return `${pad2(mm)}/${pad2(dd)} ${pad2(hh)}:${pad2(min)}`;\n }\n // Keep short calendar dates until the visible range reaches ~3 months.\n if (visibleRangeMs < 3 * MS_PER_MONTH_APPROX) {\n return `${pad2(mm)}/${pad2(dd)}`;\n }\n if (visibleRangeMs <= MS_PER_YEAR_APPROX) {\n const mmm = MONTH_SHORT_EN[d.getMonth()] ?? pad2(mm);\n return `${mmm} ${pad2(dd)}`;\n }\n return `${yyyy}/${pad2(mm)}`;\n};\n\n/**\n * Generates evenly-spaced tick values across domain.\n *\n * @param domainMin - Domain minimum value\n * @param domainMax - Domain maximum value\n * @param tickCount - Number of ticks to generate\n * @returns Array of tick values\n */\nexport const generateLinearTicks = (domainMin: number, domainMax: number, tickCount: number): number[] => {\n const count = Math.max(1, Math.floor(tickCount));\n const ticks: number[] = new Array(count);\n for (let i = 0; i < count; i++) {\n const t = count === 1 ? 0.5 : i / (count - 1);\n ticks[i] = domainMin + t * (domainMax - domainMin);\n }\n return ticks;\n};\n\n/**\n * Computes optimal tick count + values to avoid label overlap on time x-axis.\n * Uses text measurement context to test label widths.\n * Tries tick counts from MAX (9) down to MIN (1) until labels fit without overlap.\n *\n * @param params - Configuration object with axis, scale, canvas, and measurement settings\n * @returns Object with tickCount and tickValues\n */\nexport const computeAdaptiveTimeXAxisTicks = (params: {\n readonly axisMin: number | null;\n readonly axisMax: number | null;\n readonly xScale: LinearScale;\n readonly plotClipLeft: number;\n readonly plotClipRight: number;\n readonly canvasCssWidth: number;\n readonly visibleRangeMs: number;\n readonly measureCtx: CanvasRenderingContext2D | null;\n readonly measureCache?: Map<string, number>;\n readonly fontSize: number;\n readonly fontFamily: string;\n}): { readonly tickCount: number; readonly tickValues: readonly number[] } => {\n const {\n axisMin,\n axisMax,\n xScale,\n plotClipLeft,\n plotClipRight,\n canvasCssWidth,\n visibleRangeMs,\n measureCtx,\n measureCache,\n fontSize,\n fontFamily,\n } = params;\n\n // Domain fallback matches `createAxisRenderer` (use explicit min/max when provided).\n const domainMin = finiteOrNull(axisMin) ?? xScale.invert(plotClipLeft);\n const domainMax = finiteOrNull(axisMax) ?? xScale.invert(plotClipRight);\n\n if (!measureCtx || canvasCssWidth <= 0) {\n return { tickCount: DEFAULT_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, DEFAULT_TICK_COUNT) };\n }\n\n // Ensure the measurement font matches the overlay labels.\n measureCtx.font = `${fontSize}px ${fontFamily}`;\n if (measureCache && measureCache.size > 2000) measureCache.clear();\n\n // Pre-construct the font part of the cache key to avoid repeated concatenation.\n const cacheKeyPrefix = measureCache ? `${fontSize}px ${fontFamily}@@` : null;\n\n for (let tickCount = MAX_TIME_X_TICK_COUNT; tickCount >= MIN_TIME_X_TICK_COUNT; tickCount--) {\n const tickValues = generateLinearTicks(domainMin, domainMax, tickCount);\n\n // Compute label extents in *canvas-local CSS px* and ensure adjacent labels don't overlap.\n let prevRight = Number.NEGATIVE_INFINITY;\n let ok = true;\n\n for (let i = 0; i < tickValues.length; i++) {\n const v = tickValues[i]!;\n const label = formatTimeTickValue(v, visibleRangeMs);\n if (label == null) continue;\n\n const w = (() => {\n if (!cacheKeyPrefix) return measureCtx.measureText(label).width;\n const key = cacheKeyPrefix + label;\n const cached = measureCache!.get(key);\n if (cached != null) return cached;\n const measured = measureCtx.measureText(label).width;\n measureCache!.set(key, measured);\n return measured;\n })();\n const xClip = xScale.scale(v);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n\n const anchor: TextOverlayAnchor =\n tickCount === 1 ? 'middle' : i === 0 ? 'start' : i === tickValues.length - 1 ? 'end' : 'middle';\n\n const left = anchor === 'start' ? xCss : anchor === 'end' ? xCss - w : xCss - w * 0.5;\n const right = anchor === 'start' ? xCss + w : anchor === 'end' ? xCss : xCss + w * 0.5;\n\n if (left < prevRight + MIN_X_LABEL_GAP_CSS_PX) {\n ok = false;\n break;\n }\n prevRight = right;\n }\n\n if (ok) {\n return { tickCount, tickValues };\n }\n }\n\n return { tickCount: MIN_TIME_X_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, MIN_TIME_X_TICK_COUNT) };\n};\n","/**\n * Axis tick computation and formatting.\n *\n * Generates tick values and formatting for linear axes. Handles decimal precision\n * determination based on tick step size and provides number formatting utilities.\n *\n * @module computeAxisTicks\n */\n\n/**\n * Default maximum fraction digits for tick formatting.\n */\nconst DEFAULT_MAX_TICK_FRACTION_DIGITS = 8;\n\n/**\n * Generates evenly-spaced tick values between domain min and max.\n *\n * @param domainMin - Minimum value of the domain\n * @param domainMax - Maximum value of the domain\n * @param tickCount - Number of ticks to generate (must be >= 1)\n * @returns Array of tick values\n */\nexport function generateLinearTicks(domainMin: number, domainMax: number, tickCount: number): number[] {\n const count = Math.max(1, Math.floor(tickCount));\n const ticks: number[] = new Array(count);\n for (let i = 0; i < count; i++) {\n const t = count === 1 ? 0.5 : i / (count - 1);\n const v = domainMin + t * (domainMax - domainMin);\n ticks[i] = v;\n }\n return ticks;\n}\n\n/**\n * Computes the maximum number of decimal places needed to display a tick step cleanly.\n *\n * Prefers \"clean\" decimal representations (e.g., 2.5, 0.25, 0.125) without relying on\n * magnitude alone. Accepts floating-point noise and caps the search to keep formatting\n * reasonable.\n *\n * @param tickStep - The step size between ticks\n * @param cap - Maximum number of decimal places to consider (default: 8)\n * @returns Number of decimal places (0 to cap)\n */\nexport function computeMaxFractionDigitsFromStep(tickStep: number, cap: number = DEFAULT_MAX_TICK_FRACTION_DIGITS): number {\n const stepAbs = Math.abs(tickStep);\n if (!Number.isFinite(stepAbs) || stepAbs === 0) return 0;\n\n // Prefer \"clean\" decimal representations (e.g. 2.5, 0.25, 0.125) without relying on magnitude alone.\n // We accept floating-point noise and cap the search to keep formatting reasonable.\n for (let d = 0; d <= cap; d++) {\n const scaled = stepAbs * 10 ** d;\n const rounded = Math.round(scaled);\n const err = Math.abs(scaled - rounded);\n const tol = 1e-9 * Math.max(1, Math.abs(scaled));\n if (err <= tol) return d;\n }\n\n // Fallback for repeating decimals (e.g. 1/3): show a small number of digits based on magnitude.\n // The +1 nudges values like 0.333.. towards 2 decimals rather than 1.\n return Math.max(0, Math.min(cap, 1 - Math.floor(Math.log10(stepAbs)) + 1));\n}\n\n/**\n * Creates an Intl.NumberFormat for tick value formatting.\n *\n * Automatically determines the appropriate number of decimal places based on the\n * tick step size using `computeMaxFractionDigitsFromStep()`.\n *\n * @param tickStep - The step size between ticks\n * @returns Intl.NumberFormat configured for tick formatting\n */\nexport function createTickFormatter(tickStep: number): Intl.NumberFormat {\n const maximumFractionDigits = computeMaxFractionDigitsFromStep(tickStep);\n return new Intl.NumberFormat(undefined, { maximumFractionDigits });\n}\n\n/**\n * Formats a numeric tick value using the provided number formatter.\n *\n * Handles edge cases:\n * - Non-finite values return null\n * - Values near zero (< 1e-12) are normalized to 0 to avoid \"-0\" display\n * - Unexpected \"NaN\" output from formatter is guarded against\n *\n * @param nf - Intl.NumberFormat to use for formatting\n * @param v - Numeric value to format\n * @returns Formatted string or null if value cannot be formatted\n */\nexport function formatTickValue(nf: Intl.NumberFormat, v: number): string | null {\n if (!Number.isFinite(v)) return null;\n // Avoid displaying \"-0\" from floating-point artifacts.\n const normalized = Math.abs(v) < 1e-12 ? 0 : v;\n const formatted = nf.format(normalized);\n // Guard against unexpected output like \"NaN\" even after the finite check (defensive).\n return formatted === 'NaN' ? null : formatted;\n}\n","/**\n * Shared axis label styling utilities.\n */\n\n/**\n * Theme configuration for axis labels.\n */\nexport interface AxisLabelThemeConfig {\n readonly fontSize: number;\n readonly fontFamily: string;\n readonly textColor: string;\n}\n\n/**\n * Calculates the font size for axis titles (larger than regular tick labels).\n */\nexport function getAxisTitleFontSize(baseFontSize: number): number {\n return Math.max(\n baseFontSize + 1,\n Math.round(baseFontSize * 1.15)\n );\n}\n\n/**\n * Applies consistent styling to an axis label span element.\n */\nexport function styleAxisLabelSpan(\n span: HTMLSpanElement,\n isTitle: boolean,\n theme: AxisLabelThemeConfig\n): void {\n // Set inline styles\n span.dir = 'auto';\n span.style.fontFamily = theme.fontFamily;\n\n // Axis titles are bold\n if (isTitle) {\n span.style.fontWeight = '600';\n }\n}\n\n","/**\n * Axis Label Rendering Utilities\n *\n * Generates DOM-based axis labels and titles for cartesian charts.\n * Labels are positioned using canvas-local CSS coordinates and rendered\n * into a text overlay element.\n *\n * @module renderAxisLabels\n */\n\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { TextOverlay, TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport { getCanvasCssWidth, getCanvasCssHeight } from '../utils/canvasUtils';\nimport { formatTimeTickValue } from '../utils/timeAxisUtils';\nimport { formatTickValue, createTickFormatter } from '../axis/computeAxisTicks';\nimport { finiteOrUndefined } from '../utils/dataPointUtils';\nimport { getAxisTitleFontSize } from '../../../utils/axisLabelStyling';\n\nconst DEFAULT_TICK_LENGTH_CSS_PX = 6;\nconst LABEL_PADDING_CSS_PX = 4;\nconst DEFAULT_TICK_COUNT = 5;\n\nexport interface AxisLabelRenderContext {\n gpuContext: {\n canvas: HTMLCanvasElement | OffscreenCanvas | null;\n };\n currentOptions: ResolvedChartGPUOptions;\n xScale: LinearScale;\n yScale: LinearScale;\n xTickValues: ReadonlyArray<number>;\n plotClipRect: {\n left: number;\n right: number;\n top: number;\n bottom: number;\n };\n visibleXRangeMs: number;\n}\n\nfunction clipXToCanvasCssPx(xClip: number, canvasCssWidth: number): number {\n return ((xClip + 1) / 2) * canvasCssWidth;\n}\n\nfunction clipYToCanvasCssPx(yClip: number, canvasCssHeight: number): number {\n return ((1 - yClip) / 2) * canvasCssHeight;\n}\n\nfunction styleAxisLabelSpan(span: HTMLSpanElement, isTitle: boolean, theme: ResolvedChartGPUOptions['theme']): void {\n span.style.fontFamily = theme.fontFamily;\n span.style.fontWeight = isTitle ? '500' : '400';\n span.style.userSelect = 'none';\n span.style.pointerEvents = 'none';\n}\n\n/**\n * Renders axis labels and titles to the text overlay.\n *\n * Generates X and Y axis tick labels with appropriate formatting,\n * and renders axis titles if configured.\n *\n * @param axisLabelOverlay - Text overlay for rendering labels\n * @param overlayContainer - DOM container for overlay positioning\n * @param context - Rendering context with scales, options, and layout\n */\nexport function renderAxisLabels(\n axisLabelOverlay: TextOverlay | null,\n overlayContainer: HTMLElement | null,\n context: AxisLabelRenderContext\n): void {\n const { gpuContext, currentOptions, xScale, yScale, xTickValues, plotClipRect, visibleXRangeMs } = context;\n\n const hasCartesianSeries = currentOptions.series.some((s) => s.type !== 'pie');\n if (!hasCartesianSeries || !axisLabelOverlay || !overlayContainer) {\n return;\n }\n\n const canvas = gpuContext.canvas;\n if (!canvas) return;\n\n // Get canvas dimensions\n const canvasCssWidth = getCanvasCssWidth(canvas as HTMLCanvasElement);\n const canvasCssHeight = getCanvasCssHeight(canvas as HTMLCanvasElement);\n if (canvasCssWidth <= 0 || canvasCssHeight <= 0) return;\n\n // Calculate offsets (only for HTMLCanvasElement with DOM)\n const offsetX = (canvas as HTMLCanvasElement).offsetLeft || 0;\n const offsetY = (canvas as HTMLCanvasElement).offsetTop || 0;\n\n const plotLeftCss = clipXToCanvasCssPx(plotClipRect.left, canvasCssWidth);\n const plotRightCss = clipXToCanvasCssPx(plotClipRect.right, canvasCssWidth);\n const plotTopCss = clipYToCanvasCssPx(plotClipRect.top, canvasCssHeight);\n const plotBottomCss = clipYToCanvasCssPx(plotClipRect.bottom, canvasCssHeight);\n\n // Clear axis label overlay\n axisLabelOverlay.clear();\n\n // X-axis tick labels\n const xTickLengthCssPx = currentOptions.xAxis.tickLength ?? DEFAULT_TICK_LENGTH_CSS_PX;\n const xLabelY = plotBottomCss + xTickLengthCssPx + LABEL_PADDING_CSS_PX + currentOptions.theme.fontSize * 0.5;\n const isTimeXAxis = currentOptions.xAxis.type === 'time';\n const xFormatter = (() => {\n if (isTimeXAxis) return null;\n const xDomainMin = finiteOrUndefined(currentOptions.xAxis.min) ?? xScale.invert(plotClipRect.left);\n const xDomainMax = finiteOrUndefined(currentOptions.xAxis.max) ?? xScale.invert(plotClipRect.right);\n const xTickCount = xTickValues.length;\n const xTickStep = xTickCount === 1 ? 0 : (xDomainMax - xDomainMin) / (xTickCount - 1);\n return createTickFormatter(xTickStep);\n })();\n\n for (let i = 0; i < xTickValues.length; i++) {\n const v = xTickValues[i]!;\n const xClip = xScale.scale(v);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n\n const anchor: TextOverlayAnchor =\n xTickValues.length === 1 ? 'middle' : i === 0 ? 'start' : i === xTickValues.length - 1 ? 'end' : 'middle';\n const label = isTimeXAxis ? formatTimeTickValue(v, visibleXRangeMs) : formatTickValue(xFormatter!, v);\n if (label == null) continue;\n\n const span = axisLabelOverlay.addLabel(label, offsetX + xCss, offsetY + xLabelY, {\n fontSize: currentOptions.theme.fontSize,\n color: currentOptions.theme.textColor,\n anchor,\n });\n styleAxisLabelSpan(span, false, currentOptions.theme);\n }\n\n // Y-axis tick labels\n const yTickCount = DEFAULT_TICK_COUNT;\n const yTickLengthCssPx = currentOptions.yAxis.tickLength ?? DEFAULT_TICK_LENGTH_CSS_PX;\n const yDomainMin = finiteOrUndefined(currentOptions.yAxis.min) ?? yScale.invert(plotClipRect.bottom);\n const yDomainMax = finiteOrUndefined(currentOptions.yAxis.max) ?? yScale.invert(plotClipRect.top);\n const yTickStep = yTickCount <= 1 ? 0 : (yDomainMax - yDomainMin) / (yTickCount - 1);\n const yFormatter = createTickFormatter(yTickStep);\n const yLabelX = plotLeftCss - yTickLengthCssPx - LABEL_PADDING_CSS_PX;\n const ySpans: HTMLSpanElement[] = [];\n\n for (let i = 0; i < yTickCount; i++) {\n const t = yTickCount <= 1 ? 0.5 : i / (yTickCount - 1);\n const v = yDomainMin + t * (yDomainMax - yDomainMin);\n const yClip = yScale.scale(v);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n\n const label = formatTickValue(yFormatter, v);\n if (label == null) continue;\n\n const span = axisLabelOverlay.addLabel(label, offsetX + yLabelX, offsetY + yCss, {\n fontSize: currentOptions.theme.fontSize,\n color: currentOptions.theme.textColor,\n anchor: 'end',\n });\n styleAxisLabelSpan(span, false, currentOptions.theme);\n ySpans.push(span);\n }\n\n // X-axis title\n const axisNameFontSize = getAxisTitleFontSize(currentOptions.theme.fontSize);\n const xAxisName = currentOptions.xAxis.name?.trim() ?? '';\n if (xAxisName.length > 0) {\n const xCenter = (plotLeftCss + plotRightCss) / 2;\n const xTickLabelsBottom = xLabelY + currentOptions.theme.fontSize * 0.5;\n const hasSliderZoom = currentOptions.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n const sliderTrackHeightCssPx = 32;\n const bottomLimitCss = hasSliderZoom ? canvasCssHeight - sliderTrackHeightCssPx : canvasCssHeight;\n const xTitleY = (xTickLabelsBottom + bottomLimitCss) / 2;\n\n const span = axisLabelOverlay.addLabel(xAxisName, offsetX + xCenter, offsetY + xTitleY, {\n fontSize: axisNameFontSize,\n color: currentOptions.theme.textColor,\n anchor: 'middle',\n });\n styleAxisLabelSpan(span, true, currentOptions.theme);\n }\n\n // Y-axis title\n const yAxisName = currentOptions.yAxis.name?.trim() ?? '';\n if (yAxisName.length > 0) {\n // Measure actual rendered label widths from DOM\n const maxTickLabelWidth =\n ySpans.length === 0 ? 0 : ySpans.reduce((max, s) => Math.max(max, s.getBoundingClientRect().width), 0);\n\n const yCenter = (plotTopCss + plotBottomCss) / 2;\n const yTickLabelLeft = yLabelX - maxTickLabelWidth;\n const yTitleX = yTickLabelLeft - LABEL_PADDING_CSS_PX - axisNameFontSize * 0.5;\n\n const span = axisLabelOverlay.addLabel(yAxisName, offsetX + yTitleX, offsetY + yCenter, {\n fontSize: axisNameFontSize,\n color: currentOptions.theme.textColor,\n anchor: 'middle',\n rotation: -90,\n });\n styleAxisLabelSpan(span, true, currentOptions.theme);\n }\n}\n","/**\n * Annotation Label Rendering Utilities\n *\n * Generates DOM-based annotation labels for cartesian charts.\n * Handles template rendering, coordinate transformations, and styling\n * for lineX, lineY, point, and text annotations.\n *\n * @module renderAnnotationLabels\n */\n\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { TextOverlay, TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport { parseCssColorToRgba01 } from '../../../utils/colors';\nimport { clamp01 } from '../utils/axisUtils';\nimport { assertUnreachable } from '../utils/dataPointUtils';\n\nexport interface AnnotationLabelRenderContext {\n currentOptions: ResolvedChartGPUOptions;\n xScale: LinearScale;\n yScale: LinearScale;\n canvasCssWidthForAnnotations: number;\n canvasCssHeightForAnnotations: number;\n plotLeftCss: number;\n plotTopCss: number;\n plotWidthCss: number;\n plotHeightCss: number;\n canvas: HTMLCanvasElement | OffscreenCanvas;\n}\n\ninterface AnnotationLabelData {\n text: string;\n x: number;\n y: number;\n anchor: TextOverlayAnchor;\n color: string;\n fontSize: number;\n background?: {\n backgroundColor: string;\n padding?: readonly [number, number, number, number];\n borderRadius?: number;\n };\n}\n\nfunction isHTMLCanvasElement(canvas: HTMLCanvasElement | OffscreenCanvas): canvas is HTMLCanvasElement {\n return 'offsetLeft' in canvas;\n}\n\nfunction clipXToCanvasCssPx(xClip: number, canvasCssWidth: number): number {\n return ((xClip + 1) / 2) * canvasCssWidth;\n}\n\nfunction clipYToCanvasCssPx(yClip: number, canvasCssHeight: number): number {\n return ((1 - yClip) / 2) * canvasCssHeight;\n}\n\nfunction toCssRgba(color: string, opacity01: number): string {\n const base = parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n const a = clamp01(base[3] * clamp01(opacity01));\n const r = Math.round(clamp01(base[0]) * 255);\n const g = Math.round(clamp01(base[1]) * 255);\n const b = Math.round(clamp01(base[2]) * 255);\n return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\nfunction formatNumber(n: number, decimals?: number): string {\n if (!Number.isFinite(n)) return '';\n if (decimals == null) return String(n);\n const d = Math.min(20, Math.max(0, Math.floor(decimals)));\n return n.toFixed(d);\n}\n\n// PERFORMANCE: Cache regex pattern (compiled once per render, reused for all templates)\nconst templateRegex = /\\{(x|y|value|name)\\}/g;\n\nfunction renderTemplate(\n template: string,\n values: Readonly<{ x?: number; y?: number; value?: number; name?: string }>,\n decimals?: number\n): string {\n // PERFORMANCE: Reset regex lastIndex to ensure consistent behavior\n templateRegex.lastIndex = 0;\n return template.replace(templateRegex, (_m, key) => {\n if (key === 'name') return values.name ?? '';\n const v = (values as any)[key] as number | undefined;\n return v == null ? '' : formatNumber(v, decimals);\n });\n}\n\nfunction mapAnchor(anchor: 'start' | 'center' | 'end' | undefined): TextOverlayAnchor {\n switch (anchor) {\n case 'center':\n return 'middle';\n case 'end':\n return 'end';\n case 'start':\n default:\n return 'start';\n }\n}\n\n/**\n * Renders annotation labels to the text overlay.\n *\n * Processes annotations and generates DOM labels with template support,\n * coordinate transformations, and background styling.\n *\n * @param annotationOverlay - Text overlay for rendering labels\n * @param overlayContainer - DOM container for overlay positioning\n * @param context - Rendering context with scales, options, and layout\n */\nexport function renderAnnotationLabels(\n annotationOverlay: TextOverlay | null,\n overlayContainer: HTMLElement | null,\n context: AnnotationLabelRenderContext\n): void {\n const {\n currentOptions,\n xScale,\n yScale,\n canvasCssWidthForAnnotations,\n canvasCssHeightForAnnotations,\n plotLeftCss,\n plotTopCss,\n plotWidthCss,\n plotHeightCss,\n canvas,\n } = context;\n\n const hasCartesianSeries = currentOptions.series.some((s) => s.type !== 'pie');\n if (!hasCartesianSeries || !annotationOverlay || !overlayContainer) {\n return;\n }\n\n // Validate canvas dimensions\n if (\n !canvas ||\n canvasCssWidthForAnnotations <= 0 ||\n canvasCssHeightForAnnotations <= 0 ||\n plotWidthCss <= 0 ||\n plotHeightCss <= 0\n ) {\n annotationOverlay.clear();\n return;\n }\n\n const offsetX = isHTMLCanvasElement(canvas) ? canvas.offsetLeft : 0;\n const offsetY = isHTMLCanvasElement(canvas) ? canvas.offsetTop : 0;\n\n annotationOverlay.clear();\n\n const annotations = currentOptions.annotations ?? [];\n if (annotations.length === 0) {\n return;\n }\n\n const labelsOut: AnnotationLabelData[] = [];\n\n for (let i = 0; i < annotations.length; i++) {\n const a = annotations[i]!;\n\n const labelCfg = a.label;\n const wantsLabel = labelCfg != null || a.type === 'text';\n if (!wantsLabel) continue;\n\n // Compute anchor point (canvas-local CSS px)\n let anchorXCss: number | null = null;\n let anchorYCss: number | null = null;\n let values: { x?: number; y?: number; value?: number; name?: string } = { name: a.id ?? '' };\n\n switch (a.type) {\n case 'lineX': {\n const xClip = xScale.scale(a.x);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidthForAnnotations);\n anchorXCss = xCss;\n anchorYCss = plotTopCss;\n values = { ...values, x: a.x, value: a.x };\n break;\n }\n case 'lineY': {\n const yClip = yScale.scale(a.y);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeightForAnnotations);\n anchorXCss = plotLeftCss;\n // Offset label 8px above the horizontal line (negative Y = upward)\n anchorYCss = yCss - 8;\n values = { ...values, y: a.y, value: a.y };\n break;\n }\n case 'point': {\n const xClip = xScale.scale(a.x);\n const yClip = yScale.scale(a.y);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidthForAnnotations);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeightForAnnotations);\n anchorXCss = xCss;\n anchorYCss = yCss;\n values = { ...values, x: a.x, y: a.y, value: a.y };\n break;\n }\n case 'text': {\n if (a.position.space === 'data') {\n const xClip = xScale.scale(a.position.x);\n const yClip = yScale.scale(a.position.y);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidthForAnnotations);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeightForAnnotations);\n anchorXCss = xCss;\n anchorYCss = yCss;\n values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n } else {\n const xCss = plotLeftCss + a.position.x * plotWidthCss;\n const yCss = plotTopCss + a.position.y * plotHeightCss;\n anchorXCss = xCss;\n anchorYCss = yCss;\n values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n }\n break;\n }\n default:\n assertUnreachable(a);\n }\n\n if (anchorXCss == null || anchorYCss == null || !Number.isFinite(anchorXCss) || !Number.isFinite(anchorYCss)) {\n continue;\n }\n\n const dx = labelCfg?.offset?.[0] ?? 0;\n const dy = labelCfg?.offset?.[1] ?? 0;\n const x = anchorXCss + dx;\n const y = anchorYCss + dy;\n\n // Label text selection (explicit > template > defaults)\n const text =\n labelCfg?.text ??\n (labelCfg?.template\n ? renderTemplate(labelCfg.template, values, labelCfg.decimals)\n : labelCfg\n ? (() => {\n const defaultTemplate =\n a.type === 'lineX'\n ? 'x={x}'\n : a.type === 'lineY'\n ? 'y={y}'\n : a.type === 'point'\n ? '({x}, {y})'\n : a.type === 'text'\n ? a.text\n : '';\n return defaultTemplate.includes('{')\n ? renderTemplate(defaultTemplate, values, labelCfg.decimals)\n : defaultTemplate;\n })()\n : a.type === 'text'\n ? a.text\n : '');\n\n const trimmed = typeof text === 'string' ? text.trim() : '';\n if (trimmed.length === 0) continue;\n\n const anchor = mapAnchor(labelCfg?.anchor);\n const color = a.style?.color ?? currentOptions.theme.textColor;\n const fontSize = currentOptions.theme.fontSize;\n\n const bg = labelCfg?.background;\n const bgColor = bg?.color != null ? toCssRgba(bg.color, bg.opacity ?? 1) : undefined;\n const padding = (() => {\n const p = bg?.padding;\n if (typeof p === 'number' && Number.isFinite(p)) return [p, p, p, p] as const;\n if (Array.isArray(p) && p.length === 4 && p.every((n) => typeof n === 'number' && Number.isFinite(n))) {\n return [p[0], p[1], p[2], p[3]] as const;\n }\n return bg ? ([2, 4, 2, 4] as const) : undefined;\n })();\n const borderRadius =\n typeof bg?.borderRadius === 'number' && Number.isFinite(bg.borderRadius) ? bg.borderRadius : undefined;\n\n const labelData: AnnotationLabelData = {\n text: trimmed,\n x: offsetX + x,\n y: offsetY + y,\n anchor,\n color,\n fontSize,\n ...(bgColor\n ? {\n background: {\n backgroundColor: bgColor,\n ...(padding ? { padding } : {}),\n ...(borderRadius != null ? { borderRadius } : {}),\n },\n }\n : {}),\n };\n\n labelsOut.push(labelData);\n\n // Render label to DOM\n const span = annotationOverlay.addLabel(trimmed, labelData.x, labelData.y, {\n fontSize,\n color,\n anchor,\n });\n\n if (labelData.background) {\n span.style.backgroundColor = labelData.background.backgroundColor;\n span.style.display = 'inline-block';\n span.style.boxSizing = 'border-box';\n if (labelData.background.padding) {\n const [t, r, b, l] = labelData.background.padding;\n span.style.padding = `${t}px ${r}px ${b}px ${l}px`;\n }\n if (labelData.background.borderRadius != null) {\n span.style.borderRadius = `${labelData.background.borderRadius}px`;\n }\n }\n }\n}\n","import type { DataPoint, CartesianSeriesData, DataPointTuple, ScatterPointTuple } from '../config/types';\nimport type {\n ResolvedBarSeriesConfig,\n ResolvedScatterSeriesConfig,\n ResolvedSeriesConfig,\n} from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { getPointCount, getX, getY, getSize } from '../data/cartesianData';\nimport { isMonotonicNonDecreasingFiniteX } from '../core/renderCoordinator/data/computeVisibleSlice';\n\nconst DEFAULT_MAX_DISTANCE_PX = 20;\nconst DEFAULT_BAR_GAP = 0.01; // Minimal gap between bars within a group (was 0.1)\nconst DEFAULT_BAR_CATEGORY_GAP = 0.2;\nconst DEFAULT_SCATTER_RADIUS_CSS_PX = 4;\n\n/**\n * Binary search: finds the lower bound index (first element >= target) in monotonic cartesian data.\n * Returns index in range [0, n] where n = point count.\n */\nfunction lowerBoundX(data: CartesianSeriesData, xTarget: number): number {\n let lo = 0;\n let hi = getPointCount(data);\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = getX(data, mid);\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nexport type NearestPointMatch = Readonly<{\n seriesIndex: number;\n dataIndex: number;\n point: DataPoint;\n /** Euclidean distance in range units. */\n distance: number;\n}>;\n\nexport type BarBounds = { left: number; right: number; top: number; bottom: number };\n\nexport function isPointInBar(x: number, y: number, barBounds: BarBounds): boolean {\n // Inclusive bounds.\n // Note: stacked bar segments can share edges; tie-breaking is handled by the caller.\n return (\n x >= barBounds.left &&\n x <= barBounds.right &&\n y >= barBounds.top &&\n y <= barBounds.bottom\n );\n}\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\nconst parsePercent = (value: string): number | null => {\n const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n if (!m) return null;\n const p = Number(m[1]) / 100;\n return Number.isFinite(p) ? p : null;\n};\n\nconst normalizeStackId = (stack: unknown): string => {\n if (typeof stack !== 'string') return '';\n const trimmed = stack.trim();\n return trimmed.length > 0 ? trimmed : '';\n};\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst getPointSizeCssPx = (p: DataPoint): number | null => {\n if (isTupleDataPoint(p)) {\n const s = p[2];\n return typeof s === 'number' && Number.isFinite(s) ? s : null;\n }\n const s = p.size;\n return typeof s === 'number' && Number.isFinite(s) ? s : null;\n};\n\nconst toScatterTuple = (p: DataPoint): ScatterPointTuple => {\n if (isTupleDataPoint(p)) return p;\n return [p.x, p.y, p.size] as const;\n};\n\nconst safeCallSymbolSize = (\n fn: (value: ScatterPointTuple) => number,\n value: ScatterPointTuple,\n): number | null => {\n try {\n const v = fn(value);\n return typeof v === 'number' && Number.isFinite(v) ? v : null;\n } catch {\n return null;\n }\n};\n\nconst getScatterRadiusCssPx = (seriesCfg: ResolvedScatterSeriesConfig, p: DataPoint): number => {\n // Mirrors `createScatterRenderer.ts` size semantics (but stays in CSS px):\n // point.size -> series.symbolSize -> default 4px.\n const perPoint = getPointSizeCssPx(p);\n if (perPoint != null) return Math.max(0, perPoint);\n\n const seriesSymbolSize = seriesCfg.symbolSize;\n if (typeof seriesSymbolSize === 'number') {\n return Number.isFinite(seriesSymbolSize)\n ? Math.max(0, seriesSymbolSize)\n : DEFAULT_SCATTER_RADIUS_CSS_PX;\n }\n if (typeof seriesSymbolSize === 'function') {\n const v = safeCallSymbolSize(seriesSymbolSize, toScatterTuple(p));\n return v == null ? DEFAULT_SCATTER_RADIUS_CSS_PX : Math.max(0, v);\n }\n\n return DEFAULT_SCATTER_RADIUS_CSS_PX;\n};\n\n\n// Note: we intentionally do NOT compute “nearest bar by distance”.\n// Bars are only considered a match when the cursor is inside their rect bounds.\n\nexport type BarClusterSlots = Readonly<{\n clusterIndexBySeries: ReadonlyArray<number>;\n clusterCount: number;\n stackIdBySeries: ReadonlyArray<string>;\n}>;\n\nexport function computeBarClusterSlots(\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n): BarClusterSlots {\n // Cluster slots (mirrors `createBarRenderer.ts`):\n // - Each unique non-empty stackId gets a single cluster slot.\n // - Each unstacked series gets its own cluster slot.\n const stackIdToClusterIndex = new Map<string, number>();\n const clusterIndexBySeries: number[] = new Array(seriesConfigs.length);\n const stackIdBySeries: string[] = new Array(seriesConfigs.length);\n\n let clusterCount = 0;\n for (let i = 0; i < seriesConfigs.length; i++) {\n const stackId = normalizeStackId(seriesConfigs[i].stack);\n stackIdBySeries[i] = stackId;\n\n if (stackId !== '') {\n const existing = stackIdToClusterIndex.get(stackId);\n if (existing !== undefined) {\n clusterIndexBySeries[i] = existing;\n } else {\n const idx = clusterCount++;\n stackIdToClusterIndex.set(stackId, idx);\n clusterIndexBySeries[i] = idx;\n }\n } else {\n clusterIndexBySeries[i] = clusterCount++;\n }\n }\n\n return {\n clusterIndexBySeries,\n clusterCount: Math.max(1, clusterCount),\n stackIdBySeries,\n };\n}\n\nexport function computeBarCategoryStep(seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number {\n const xs: number[] = [];\n for (let s = 0; s < seriesConfigs.length; s++) {\n const data = seriesConfigs[s].data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n if (Number.isFinite(x)) xs.push(x);\n }\n }\n\n if (xs.length < 2) return 1;\n xs.sort((a, b) => a - b);\n\n let minStep = Number.POSITIVE_INFINITY;\n for (let i = 1; i < xs.length; i++) {\n const d = xs[i] - xs[i - 1];\n if (d > 0 && d < minStep) minStep = d;\n }\n return Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n}\n\nexport function computeCategoryWidthPx(\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n xScale: LinearScale,\n categoryStep: number,\n): number {\n // Primary path (mirrors renderer): derive width from domain step via scale().\n if (Number.isFinite(categoryStep) && categoryStep > 0) {\n const x0 = 0;\n const p0 = xScale.scale(x0);\n const p1 = xScale.scale(x0 + categoryStep);\n const w = Math.abs(p1 - p0);\n if (Number.isFinite(w) && w > 0) return w;\n }\n\n // Fallback: compute min positive delta in *scaled* x positions.\n const sx: number[] = [];\n for (let s = 0; s < seriesConfigs.length; s++) {\n const data = seriesConfigs[s].data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n if (!Number.isFinite(x)) continue;\n const px = xScale.scale(x);\n if (Number.isFinite(px)) sx.push(px);\n }\n }\n if (sx.length < 2) return 0;\n sx.sort((a, b) => a - b);\n\n let minDx = Number.POSITIVE_INFINITY;\n for (let i = 1; i < sx.length; i++) {\n const d = sx[i] - sx[i - 1];\n if (d > 0 && d < minDx) minDx = d;\n }\n\n return Number.isFinite(minDx) && minDx > 0 ? minDx : 0;\n}\n\ntype BarSharedLayout = Readonly<{\n barWidth?: number | string;\n barGap?: number;\n barCategoryGap?: number;\n}>;\n\nconst computeSharedBarLayout = (\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n): BarSharedLayout => {\n let barWidth: number | string | undefined = undefined;\n let barGap: number | undefined = undefined;\n let barCategoryGap: number | undefined = undefined;\n\n for (let i = 0; i < seriesConfigs.length; i++) {\n const s = seriesConfigs[i];\n if (barWidth === undefined && s.barWidth !== undefined) barWidth = s.barWidth;\n if (barGap === undefined && s.barGap !== undefined) barGap = s.barGap;\n if (barCategoryGap === undefined && s.barCategoryGap !== undefined) barCategoryGap = s.barCategoryGap;\n }\n\n return { barWidth, barGap, barCategoryGap };\n};\n\nexport type BarLayoutPx = Readonly<{\n categoryStep: number;\n categoryWidthPx: number;\n barWidthPx: number;\n gapPx: number;\n clusterWidthPx: number;\n clusterSlots: BarClusterSlots;\n}>;\n\nexport function computeBarLayoutPx(\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n xScale: LinearScale,\n): BarLayoutPx {\n const clusterSlots = computeBarClusterSlots(seriesConfigs);\n const clusterCount = clusterSlots.clusterCount;\n\n const categoryStep = computeBarCategoryStep(seriesConfigs);\n const categoryWidthPx = computeCategoryWidthPx(seriesConfigs, xScale, categoryStep);\n\n const layout = computeSharedBarLayout(seriesConfigs);\n const barGap = clamp01(layout.barGap ?? DEFAULT_BAR_GAP);\n const barCategoryGap = clamp01(layout.barCategoryGap ?? DEFAULT_BAR_CATEGORY_GAP);\n\n const categoryInnerWidthPx = Math.max(0, categoryWidthPx * (1 - barCategoryGap));\n const denom = clusterCount + Math.max(0, clusterCount - 1) * barGap;\n const maxBarWidthPx = denom > 0 ? categoryInnerWidthPx / denom : 0;\n\n let barWidthPx = 0;\n const rawBarWidth = layout.barWidth;\n if (typeof rawBarWidth === 'number') {\n barWidthPx = Math.max(0, rawBarWidth);\n barWidthPx = Math.min(barWidthPx, maxBarWidthPx);\n } else if (typeof rawBarWidth === 'string') {\n const p = parsePercent(rawBarWidth);\n barWidthPx = p == null ? 0 : maxBarWidthPx * clamp01(p);\n }\n\n if (!(barWidthPx > 0)) {\n // Auto-width: max per-bar width that still avoids overlap (given clusterCount and barGap).\n barWidthPx = maxBarWidthPx;\n }\n\n const gapPx = barWidthPx * barGap;\n const clusterWidthPx = clusterCount * barWidthPx + Math.max(0, clusterCount - 1) * gapPx;\n\n return {\n categoryStep,\n categoryWidthPx,\n barWidthPx,\n gapPx,\n clusterWidthPx,\n clusterSlots,\n };\n}\n\nconst computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let s = 0; s < seriesConfigs.length; s++) {\n const data = seriesConfigs[s].data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const y = getY(data, i);\n if (!Number.isFinite(y)) continue;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n }\n\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) return 0;\n if (yMin <= 0 && 0 <= yMax) return 0;\n return Math.abs(yMin) < Math.abs(yMax) ? yMin : yMax;\n};\n\nexport function inferPlotHeightPxForBarHitTesting(\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n yScale: LinearScale,\n): number {\n // We don't have direct access to the scale range endpoints, so infer the plot height in range-space.\n // In the common ChartGPU interaction setup, yScale.range(plotHeightCss, 0), so max(scaledY) should\n // approximate plotHeightCss (or be <= plotHeightCss if axis min/max are overridden).\n let maxY = 0;\n for (let s = 0; s < seriesConfigs.length; s++) {\n const data = seriesConfigs[s].data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const y = getY(data, i);\n if (!Number.isFinite(y)) continue;\n const py = yScale.scale(y);\n if (Number.isFinite(py) && py > maxY) maxY = py;\n }\n }\n return Math.max(0, maxY);\n}\n\nexport function computeBaselineDomainAndPx(\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n yScale: LinearScale,\n plotHeightPx: number,\n): Readonly<{ baselineDomain: number; baselinePx: number }> {\n // Axis-aware baseline logic (mirrors `createBarRenderer.ts`, but in px-space):\n // Determine visible y-domain from yScale via invert(bottom/top) where top=0 and bottom=plotHeightPx.\n const yDomainA = yScale.invert(plotHeightPx);\n const yDomainB = yScale.invert(0);\n const yMin = Math.min(yDomainA, yDomainB);\n const yMax = Math.max(yDomainA, yDomainB);\n\n let baselineDomain: number;\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n baselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n } else if (yMin <= 0 && 0 <= yMax) {\n baselineDomain = 0;\n } else if (yMin > 0) {\n baselineDomain = yMin;\n } else if (yMax < 0) {\n baselineDomain = yMax;\n } else {\n baselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n }\n\n let baselinePx = yScale.scale(baselineDomain);\n if (!Number.isFinite(baselinePx)) {\n baselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n baselinePx = yScale.scale(baselineDomain);\n }\n if (!Number.isFinite(baselinePx)) {\n baselineDomain = 0;\n baselinePx = yScale.scale(0);\n }\n\n return { baselineDomain, baselinePx };\n}\n\nexport function bucketStackedXKey(\n xCenterPx: number,\n categoryWidthPx: number,\n xDomain: number,\n categoryStep: number,\n): number {\n // Match renderer intent:\n // - Prefer bucketing in *range-space* to avoid float-equality issues in domain-x.\n // - Requirement: Math.round(xCenterPx / categoryWidthPx) (grid-local).\n if (Number.isFinite(categoryWidthPx) && categoryWidthPx > 0 && Number.isFinite(xCenterPx)) {\n return Math.round(xCenterPx / categoryWidthPx);\n }\n if (Number.isFinite(categoryStep) && categoryStep > 0 && Number.isFinite(xDomain)) {\n return Math.round(xDomain / categoryStep);\n }\n return Math.round(xDomain * 1e6);\n}\n\n/**\n * Finds the nearest data point to the given cursor position across all series.\n *\n * Coordinate system contract:\n * - `x`/`y` MUST be in the same units as `xScale`/`yScale` **range**.\n * - If you pass **grid-local CSS pixels** (e.g. `payload.gridX` / `payload.gridY` from `createEventManager`),\n * then `xScale.range()` / `yScale.range()` must also be in **CSS pixels**.\n * - If your scales are in **clip space** (e.g. \\([-1, 1]\\)), pass cursor coordinates in clip space too.\n *\n * DPR/WebGPU note:\n * - Pointer events are naturally in CSS pixels; WebGPU rendering often uses device pixels or clip space.\n * This helper stays agnostic and only computes Euclidean distance in the provided **range-space**.\n *\n * Performance notes:\n * - Assumes each series is sorted by increasing x in domain space.\n * - Uses per-series lower-bound binary search on x, then expands outward while x-distance alone can still win.\n * - Uses squared distance comparisons and computes `sqrt` only for the final match.\n * - Skips non-finite points and any points whose scaled coordinates are NaN.\n */\nexport function findNearestPoint(\n series: ReadonlyArray<ResolvedSeriesConfig>,\n x: number,\n y: number,\n xScale: LinearScale,\n yScale: LinearScale,\n maxDistance: number = DEFAULT_MAX_DISTANCE_PX,\n): NearestPointMatch | null {\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\n const md = Number.isFinite(maxDistance)\n ? Math.max(0, maxDistance)\n : DEFAULT_MAX_DISTANCE_PX;\n const maxDistSq = md * md;\n\n const xTarget = xScale.invert(x);\n if (!Number.isFinite(xTarget)) return null;\n\n let bestSeriesIndex = -1;\n let bestDataIndex = -1;\n let bestPoint: DataPoint | null = null;\n let bestDistSq = Number.POSITIVE_INFINITY;\n\n // Story 4.6: Bar hit-testing (range-space bounds).\n // - Only counts as a match when cursor is inside a bar rect.\n // - For stacked bars, uses the same stacking bucket logic as the bar renderer (xKey bucketing).\n // - If multiple segments match (shared edges), prefer visually topmost (smallest `top` in CSS px).\n // If still tied, prefer larger `seriesIndex` for determinism.\n const barSeriesConfigs: ResolvedBarSeriesConfig[] = [];\n const barSeriesIndexByBar: number[] = [];\n for (let s = 0; s < series.length; s++) {\n const cfg = series[s];\n if (cfg?.type === 'bar' && cfg.visible !== false) {\n barSeriesConfigs.push(cfg);\n barSeriesIndexByBar.push(s);\n }\n }\n\n if (barSeriesConfigs.length > 0) {\n const layoutPx = computeBarLayoutPx(barSeriesConfigs, xScale);\n if (layoutPx.barWidthPx > 0 && layoutPx.clusterWidthPx >= 0) {\n const plotHeightPx = inferPlotHeightPxForBarHitTesting(barSeriesConfigs, yScale);\n const { baselineDomain, baselinePx } = computeBaselineDomainAndPx(barSeriesConfigs, yScale, plotHeightPx);\n\n const { clusterSlots, barWidthPx, gapPx, clusterWidthPx, categoryWidthPx, categoryStep } = layoutPx;\n const stackSumsByStackId = new Map<string, Map<number, { posSum: number; negSum: number }>>();\n\n let bestBarHit:\n | {\n readonly seriesIndex: number;\n readonly dataIndex: number;\n readonly top: number;\n }\n | null = null;\n\n for (let b = 0; b < barSeriesConfigs.length; b++) {\n const seriesCfg = barSeriesConfigs[b];\n const originalSeriesIndex = barSeriesIndexByBar[b] ?? -1;\n if (originalSeriesIndex < 0) continue;\n\n const data = seriesCfg.data as CartesianSeriesData;\n const n = getPointCount(data);\n const clusterIndex = clusterSlots.clusterIndexBySeries[b] ?? 0;\n const stackId = clusterSlots.stackIdBySeries[b] ?? '';\n\n for (let i = 0; i < n; i++) {\n const xDomain = getX(data, i);\n const yDomain = getY(data, i);\n if (!Number.isFinite(xDomain) || !Number.isFinite(yDomain)) continue;\n\n const xCenterPx = xScale.scale(xDomain);\n if (!Number.isFinite(xCenterPx)) continue;\n\n const left = xCenterPx - clusterWidthPx / 2 + clusterIndex * (barWidthPx + gapPx);\n const right = left + barWidthPx;\n\n let baseDomain = baselineDomain;\n let topDomain = yDomain;\n\n if (stackId !== '') {\n let sumsForX = stackSumsByStackId.get(stackId);\n if (!sumsForX) {\n sumsForX = new Map<number, { posSum: number; negSum: number }>();\n stackSumsByStackId.set(stackId, sumsForX);\n }\n\n const xKey = bucketStackedXKey(xCenterPx, categoryWidthPx, xDomain, categoryStep);\n let sums = sumsForX.get(xKey);\n if (!sums) {\n sums = { posSum: baselineDomain, negSum: baselineDomain };\n sumsForX.set(xKey, sums);\n }\n\n if (yDomain >= 0) {\n baseDomain = sums.posSum;\n topDomain = baseDomain + yDomain;\n sums.posSum = topDomain;\n } else {\n baseDomain = sums.negSum;\n topDomain = baseDomain + yDomain;\n sums.negSum = topDomain;\n }\n } else {\n baseDomain = baselineDomain;\n topDomain = yDomain;\n }\n\n const basePx = stackId !== '' ? yScale.scale(baseDomain) : baselinePx;\n const topPx = yScale.scale(topDomain);\n if (!Number.isFinite(basePx) || !Number.isFinite(topPx)) continue;\n\n const bounds: BarBounds = {\n left,\n right,\n top: Math.min(basePx, topPx),\n bottom: Math.max(basePx, topPx),\n };\n\n if (!isPointInBar(x, y, bounds)) continue;\n\n const isBetter =\n bestBarHit === null ||\n bounds.top < bestBarHit.top ||\n (bounds.top === bestBarHit.top && originalSeriesIndex > bestBarHit.seriesIndex);\n\n if (isBetter) {\n bestBarHit = { seriesIndex: originalSeriesIndex, dataIndex: i, top: bounds.top };\n }\n }\n }\n\n if (bestBarHit) {\n const seriesData = series[bestBarHit.seriesIndex]?.data as CartesianSeriesData | undefined;\n if (seriesData) {\n const x = getX(seriesData, bestBarHit.dataIndex);\n const y = getY(seriesData, bestBarHit.dataIndex);\n const size = getSize(seriesData, bestBarHit.dataIndex);\n const point: DataPoint = size !== undefined ? [x, y, size] : [x, y];\n return {\n seriesIndex: bestBarHit.seriesIndex,\n dataIndex: bestBarHit.dataIndex,\n point,\n distance: 0,\n };\n }\n }\n }\n }\n\n // Build index mapping for non-bar cartesian series (scatter, line, area) to preserve original series indices\n // after filtering for visibility, matching the pattern used for bar series above.\n const cartesianSeriesConfigs: ResolvedSeriesConfig[] = [];\n const cartesianSeriesIndexMap: number[] = [];\n for (let s = 0; s < series.length; s++) {\n const seriesCfg = series[s];\n // Pie and candlestick series are non-cartesian (or not yet implemented); they don't participate in x/y nearest-point hit-testing.\n if (seriesCfg.type === 'pie' || seriesCfg.type === 'candlestick') continue;\n\n // Skip invisible series (matches bar series visibility check above).\n if (seriesCfg.visible === false) continue;\n\n cartesianSeriesConfigs.push(seriesCfg);\n cartesianSeriesIndexMap.push(s);\n }\n\n for (let s = 0; s < cartesianSeriesConfigs.length; s++) {\n const seriesCfg = cartesianSeriesConfigs[s];\n const originalSeriesIndex = cartesianSeriesIndexMap[s] ?? -1;\n if (originalSeriesIndex < 0) continue;\n\n const data = seriesCfg.data as CartesianSeriesData;\n const n = getPointCount(data);\n if (n === 0) continue;\n\n const isScatter = seriesCfg.type === 'scatter';\n const scatterCfg = isScatter ? (seriesCfg as ResolvedScatterSeriesConfig) : null;\n\n // Check if data is monotonic for O(log n) fast path\n const canBinarySearch = isMonotonicNonDecreasingFiniteX(data);\n\n if (canBinarySearch) {\n // Fast path: binary search + expand outward\n // Find the index where data[i].x >= xTarget (lower bound)\n const startIdx = lowerBoundX(data, xTarget);\n\n // Expand outward from startIdx while points could still be closer\n // Check right side first (startIdx onwards)\n for (let i = startIdx; i < n; i++) {\n const px = getX(data, i);\n const py = getY(data, i);\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n\n const sx = xScale.scale(px);\n const sy = yScale.scale(py);\n if (!Number.isFinite(sx) || !Number.isFinite(sy)) continue;\n\n const dx = sx - x;\n const dy = sy - y;\n const distSq = dx * dx + dy * dy;\n\n // Early exit: if x-distance alone exceeds current best, no point can be closer (monotonic x)\n const dxSq = dx * dx;\n if (dxSq > bestDistSq) break;\n\n // Check scatter radius if applicable\n let allowedSq = maxDistSq;\n if (scatterCfg) {\n const size = getSize(data, i);\n const p: DataPoint = size !== undefined ? [px, py, size] : [px, py];\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n allowedSq = allowed * allowed;\n }\n\n if (distSq > allowedSq) continue;\n\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n originalSeriesIndex < bestSeriesIndex ||\n (originalSeriesIndex === bestSeriesIndex && i < bestDataIndex)));\n\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = originalSeriesIndex;\n bestDataIndex = i;\n const size = getSize(data, i);\n bestPoint = size !== undefined ? [px, py, size] : [px, py];\n }\n }\n\n // Check left side (before startIdx)\n for (let i = startIdx - 1; i >= 0; i--) {\n const px = getX(data, i);\n const py = getY(data, i);\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n\n const sx = xScale.scale(px);\n const sy = yScale.scale(py);\n if (!Number.isFinite(sx) || !Number.isFinite(sy)) continue;\n\n const dx = sx - x;\n const dy = sy - y;\n const distSq = dx * dx + dy * dy;\n\n // Early exit: if x-distance alone exceeds current best, no point can be closer\n const dxSq = dx * dx;\n if (dxSq > bestDistSq) break;\n\n // Check scatter radius if applicable\n let allowedSq = maxDistSq;\n if (scatterCfg) {\n const size = getSize(data, i);\n const p: DataPoint = size !== undefined ? [px, py, size] : [px, py];\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n allowedSq = allowed * allowed;\n }\n\n if (distSq > allowedSq) continue;\n\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n originalSeriesIndex < bestSeriesIndex ||\n (originalSeriesIndex === bestSeriesIndex && i < bestDataIndex)));\n\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = originalSeriesIndex;\n bestDataIndex = i;\n const size = getSize(data, i);\n bestPoint = size !== undefined ? [px, py, size] : [px, py];\n }\n }\n } else {\n // Fallback: linear scan for non-monotonic data\n for (let i = 0; i < n; i++) {\n const px = getX(data, i);\n const py = getY(data, i);\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n\n const sx = xScale.scale(px);\n const sy = yScale.scale(py);\n if (!Number.isFinite(sx) || !Number.isFinite(sy)) continue;\n\n const dx = sx - x;\n const dy = sy - y;\n const distSq = dx * dx + dy * dy;\n\n // Check scatter radius if applicable\n let allowedSq = maxDistSq;\n if (scatterCfg) {\n const size = getSize(data, i);\n const p: DataPoint = size !== undefined ? [px, py, size] : [px, py];\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n allowedSq = allowed * allowed;\n }\n\n if (distSq > allowedSq) continue;\n\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n originalSeriesIndex < bestSeriesIndex ||\n (originalSeriesIndex === bestSeriesIndex && i < bestDataIndex)));\n\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = originalSeriesIndex;\n bestDataIndex = i;\n const size = getSize(data, i);\n bestPoint = size !== undefined ? [px, py, size] : [px, py];\n }\n }\n }\n }\n\n if (bestPoint === null) return null;\n if (!Number.isFinite(bestDistSq)) return null;\n\n return {\n seriesIndex: bestSeriesIndex,\n dataIndex: bestDataIndex,\n point: bestPoint,\n distance: Math.sqrt(bestDistSq),\n };\n}\n\n","/**\n * Overlay Rendering Utilities\n *\n * Prepares and renders GPU-based chart overlays (grid, axes, crosshair, highlight).\n * These overlays are rendered on top of the main chart series.\n *\n * @module renderOverlays\n */\n\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { GridRenderer } from '../../../renderers/createGridRenderer';\nimport type { AxisRenderer } from '../../../renderers/createAxisRenderer';\nimport type { CrosshairRenderer, CrosshairRenderOptions } from '../../../renderers/createCrosshairRenderer';\nimport type { HighlightRenderer, HighlightPoint } from '../../../renderers/createHighlightRenderer';\nimport type { GridArea } from '../../../renderers/createGridRenderer';\nimport { findNearestPoint } from '../../../interaction/findNearestPoint';\nimport { getPointXY } from '../utils/dataPointUtils';\nimport { computePlotScissorDevicePx } from '../utils/axisUtils';\n\nconst DEFAULT_TICK_COUNT = 5;\nconst DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX = 1;\nconst DEFAULT_HIGHLIGHT_SIZE_CSS_PX = 4;\n\nexport interface OverlayRenderers {\n gridRenderer: GridRenderer;\n xAxisRenderer: AxisRenderer;\n yAxisRenderer: AxisRenderer;\n crosshairRenderer: CrosshairRenderer;\n highlightRenderer: HighlightRenderer;\n}\n\nexport interface OverlayPrepareContext {\n currentOptions: ResolvedChartGPUOptions;\n xScale: LinearScale;\n yScale: LinearScale;\n gridArea: GridArea;\n xTickCount: number;\n hasCartesianSeries: boolean;\n effectivePointer: {\n hasPointer: boolean;\n isInGrid: boolean;\n source: 'mouse' | 'sync';\n x: number;\n y: number;\n gridX: number;\n gridY: number;\n };\n interactionScales: {\n xScale: LinearScale;\n yScale: LinearScale;\n } | null;\n seriesForRender: ReadonlyArray<any>;\n withAlpha: (color: string, alpha: number) => string;\n}\n\nexport interface OverlayRenderContext {\n mainPass: GPURenderPassEncoder;\n topOverlayPass: GPURenderPassEncoder;\n hasCartesianSeries: boolean;\n}\n\n/**\n * Prepares all overlay renderers with current frame data.\n *\n * This includes grid lines, axes, crosshair, and point highlights.\n *\n * @param renderers - Overlay renderer instances\n * @param context - Rendering context with scales, options, and pointer state\n */\nexport function prepareOverlays(renderers: OverlayRenderers, context: OverlayPrepareContext): void {\n const {\n currentOptions,\n xScale,\n yScale,\n gridArea,\n xTickCount,\n hasCartesianSeries,\n effectivePointer,\n interactionScales,\n seriesForRender,\n withAlpha,\n } = context;\n\n // Grid preparation\n renderers.gridRenderer.prepare(gridArea, { color: currentOptions.theme.gridLineColor });\n\n // Axes preparation (cartesian only)\n if (hasCartesianSeries) {\n renderers.xAxisRenderer.prepare(\n currentOptions.xAxis,\n xScale,\n 'x',\n gridArea,\n currentOptions.theme.axisLineColor,\n currentOptions.theme.axisTickColor,\n xTickCount\n );\n renderers.yAxisRenderer.prepare(\n currentOptions.yAxis,\n yScale,\n 'y',\n gridArea,\n currentOptions.theme.axisLineColor,\n currentOptions.theme.axisTickColor,\n DEFAULT_TICK_COUNT\n );\n }\n\n // Crosshair preparation (when pointer is in grid)\n if (effectivePointer.hasPointer && effectivePointer.isInGrid) {\n const crosshairOptions: CrosshairRenderOptions = {\n showX: true,\n // Sync has no meaningful y, so avoid horizontal line.\n showY: effectivePointer.source !== 'sync',\n color: withAlpha(currentOptions.theme.axisLineColor, 0.6),\n lineWidth: DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX,\n };\n renderers.crosshairRenderer.prepare(effectivePointer.x, effectivePointer.y, gridArea, crosshairOptions);\n renderers.crosshairRenderer.setVisible(true);\n } else {\n renderers.crosshairRenderer.setVisible(false);\n }\n\n // Highlight preparation (on hover, find nearest point)\n if (effectivePointer.source === 'mouse' && effectivePointer.hasPointer && effectivePointer.isInGrid) {\n if (interactionScales) {\n // findNearestPoint handles visibility filtering internally\n const match = findNearestPoint(\n seriesForRender,\n effectivePointer.gridX,\n effectivePointer.gridY,\n interactionScales.xScale,\n interactionScales.yScale\n );\n\n if (match) {\n const { x, y } = getPointXY(match.point);\n const xGridCss = interactionScales.xScale.scale(x);\n const yGridCss = interactionScales.yScale.scale(y);\n\n if (Number.isFinite(xGridCss) && Number.isFinite(yGridCss)) {\n const centerCssX = gridArea.left + xGridCss;\n const centerCssY = gridArea.top + yGridCss;\n\n const plotScissor = computePlotScissorDevicePx(gridArea);\n const point: HighlightPoint = {\n centerDeviceX: centerCssX * gridArea.devicePixelRatio,\n centerDeviceY: centerCssY * gridArea.devicePixelRatio,\n devicePixelRatio: gridArea.devicePixelRatio,\n canvasWidth: gridArea.canvasWidth,\n canvasHeight: gridArea.canvasHeight,\n scissor: plotScissor,\n };\n\n const seriesColor = currentOptions.series[match.seriesIndex]?.color ?? '#888';\n renderers.highlightRenderer.prepare(point, seriesColor, DEFAULT_HIGHLIGHT_SIZE_CSS_PX);\n renderers.highlightRenderer.setVisible(true);\n } else {\n renderers.highlightRenderer.setVisible(false);\n }\n } else {\n renderers.highlightRenderer.setVisible(false);\n }\n } else {\n renderers.highlightRenderer.setVisible(false);\n }\n } else {\n renderers.highlightRenderer.setVisible(false);\n }\n}\n\n/**\n * Renders all overlay elements to the appropriate render passes.\n *\n * Grid is rendered in the main pass (background).\n * Highlight, axes, and crosshair are rendered in the top overlay pass (foreground).\n *\n * @param renderers - Overlay renderer instances\n * @param context - Render pass context\n */\nexport function renderOverlays(renderers: OverlayRenderers, context: OverlayRenderContext): void {\n const { mainPass, topOverlayPass, hasCartesianSeries } = context;\n\n // Grid renders in main pass (background)\n if (renderers.gridRenderer) {\n renderers.gridRenderer.render(mainPass);\n }\n\n // Highlight, axes, crosshair render in top overlay pass (foreground)\n renderers.highlightRenderer.render(topOverlayPass);\n if (hasCartesianSeries) {\n renderers.xAxisRenderer.render(topOverlayPass);\n renderers.yAxisRenderer.render(topOverlayPass);\n }\n renderers.crosshairRenderer.render(topOverlayPass);\n}\n","/**\n * Annotation processing for the RenderCoordinator.\n *\n * Processes annotation configurations into GPU-renderable instances (reference lines,\n * markers) and DOM label data. Supports layering (above/below series) and multiple\n * annotation types (lineX, lineY, point, text).\n *\n * @module processAnnotations\n */\n\nimport type { AnnotationConfig } from '../../../config/types';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { ThemeConfig } from '../../../themes/types';\nimport type { ReferenceLineInstance } from '../../../renderers/createReferenceLineRenderer';\nimport type { AnnotationMarkerInstance } from '../../../renderers/createAnnotationMarkerRenderer';\nimport type { TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport { parseCssColorToRgba01 } from '../../../utils/colors';\nimport { clipXToCanvasCssPx, clipYToCanvasCssPx, clamp01 } from '../utils/axisUtils';\nimport { assertUnreachable } from '../utils/dataPointUtils';\n\n/**\n * Internal type for annotation label data (DOM overlay).\n */\nexport interface AnnotationLabelData {\n readonly text: string;\n readonly x: number;\n readonly y: number;\n readonly anchor?: 'start' | 'middle' | 'end';\n readonly color?: string;\n readonly fontSize?: number;\n readonly background?: Readonly<{\n readonly backgroundColor: string;\n readonly padding?: readonly [number, number, number, number];\n readonly borderRadius?: number;\n }>;\n}\n\n/**\n * Plot bounds in CSS pixels.\n */\nexport interface PlotBounds {\n readonly leftCss: number;\n readonly rightCss: number;\n readonly topCss: number;\n readonly bottomCss: number;\n readonly widthCss: number;\n readonly heightCss: number;\n}\n\n/**\n * Context for annotation processing.\n */\nexport interface AnnotationContext {\n readonly annotations: ReadonlyArray<AnnotationConfig>;\n readonly xScale: LinearScale;\n readonly yScale: LinearScale;\n readonly plotBounds: PlotBounds;\n readonly canvasCssWidth: number;\n readonly canvasCssHeight: number;\n readonly theme: ThemeConfig;\n readonly offsetX?: number;\n readonly offsetY?: number;\n}\n\n/**\n * Result of annotation processing.\n */\nexport interface AnnotationResult {\n readonly linesBelow: ReferenceLineInstance[];\n readonly linesAbove: ReferenceLineInstance[];\n readonly markersBelow: AnnotationMarkerInstance[];\n readonly markersAbove: AnnotationMarkerInstance[];\n readonly labels: AnnotationLabelData[];\n}\n\n/**\n * Resolves annotation RGBA color with opacity.\n *\n * @param color - CSS color string or undefined\n * @param opacity - Opacity value [0, 1] or undefined\n * @param defaultColor - Default color (typically theme text color)\n * @returns RGBA tuple [r, g, b, a] in range [0, 1]\n */\nfunction resolveAnnotationRgba(\n color: string | undefined,\n opacity: number | undefined,\n defaultColor: string\n): readonly [number, number, number, number] {\n const base =\n parseCssColorToRgba01(color ?? defaultColor) ??\n parseCssColorToRgba01(defaultColor) ??\n ([1, 1, 1, 1] as const);\n const o = opacity == null ? 1 : clamp01(opacity);\n return [clamp01(base[0]), clamp01(base[1]), clamp01(base[2]), clamp01(base[3] * o)] as const;\n}\n\n/**\n * Converts color and opacity to CSS rgba() string.\n *\n * @param color - CSS color string\n * @param opacity01 - Opacity in range [0, 1]\n * @returns CSS rgba() string\n */\nfunction toCssRgba(color: string, opacity01: number): string {\n const base = parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n const a = clamp01(base[3] * clamp01(opacity01));\n const r = Math.round(clamp01(base[0]) * 255);\n const g = Math.round(clamp01(base[1]) * 255);\n const b = Math.round(clamp01(base[2]) * 255);\n return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\n/**\n * Formats number with optional decimal precision.\n *\n * @param n - Number to format\n * @param decimals - Number of decimal places (optional)\n * @returns Formatted string\n */\nfunction formatNumber(n: number, decimals?: number): string {\n if (!Number.isFinite(n)) return '';\n if (decimals == null) return String(n);\n const d = Math.min(20, Math.max(0, Math.floor(decimals)));\n return n.toFixed(d);\n}\n\n/**\n * Renders template string with value substitution.\n * Supports {x}, {y}, {value}, and {name} placeholders.\n *\n * @param template - Template string with placeholders\n * @param values - Values for substitution\n * @param decimals - Decimal precision for numbers\n * @returns Rendered string\n */\nfunction renderTemplate(\n template: string,\n values: Readonly<{ x?: number; y?: number; value?: number; name?: string }>,\n decimals?: number\n): string {\n // PERFORMANCE: Create regex per call (cached by engine in hot path)\n const templateRegex = /\\{(x|y|value|name)\\}/g;\n return template.replace(templateRegex, (_m, key) => {\n if (key === 'name') return values.name ?? '';\n const v = (values as any)[key] as number | undefined;\n return v == null ? '' : formatNumber(v, decimals);\n });\n}\n\n/**\n * Maps annotation anchor to text overlay anchor.\n *\n * @param anchor - Annotation anchor or undefined\n * @returns Text overlay anchor\n */\nfunction mapAnchor(anchor: 'start' | 'center' | 'end' | undefined): TextOverlayAnchor {\n switch (anchor) {\n case 'center':\n return 'middle';\n case 'end':\n return 'end';\n case 'start':\n default:\n return 'start';\n }\n}\n\n/**\n * Processes annotations into GPU-renderable instances and DOM labels.\n *\n * **Annotation Types:**\n * - `lineX`: Vertical reference line at x coordinate\n * - `lineY`: Horizontal reference line at y coordinate\n * - `point`: Marker at (x, y) coordinate\n * - `text`: Text annotation with flexible positioning\n *\n * **Layering:**\n * - `belowSeries`: Rendered before series (occluded by data)\n * - `aboveSeries`: Rendered after series (always visible, default)\n *\n * **Labels:**\n * - Optional text labels for all annotation types\n * - Template support with {x}, {y}, {value}, {name} placeholders\n * - Background styling with padding and border radius\n *\n * @param context - Annotation processing context\n * @returns Annotation result with lines, markers, and labels\n */\nexport function processAnnotations(context: AnnotationContext): AnnotationResult {\n const {\n annotations,\n xScale,\n yScale,\n plotBounds,\n canvasCssWidth,\n canvasCssHeight,\n theme,\n offsetX = 0,\n offsetY = 0,\n } = context;\n\n const { leftCss: plotLeftCss, topCss: plotTopCss, widthCss: plotWidthCss, heightCss: plotHeightCss } = plotBounds;\n\n // Output arrays (reused across calls for performance)\n const linesBelow: ReferenceLineInstance[] = [];\n const linesAbove: ReferenceLineInstance[] = [];\n const markersBelow: AnnotationMarkerInstance[] = [];\n const markersAbove: AnnotationMarkerInstance[] = [];\n const labels: AnnotationLabelData[] = [];\n\n // PERFORMANCE: Early exit if no annotations or invalid canvas dimensions\n if (annotations.length === 0 || canvasCssWidth <= 0 || canvasCssHeight <= 0 || plotWidthCss <= 0 || plotHeightCss <= 0) {\n return { linesBelow, linesAbove, markersBelow, markersAbove, labels };\n }\n\n // Process each annotation\n for (let i = 0; i < annotations.length; i++) {\n const a = annotations[i]!;\n const layer = a.layer ?? 'aboveSeries';\n const targetLines = layer === 'belowSeries' ? linesBelow : linesAbove;\n const targetMarkers = layer === 'belowSeries' ? markersBelow : markersAbove;\n\n // Resolve annotation styling\n const styleColor = a.style?.color;\n const styleOpacity = a.style?.opacity;\n const lineWidth = typeof a.style?.lineWidth === 'number' && Number.isFinite(a.style.lineWidth) ? Math.max(0, a.style.lineWidth) : 1;\n const lineDash = a.style?.lineDash;\n const rgba = resolveAnnotationRgba(styleColor, styleOpacity, theme.textColor);\n\n // Process annotation by type (GPU rendering)\n switch (a.type) {\n case 'lineX': {\n const xClip = xScale.scale(a.x);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n if (!Number.isFinite(xCss)) break;\n targetLines.push({\n axis: 'vertical',\n positionCssPx: xCss,\n lineWidth,\n lineDash,\n rgba,\n });\n break;\n }\n case 'lineY': {\n const yClip = yScale.scale(a.y);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n if (!Number.isFinite(yCss)) break;\n targetLines.push({\n axis: 'horizontal',\n positionCssPx: yCss,\n lineWidth,\n lineDash,\n rgba,\n });\n break;\n }\n case 'point': {\n const xClip = xScale.scale(a.x);\n const yClip = yScale.scale(a.y);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n if (!Number.isFinite(xCss) || !Number.isFinite(yCss)) break;\n\n const markerSize =\n typeof a.marker?.size === 'number' && Number.isFinite(a.marker.size) ? Math.max(1, a.marker.size) : 6;\n const markerColor = a.marker?.style?.color ?? a.style?.color;\n const markerOpacity = a.marker?.style?.opacity ?? a.style?.opacity;\n const fillRgba = resolveAnnotationRgba(markerColor, markerOpacity, theme.textColor);\n\n targetMarkers.push({\n xCssPx: xCss,\n yCssPx: yCss,\n sizeCssPx: markerSize,\n fillRgba,\n });\n break;\n }\n case 'text': {\n // Text annotations are handled via DOM overlays (labels), not GPU\n break;\n }\n default:\n assertUnreachable(a);\n }\n\n // Process annotation label (DOM overlay)\n const labelCfg = a.label;\n const wantsLabel = labelCfg != null || a.type === 'text';\n if (!wantsLabel) continue;\n\n // Compute anchor point (canvas-local CSS px)\n let anchorXCss: number | null = null;\n let anchorYCss: number | null = null;\n let values: { x?: number; y?: number; value?: number; name?: string } = { name: a.id ?? '' };\n\n switch (a.type) {\n case 'lineX': {\n const xClip = xScale.scale(a.x);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n anchorXCss = xCss;\n anchorYCss = plotTopCss;\n values = { ...values, x: a.x, value: a.x };\n break;\n }\n case 'lineY': {\n const yClip = yScale.scale(a.y);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n anchorXCss = plotLeftCss;\n // Offset label 8px above the horizontal line (negative Y = upward)\n anchorYCss = yCss - 8;\n values = { ...values, y: a.y, value: a.y };\n break;\n }\n case 'point': {\n const xClip = xScale.scale(a.x);\n const yClip = yScale.scale(a.y);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n anchorXCss = xCss;\n anchorYCss = yCss;\n values = { ...values, x: a.x, y: a.y, value: a.y };\n break;\n }\n case 'text': {\n if (a.position.space === 'data') {\n const xClip = xScale.scale(a.position.x);\n const yClip = yScale.scale(a.position.y);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n anchorXCss = xCss;\n anchorYCss = yCss;\n values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n } else {\n const xCss = plotLeftCss + a.position.x * plotWidthCss;\n const yCss = plotTopCss + a.position.y * plotHeightCss;\n anchorXCss = xCss;\n anchorYCss = yCss;\n values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n }\n break;\n }\n default:\n assertUnreachable(a);\n }\n\n if (anchorXCss == null || anchorYCss == null || !Number.isFinite(anchorXCss) || !Number.isFinite(anchorYCss)) {\n continue;\n }\n\n // Apply label offset\n const dx = labelCfg?.offset?.[0] ?? 0;\n const dy = labelCfg?.offset?.[1] ?? 0;\n const x = anchorXCss + dx;\n const y = anchorYCss + dy;\n\n // Label text selection (explicit > template > defaults)\n const text =\n labelCfg?.text ??\n (labelCfg?.template\n ? renderTemplate(labelCfg.template, values, labelCfg.decimals)\n : labelCfg\n ? (() => {\n const defaultTemplate =\n a.type === 'lineX'\n ? 'x={x}'\n : a.type === 'lineY'\n ? 'y={y}'\n : a.type === 'point'\n ? '({x}, {y})'\n : a.type === 'text'\n ? a.text\n : '';\n return defaultTemplate.includes('{')\n ? renderTemplate(defaultTemplate, values, labelCfg.decimals)\n : defaultTemplate;\n })()\n : a.type === 'text'\n ? a.text\n : '');\n\n const trimmed = typeof text === 'string' ? text.trim() : '';\n if (trimmed.length === 0) continue;\n\n // Label styling\n const anchor = mapAnchor(labelCfg?.anchor);\n const color = a.style?.color ?? theme.textColor;\n const fontSize = theme.fontSize;\n\n // Background styling\n const bg = labelCfg?.background;\n const bgColor = bg?.color != null ? toCssRgba(bg.color, bg.opacity ?? 1) : undefined;\n const padding = (() => {\n const p = bg?.padding;\n if (typeof p === 'number' && Number.isFinite(p)) return [p, p, p, p] as const;\n if (Array.isArray(p) && p.length === 4 && p.every((n) => typeof n === 'number' && Number.isFinite(n))) {\n return [p[0], p[1], p[2], p[3]] as const;\n }\n return bg ? ([2, 4, 2, 4] as const) : undefined;\n })();\n const borderRadius =\n typeof bg?.borderRadius === 'number' && Number.isFinite(bg.borderRadius) ? bg.borderRadius : undefined;\n\n // Create label data\n const labelData: AnnotationLabelData = {\n text: trimmed,\n x: offsetX + x,\n y: offsetY + y,\n anchor,\n color,\n fontSize,\n ...(bgColor\n ? {\n background: {\n backgroundColor: bgColor,\n ...(padding ? { padding } : {}),\n ...(borderRadius != null ? { borderRadius } : {}),\n },\n }\n : {}),\n };\n\n labels.push(labelData);\n }\n\n return {\n linesBelow,\n linesAbove,\n markersBelow,\n markersAbove,\n labels,\n };\n}\n","/**\n * Animation helper utilities for intro and update animations.\n *\n * Provides pure functions for animation config resolution, easing transformations,\n * series interpolation, and animation state management. These utilities support\n * both intro animations (initial reveal) and update animations (smooth transitions).\n *\n * @module animationHelpers\n */\n\nimport type { AnimationConfig, DataPoint } from '../../../config/types';\nimport type { ResolvedPieSeriesConfig } from '../../../config/OptionResolver';\nimport type { EasingFunction } from '../../../utils/easing';\nimport { getPointXY, isTupleDataPoint } from '../utils/dataPointUtils';\n\n/**\n * Intro animation phase state machine.\n */\nexport type IntroPhase = 'pending' | 'running' | 'done';\n\n/**\n * Domain boundaries with min and max values.\n */\nexport interface DomainBounds {\n readonly min: number;\n readonly max: number;\n}\n\n/**\n * Resolved animation configuration with timing and easing.\n */\nexport interface ResolvedAnimationConfig {\n readonly delayMs: number;\n readonly durationMs: number;\n readonly easing: EasingFunction;\n}\n\n/**\n * Series configuration type that supports all series types.\n */\nexport type AnySeriesConfig =\n | { readonly type: 'line'; readonly data: ReadonlyArray<DataPoint> }\n | { readonly type: 'area'; readonly data: ReadonlyArray<DataPoint> }\n | { readonly type: 'bar'; readonly data: ReadonlyArray<DataPoint> }\n | { readonly type: 'scatter'; readonly data: ReadonlyArray<DataPoint> }\n | { readonly type: 'candlestick'; readonly data: ReadonlyArray<any> }\n | ResolvedPieSeriesConfig;\n\n/**\n * Clamps a value between 0 and 1.\n *\n * @param value - Value to clamp\n * @returns Clamped value in [0, 1]\n */\nexport function clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\n/**\n * Resolves animation configuration from options.\n *\n * Returns null if animation is disabled (false or null).\n * Returns default config if animation is true or an empty object.\n * Converts duration/delay from user config to milliseconds.\n *\n * @param animation - Animation options from chart config\n * @param getEasingFn - Function to resolve easing by name (to avoid circular deps)\n * @returns Resolved animation config or null if disabled\n */\nexport function resolveAnimationConfig(\n animation: boolean | AnimationConfig | null | undefined,\n getEasingFn: (name: string) => EasingFunction\n): ResolvedAnimationConfig | null {\n if (animation === false || animation == null) return null;\n\n const cfg: AnimationConfig | null = animation === true ? {} : animation;\n if (!cfg) return null;\n\n // Extract duration and delay with defaults\n const durationMsRaw = cfg.duration ?? 300;\n const delayMsRaw = cfg.delay ?? 0;\n\n const durationMs = Number.isFinite(durationMsRaw) ? Math.max(0, durationMsRaw) : 300;\n const delayMs = Number.isFinite(delayMsRaw) ? Math.max(0, delayMsRaw) : 0;\n\n // Resolve easing (string name or function)\n const easingConfig = cfg.easing ?? 'cubicOut';\n const easing =\n typeof easingConfig === 'string' ? getEasingFn(easingConfig) : easingConfig;\n\n return {\n durationMs,\n delayMs,\n easing,\n };\n}\n\n/**\n * Creates an easing function that incorporates delay.\n *\n * The returned function maps t ∈ [0, 1] to an output considering both delay\n * and duration:\n * - t in [0, delay]: output = 0 (delay phase)\n * - t in [delay, delay+duration]: output = easing((t-delay)/duration)\n * - t > delay+duration: output = 1 (complete)\n *\n * @param delayMs - Delay before animation starts (milliseconds)\n * @param durationMs - Animation duration after delay (milliseconds)\n * @param easing - Base easing function to apply after delay\n * @returns Easing function with delay incorporated\n */\nexport function createEasingWithDelay(\n delayMs: number,\n durationMs: number,\n easing: EasingFunction\n): EasingFunction {\n return (t01: number): number => {\n const t = clamp01(t01);\n const totalMs = delayMs + durationMs;\n\n if (!(totalMs > 0)) return 1;\n\n const elapsedMs = t * totalMs;\n if (elapsedMs < delayMs) return 0;\n\n if (!(durationMs > 0)) return 1;\n const innerT = (elapsedMs - delayMs) / durationMs;\n return easing(innerT);\n };\n}\n\n/**\n * Checks if a series configuration has drawable marks.\n *\n * Returns true if the series has data that will produce visible marks:\n * - Pie: at least one slice with value > 0\n * - Cartesian (line/area/bar/scatter/candlestick): at least one data point\n *\n * @param series - Series configuration to check\n * @returns True if series has drawable content\n */\nexport function hasDrawableMarks(series: AnySeriesConfig): boolean {\n switch (series.type) {\n case 'pie': {\n return series.data.some(\n (it: any) => typeof it?.value === 'number' && Number.isFinite(it.value) && it.value > 0\n );\n }\n case 'line':\n case 'area':\n case 'bar':\n case 'scatter':\n case 'candlestick': {\n return series.data.length > 0;\n }\n default: {\n return false;\n }\n }\n}\n\n/**\n * Checks if any series in the list has drawable marks.\n *\n * @param seriesList - Array of series configurations\n * @returns True if at least one series has drawable marks\n */\nexport function hasAnyDrawableMarks(seriesList: ReadonlyArray<AnySeriesConfig>): boolean {\n for (let i = 0; i < seriesList.length; i++) {\n if (hasDrawableMarks(seriesList[i]!)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Linearly interpolates between two domain bounds.\n *\n * @param from - Starting domain\n * @param to - Ending domain\n * @param t - Interpolation progress [0, 1]\n * @returns Interpolated domain\n */\nexport function lerpDomain(from: DomainBounds, to: DomainBounds, t: number): DomainBounds {\n const t01 = clamp01(t);\n return {\n min: from.min + (to.min - from.min) * t01,\n max: from.max + (to.max - from.max) * t01,\n };\n}\n\n/**\n * Linearly interpolates between two numbers.\n *\n * @param from - Starting value\n * @param to - Ending value\n * @param t - Interpolation progress [0, 1]\n * @returns Interpolated value\n */\nexport function lerp(from: number, to: number, t: number): number {\n return from + (to - from) * clamp01(t);\n}\n\n/**\n * Interpolates cartesian series data between from and to states.\n *\n * Returns null if array lengths don't match (can't interpolate mismatched arrays).\n * Reuses cache array if provided and same length.\n *\n * @param fromData - Starting data points\n * @param toData - Ending data points\n * @param t - Interpolation progress [0, 1]\n * @param cache - Optional cache array to reuse\n * @returns Interpolated data points or null if lengths mismatch\n */\nexport function interpolateCartesianData(\n fromData: ReadonlyArray<DataPoint>,\n toData: ReadonlyArray<DataPoint>,\n t: number,\n cache: DataPoint[] | null\n): DataPoint[] | null {\n if (fromData.length !== toData.length) return null;\n\n const n = toData.length;\n if (n === 0) return cache ?? [];\n\n const out = cache && cache.length === n ? cache : new Array<DataPoint>(n);\n const t01 = clamp01(t);\n\n // Determine format from first element\n const isTuple = isTupleDataPoint(toData[0]!);\n\n for (let i = 0; i < n; i++) {\n const fromPt = fromData[i]!;\n const toPt = toData[i]!;\n\n const fromXY = getPointXY(fromPt);\n const toXY = getPointXY(toPt);\n\n const x = lerp(fromXY.x, toXY.x, t01);\n const y = lerp(fromXY.y, toXY.y, t01);\n\n if (isTuple) {\n out[i] = [x, y] as DataPoint;\n } else {\n out[i] = { x, y } as DataPoint;\n }\n }\n\n return out;\n}\n\n/**\n * Interpolates pie series data between from and to states.\n *\n * Returns the toSeries unchanged if data array lengths don't match.\n * Only interpolates the value property; angles are recomputed by the renderer.\n *\n * @param fromSeries - Starting pie series\n * @param toSeries - Ending pie series\n * @param t - Interpolation progress [0, 1]\n * @param cache - Optional cache array to reuse\n * @returns Interpolated pie series\n */\nexport function interpolatePieData(\n fromSeries: ResolvedPieSeriesConfig,\n toSeries: ResolvedPieSeriesConfig,\n t: number,\n cache: ResolvedPieSeriesConfig['data'] | null\n): ResolvedPieSeriesConfig {\n const fromData = fromSeries.data;\n const toData = toSeries.data;\n\n if (fromData.length !== toData.length) return toSeries;\n\n const n = toData.length;\n if (n === 0) return toSeries;\n\n // Create or reuse cache array\n const out =\n cache && cache.length === n\n ? cache\n : (() => {\n const created: any[] = new Array(n);\n for (let i = 0; i < n; i++) {\n // Preserve name/color from \"to\"; patch value per frame\n created[i] = { ...toData[i]!, value: 0 };\n }\n return created as ResolvedPieSeriesConfig['data'];\n })();\n\n const t01 = clamp01(t);\n\n for (let i = 0; i < n; i++) {\n const vFrom = (fromData[i] as any)?.value;\n const vTo = (toData[i] as any)?.value;\n\n // Interpolate value if both are valid numbers\n const nextValue =\n typeof vFrom === 'number' && typeof vTo === 'number' && Number.isFinite(vFrom) && Number.isFinite(vTo)\n ? Math.max(0, lerp(vFrom, vTo, t01))\n : typeof vTo === 'number' && Number.isFinite(vTo)\n ? vTo\n : 0;\n\n (out[i] as any).value = nextValue;\n }\n\n return { ...toSeries, data: out };\n}\n\n/**\n * Checks if two domain bounds are equal.\n *\n * @param a - First domain\n * @param b - Second domain\n * @returns True if domains have identical min and max\n */\nexport function isDomainEqual(a: DomainBounds, b: DomainBounds): boolean {\n return a.min === b.min && a.max === b.max;\n}\n\n/**\n * Determines the next intro phase based on current state and conditions.\n *\n * State machine transitions:\n * - pending → running: when has drawable marks and animation enabled\n * - running → done: when animation completes\n * - done → pending: when retriggering (e.g., visibility change)\n *\n * @param currentPhase - Current intro phase\n * @param hasDrawable - Whether series have drawable marks\n * @param animationEnabled - Whether animation is enabled\n * @param retrigger - Whether to retrigger from done state\n * @returns Next intro phase\n */\nexport function computeNextIntroPhase(\n currentPhase: IntroPhase,\n hasDrawable: boolean,\n animationEnabled: boolean,\n retrigger: boolean = false\n): IntroPhase {\n if (retrigger && currentPhase === 'done') {\n return 'pending';\n }\n\n if (currentPhase === 'pending' && hasDrawable && animationEnabled) {\n return 'running';\n }\n\n return currentPhase;\n}\n\n/**\n * Applies intro animation progress to create an animated bar Y scale.\n *\n * During intro, bars grow from the zero line (or domain min if no zero).\n * This creates a scale that compresses bars based on progress.\n *\n * @param baseYScale - Original Y scale\n * @param yMin - Domain minimum\n * @param yMax - Domain maximum\n * @param progress - Animation progress [0, 1]\n * @returns Y coordinate adjusted for intro animation\n */\nexport function applyBarIntroProgress(\n baseY: number,\n yMin: number,\n yMax: number,\n progress: number\n): number {\n const p = clamp01(progress);\n\n // Find zero line or use domain min as anchor\n const zeroLine = yMin <= 0 && yMax >= 0 ? 0 : yMin;\n\n // Interpolate from zero line to actual value\n return lerp(zeroLine, baseY, p);\n}\n","/**\n * Series Rendering Utilities\n *\n * Prepares and renders all chart series types (area, line, bar, scatter, candlestick, pie).\n * Handles intro animations, GPU buffer management, and multi-pass rendering with proper layering.\n *\n * @module renderSeries\n */\n\nimport type { ResolvedChartGPUOptions, ResolvedSeriesConfig, ResolvedBarSeriesConfig, ResolvedAreaSeriesConfig, ResolvedPieSeriesConfig } from '../../../config/OptionResolver';\nimport type { DataPoint } from '../../../config/types';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { GridArea } from '../../../renderers/createGridRenderer';\nimport type { LineRenderer } from '../../../renderers/createLineRenderer';\nimport type { AreaRenderer } from '../../../renderers/createAreaRenderer';\nimport type { BarRenderer } from '../../../renderers/createBarRenderer';\nimport type { ScatterRenderer } from '../../../renderers/createScatterRenderer';\nimport type { ScatterDensityRenderer } from '../../../renderers/createScatterDensityRenderer';\nimport type { PieRenderer } from '../../../renderers/createPieRenderer';\nimport type { CandlestickRenderer } from '../../../renderers/createCandlestickRenderer';\nimport type { ReferenceLineRenderer } from '../../../renderers/createReferenceLineRenderer';\nimport type { AnnotationMarkerRenderer } from '../../../renderers/createAnnotationMarkerRenderer';\nimport type { DataStore } from '../../../data/createDataStore';\nimport { isTupleDataPoint } from '../utils/dataPointUtils';\nimport { clampInt } from '../utils/canvasUtils';\nimport { clamp01 } from '../animation/animationHelpers';\nimport { findVisibleRangeIndicesByX } from '../data/computeVisibleSlice';\nimport { resolvePieRadiiCss } from '../utils/timeAxisUtils';\n\nexport interface SeriesRenderers {\n lineRenderers: LineRenderer[];\n areaRenderers: AreaRenderer[];\n barRenderer: BarRenderer;\n scatterRenderers: ScatterRenderer[];\n scatterDensityRenderers: ScatterDensityRenderer[];\n pieRenderers: PieRenderer[];\n candlestickRenderers: CandlestickRenderer[];\n}\n\nexport interface AnnotationRenderers {\n referenceLineRenderer: ReferenceLineRenderer;\n referenceLineRendererMsaa: ReferenceLineRenderer;\n annotationMarkerRenderer: AnnotationMarkerRenderer;\n annotationMarkerRendererMsaa: AnnotationMarkerRenderer;\n}\n\nexport interface SeriesPrepareContext {\n currentOptions: ResolvedChartGPUOptions;\n seriesForRender: ReadonlyArray<ResolvedSeriesConfig>;\n xScale: LinearScale;\n yScale: LinearScale;\n gridArea: GridArea;\n dataStore: DataStore;\n appendedGpuThisFrame: Set<number>;\n gpuSeriesKindByIndex: Array<'fullRawLine' | 'other' | 'unknown'>;\n zoomState: { getRange(): { start: number; end: number } | null } | null;\n visibleXDomain: { min: number; max: number };\n introPhase: 'pending' | 'running' | 'done';\n introProgress01: number;\n withAlpha: (color: string, alpha: number) => string;\n maxRadiusCss: number;\n}\n\nexport interface SeriesRenderContext {\n hasCartesianSeries: boolean;\n gridArea: GridArea;\n mainPass: GPURenderPassEncoder;\n plotScissor: { x: number; y: number; w: number; h: number };\n introPhase: 'pending' | 'running' | 'done';\n introProgress01: number;\n referenceLineBelowCount: number;\n markerBelowCount: number;\n}\n\nexport interface AboveSeriesAnnotationContext {\n hasCartesianSeries: boolean;\n gridArea: GridArea;\n overlayPass: GPURenderPassEncoder;\n plotScissor: { x: number; y: number; w: number; h: number };\n referenceLineBelowCount: number;\n referenceLineAboveCount: number;\n markerBelowCount: number;\n markerAboveCount: number;\n}\n\nexport interface SeriesPreparationResult {\n visibleSeriesForRender: ReadonlyArray<{ series: ResolvedSeriesConfig; originalIndex: number }>;\n barSeriesConfigs: ResolvedBarSeriesConfig[];\n visibleBarSeriesConfigs: ResolvedBarSeriesConfig[];\n}\n\n/**\n * Helper: determines if an area should be rendered for a series.\n * Line series with areaStyle should render as area.\n */\nfunction shouldRenderArea(series: ResolvedSeriesConfig): boolean {\n return series.type === 'area' || (series.type === 'line' && !!series.areaStyle);\n}\n\n/**\n * Prepares all series renderers with current frame data.\n *\n * This loop prepares ALL series (including hidden) to maintain correct renderer indices.\n * Visibility filtering happens after preparation for rendering.\n *\n * @param renderers - Series renderer instances\n * @param context - Preparation context with scales, options, and state\n * @returns Preparation result with visibility-filtered series arrays\n */\nexport function prepareSeries(\n renderers: SeriesRenderers,\n context: SeriesPrepareContext\n): SeriesPreparationResult {\n const {\n currentOptions,\n seriesForRender,\n xScale,\n yScale,\n gridArea,\n dataStore,\n appendedGpuThisFrame,\n gpuSeriesKindByIndex,\n zoomState,\n visibleXDomain,\n introPhase,\n introProgress01,\n withAlpha,\n maxRadiusCss,\n } = context;\n\n const defaultBaseline = currentOptions.yAxis.min ?? (currentOptions.yAxis.min ?? 0);\n const barSeriesConfigs: ResolvedBarSeriesConfig[] = [];\n\n const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n\n // Preparation loop: prepare ALL series (including hidden) to maintain correct indices\n for (let i = 0; i < seriesForRender.length; i++) {\n const s = seriesForRender[i];\n switch (s.type) {\n case 'area': {\n const baseline = s.baseline ?? defaultBaseline;\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n renderers.areaRenderers[i].prepare(s, s.data as ReadonlyArray<DataPoint>, xScale, yScale, baseline);\n break;\n }\n case 'line': {\n // Always prepare the line stroke.\n // If we already appended into the DataStore this frame (fast-path), avoid a full re-upload.\n // For time axes (epoch-ms), subtract an x-origin before packing to Float32 to avoid precision loss\n // (Float32 ulp at ~1e12 is ~2e5), which can manifest as stroke shimmer during zoom.\n const xOffset = (() => {\n if (currentOptions.xAxis.type !== 'time') return 0;\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const d = s.data as ReadonlyArray<DataPoint>;\n for (let k = 0; k < d.length; k++) {\n const p = d[k]!\n const x = isTupleDataPoint(p) ? p[0] : p.x;\n if (Number.isFinite(x)) return x;\n }\n return 0;\n })();\n if (!appendedGpuThisFrame.has(i)) {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n dataStore.setSeries(i, s.data as ReadonlyArray<DataPoint>, { xOffset });\n }\n const buffer = dataStore.getSeriesBuffer(i);\n renderers.lineRenderers[i].prepare(s, buffer, xScale, yScale, xOffset);\n\n // Track the GPU buffer kind for future append fast-path decisions.\n const zoomRange = zoomState?.getRange() ?? null;\n const isFullSpanZoom =\n zoomRange == null ||\n (Number.isFinite(zoomRange.start) &&\n Number.isFinite(zoomRange.end) &&\n zoomRange.start <= 0 &&\n zoomRange.end >= 100);\n if (isFullSpanZoom && s.sampling === 'none') {\n gpuSeriesKindByIndex[i] = 'fullRawLine';\n } else {\n gpuSeriesKindByIndex[i] = 'other';\n }\n\n // If `areaStyle` is provided on a line series, render a fill behind it.\n if (s.areaStyle) {\n const areaLike: ResolvedAreaSeriesConfig = {\n type: 'area',\n name: s.name,\n rawData: s.data,\n data: s.data,\n color: s.areaStyle.color,\n areaStyle: s.areaStyle,\n sampling: s.sampling,\n samplingThreshold: s.samplingThreshold,\n };\n\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n renderers.areaRenderers[i].prepare(areaLike, areaLike.data as ReadonlyArray<DataPoint>, xScale, yScale, defaultBaseline);\n }\n\n break;\n }\n case 'bar': {\n barSeriesConfigs.push(s);\n break;\n }\n case 'scatter': {\n // Scatter renderer sets/resets its own scissor. Animate intro via alpha fade.\n if (s.mode === 'density') {\n // Density mode bins raw (unsampled) data for correctness, but limits compute to the visible\n // range when x is monotonic.\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const rawData = (s.rawData ?? s.data) as ReadonlyArray<DataPoint>;\n const visible = findVisibleRangeIndicesByX(rawData, visibleXDomain.min, visibleXDomain.max);\n\n // Upload full raw data for compute. DataStore hashing makes this a cheap no-op when unchanged.\n if (!appendedGpuThisFrame.has(i)) {\n dataStore.setSeries(i, rawData);\n }\n const buffer = dataStore.getSeriesBuffer(i);\n const pointCount = dataStore.getSeriesPointCount(i);\n\n renderers.scatterDensityRenderers[i].prepare(\n s,\n buffer,\n pointCount,\n visible.start,\n visible.end,\n xScale,\n yScale,\n gridArea,\n s.rawBounds\n );\n // Density mode keeps its own compute path; treat as non-fast-path for append heuristics.\n gpuSeriesKindByIndex[i] = 'other';\n } else {\n const animated = introP < 1 ? ({ ...s, color: withAlpha(s.color, introP) } as const) : s;\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n renderers.scatterRenderers[i].prepare(animated, s.data as ReadonlyArray<DataPoint>, xScale, yScale, gridArea);\n }\n break;\n }\n case 'pie': {\n // Pie renderer sets/resets its own scissor. Animate intro via radius scale (CSS px).\n if (introP < 1 && maxRadiusCss > 0) {\n const radiiCss = resolvePieRadiiCss(s.radius, maxRadiusCss);\n const inner = Math.max(0, radiiCss.inner) * introP;\n const outer = Math.max(inner, radiiCss.outer) * introP;\n const animated: ResolvedPieSeriesConfig = { ...s, radius: [inner, outer] as const };\n renderers.pieRenderers[i].prepare(animated, gridArea);\n break;\n }\n renderers.pieRenderers[i].prepare(s, gridArea);\n break;\n }\n case 'candlestick': {\n // Candlestick renderer handles clipping internally, no intro animation for now.\n renderers.candlestickRenderers[i].prepare(s, s.data, xScale, yScale, gridArea, currentOptions.theme.backgroundColor);\n break;\n }\n default: {\n // Exhaustive check for unhandled series types\n const _exhaustive: never = s;\n throw new Error(`Unhandled series type: ${(_exhaustive as any).type}`);\n }\n }\n }\n\n // Filter series by visibility for rendering (after preparation)\n const visibleSeriesForRender = seriesForRender\n .map((s, i) => ({ series: s, originalIndex: i }))\n .filter(({ series }) => series.visible !== false);\n\n // Bars are collected but prepared separately by coordinator (needs yScaleForBars which depends on visibleBarSeriesConfigs)\n const visibleBarSeriesConfigs = barSeriesConfigs.filter(s => s.visible !== false);\n\n return {\n visibleSeriesForRender,\n barSeriesConfigs,\n visibleBarSeriesConfigs,\n };\n}\n\n/**\n * Encodes scatter density compute passes before rendering.\n *\n * Must be called before beginRenderPass() for the main pass.\n *\n * @param renderers - Series renderer instances\n * @param seriesForRender - All series configurations\n * @param encoder - Command encoder for compute passes\n */\nexport function encodeScatterDensityCompute(\n renderers: SeriesRenderers,\n seriesForRender: ReadonlyArray<ResolvedSeriesConfig>,\n encoder: GPUCommandEncoder\n): void {\n for (let i = 0; i < seriesForRender.length; i++) {\n const s = seriesForRender[i];\n if (s.visible !== false && s.type === 'scatter' && s.mode === 'density') {\n renderers.scatterDensityRenderers[i].encodeCompute(encoder);\n }\n }\n}\n\n/**\n * Renders all series to the main render pass with proper layering.\n *\n * Render order (from back to front):\n * 1. Pies (non-cartesian, behind cartesian series)\n * 2. Annotations below series (reference lines, markers)\n * 3. Area fills\n * 4. Bars\n * 5. Candlesticks\n * 6. Scatter points\n * 7. Line strokes\n *\n * @param renderers - Series renderer instances\n * @param annotationRenderers - Annotation renderer instances\n * @param context - Render pass context with pass encoders and state\n */\nexport function renderSeries(\n renderers: SeriesRenderers,\n annotationRenderers: AnnotationRenderers,\n context: SeriesRenderContext,\n prepResult: SeriesPreparationResult\n): void {\n const {\n hasCartesianSeries,\n gridArea,\n mainPass,\n plotScissor,\n introPhase,\n introProgress01,\n referenceLineBelowCount,\n markerBelowCount,\n } = context;\n\n const { visibleSeriesForRender } = prepResult;\n const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n\n // Render pies first (non-cartesian, visible behind cartesian series)\n for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n const { series, originalIndex } = visibleSeriesForRender[idx];\n if (series.type === 'pie') {\n renderers.pieRenderers[originalIndex].render(mainPass);\n }\n }\n\n // Annotations (below series): clipped to plot scissor.\n if (hasCartesianSeries && plotScissor.w > 0 && plotScissor.h > 0) {\n const hasBelow = referenceLineBelowCount > 0 || markerBelowCount > 0;\n if (hasBelow) {\n mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n if (referenceLineBelowCount > 0) {\n annotationRenderers.referenceLineRenderer.render(mainPass, 0, referenceLineBelowCount);\n }\n if (markerBelowCount > 0) {\n annotationRenderers.annotationMarkerRenderer.render(mainPass, 0, markerBelowCount);\n }\n mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n }\n\n // Render area fills\n for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n const { series, originalIndex } = visibleSeriesForRender[idx];\n if (shouldRenderArea(series)) {\n // Line/area intro reveal: left-to-right plot scissor.\n if (introP < 1) {\n const w = clampInt(Math.floor(plotScissor.w * introP), 0, plotScissor.w);\n if (w > 0 && plotScissor.h > 0) {\n mainPass.setScissorRect(plotScissor.x, plotScissor.y, w, plotScissor.h);\n renderers.areaRenderers[originalIndex].render(mainPass);\n mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n } else {\n mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n renderers.areaRenderers[originalIndex].render(mainPass);\n mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n }\n }\n\n // Clip bars to the plot grid (mirrors area/line scissor usage).\n if (plotScissor.w > 0 && plotScissor.h > 0) {\n mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n renderers.barRenderer.render(mainPass);\n mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n\n // Render candlesticks\n for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n const { series, originalIndex } = visibleSeriesForRender[idx];\n if (series.type === 'candlestick') {\n renderers.candlestickRenderers[originalIndex].render(mainPass);\n }\n }\n\n // Render scatter points\n for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n const { series, originalIndex } = visibleSeriesForRender[idx];\n if (series.type !== 'scatter') continue;\n if (series.mode === 'density') {\n renderers.scatterDensityRenderers[originalIndex].render(mainPass);\n } else {\n renderers.scatterRenderers[originalIndex].render(mainPass);\n }\n }\n\n // Render line strokes\n for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n const { series, originalIndex } = visibleSeriesForRender[idx];\n if (series.type === 'line') {\n // Line intro reveal: left-to-right plot scissor.\n if (introP < 1) {\n const w = clampInt(Math.floor(plotScissor.w * introP), 0, plotScissor.w);\n if (w > 0 && plotScissor.h > 0) {\n mainPass.setScissorRect(plotScissor.x, plotScissor.y, w, plotScissor.h);\n renderers.lineRenderers[originalIndex].render(mainPass);\n mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n } else {\n mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n renderers.lineRenderers[originalIndex].render(mainPass);\n mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n }\n }\n}\n\n/**\n * Renders above-series annotations to the MSAA overlay pass.\n *\n * Must be called during the MSAA overlay pass (after blit).\n *\n * @param annotationRenderers - Annotation renderer instances\n * @param context - Render pass context with overlay pass and state\n */\nexport function renderAboveSeriesAnnotations(\n annotationRenderers: AnnotationRenderers,\n context: AboveSeriesAnnotationContext\n): void {\n const {\n hasCartesianSeries,\n gridArea,\n overlayPass,\n plotScissor,\n referenceLineBelowCount,\n referenceLineAboveCount,\n markerBelowCount,\n markerAboveCount,\n } = context;\n\n // Annotations (above series): reference lines then markers, clipped to plot scissor.\n if (hasCartesianSeries && plotScissor.w > 0 && plotScissor.h > 0) {\n const hasAbove = referenceLineAboveCount > 0 || markerAboveCount > 0;\n if (hasAbove) {\n const firstLine = referenceLineBelowCount;\n const firstMarker = markerBelowCount;\n overlayPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n if (referenceLineAboveCount > 0) {\n annotationRenderers.referenceLineRendererMsaa.render(overlayPass, firstLine, referenceLineAboveCount);\n }\n if (markerAboveCount > 0) {\n annotationRenderers.annotationMarkerRendererMsaa.render(overlayPass, firstMarker, markerAboveCount);\n }\n overlayPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n }\n}\n","export default \"// grid.wgsl\\n// Minimal grid line shader:\\n// - Vertex input: vec2<f32> position in clip-space coordinates\\n// - Uniforms: identity transform + solid RGBA color\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn) -> VSOut {\\n var out: VSOut;\\n out.clipPosition = vsUniforms.transform * vec4<f32>(in.position, 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n return fsUniforms.color;\\n}\\n\"","/**\n * Shared renderer utilities.\n *\n * Minimal, library-friendly helpers for common WebGPU boilerplate:\n * - shader module creation\n * - render pipeline creation (ergonomic config + sensible defaults)\n * - uniform buffer creation + updates\n *\n * Notes:\n * - All helpers are pure functions; they create resources but do not mutate external state.\n * - First argument is always `device: GPUDevice`.\n */\n\nexport type ShaderStageModuleSource =\n | {\n /** Use an existing module. */\n readonly module: GPUShaderModule;\n readonly entryPoint?: string;\n readonly constants?: Record<string, GPUPipelineConstantValue>;\n }\n | {\n /** Provide WGSL code to compile. */\n readonly code: string;\n readonly label?: string;\n readonly entryPoint?: string;\n readonly constants?: Record<string, GPUPipelineConstantValue>;\n };\n\nexport type VertexStageConfig = ShaderStageModuleSource & {\n readonly buffers?: readonly GPUVertexBufferLayout[];\n};\n\nexport type FragmentStageConfig = ShaderStageModuleSource & {\n /**\n * Provide full color target states directly (most flexible).\n * If omitted, `formats` must be provided.\n */\n readonly targets?: readonly GPUColorTargetState[];\n /**\n * Convenience: provide one or more target formats and optionally a shared blend/writeMask.\n * Ignored if `targets` is provided.\n */\n readonly formats?: GPUTextureFormat | readonly GPUTextureFormat[];\n readonly blend?: GPUBlendState;\n readonly writeMask?: GPUColorWriteFlags;\n};\n\nexport type RenderPipelineConfig =\n | (RenderPipelineConfigBase & { readonly fragment: FragmentStageConfig })\n | (RenderPipelineConfigBase & { readonly fragment?: undefined });\n\nexport interface RenderPipelineConfigBase {\n readonly label?: string;\n\n /**\n * Defaults to `'auto'`.\n *\n * If you provide `bindGroupLayouts`, a pipeline layout will be created for you.\n * If both are provided, `layout` wins.\n */\n readonly layout?: GPUPipelineLayout | 'auto';\n readonly bindGroupLayouts?: readonly GPUBindGroupLayout[];\n\n readonly vertex: VertexStageConfig;\n\n readonly primitive?: GPUPrimitiveState;\n readonly depthStencil?: GPUDepthStencilState;\n readonly multisample?: GPUMultisampleState;\n}\n\nconst DEFAULT_VERTEX_ENTRY = 'vsMain';\nconst DEFAULT_FRAGMENT_ENTRY = 'fsMain';\n\nconst isPowerOfTwo = (n: number): boolean => Number.isInteger(n) && n > 0 && (n & (n - 1)) === 0;\n\nconst alignTo = (value: number, alignment: number): number => {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`alignTo(value): value must be a finite non-negative number. Received: ${String(value)}`);\n }\n if (!isPowerOfTwo(alignment)) {\n throw new Error(`alignTo(alignment): alignment must be a positive power of two. Received: ${String(alignment)}`);\n }\n const v = Math.floor(value);\n return (v + alignment - 1) & ~(alignment - 1);\n};\n\nconst getStageModule = (\n device: GPUDevice,\n stage: ShaderStageModuleSource\n): { readonly module: GPUShaderModule; readonly entryPoint: string; readonly constants?: Record<string, GPUPipelineConstantValue> } => {\n if ('module' in stage) {\n return {\n module: stage.module,\n entryPoint: stage.entryPoint || '',\n constants: stage.constants,\n };\n }\n\n return {\n module: createShaderModule(device, stage.code, stage.label),\n entryPoint: stage.entryPoint || '',\n constants: stage.constants,\n };\n};\n\n/**\n * Creates a shader module from WGSL source.\n */\nexport function createShaderModule(device: GPUDevice, code: string, label?: string): GPUShaderModule {\n if (typeof code !== 'string' || code.length === 0) {\n throw new Error('createShaderModule(code): WGSL code must be a non-empty string.');\n }\n return device.createShaderModule({ code, label });\n}\n\n/**\n * Creates a render pipeline with reduced boilerplate and sensible defaults.\n *\n * Defaults:\n * - `layout: 'auto'`\n * - `vertex.entryPoint: 'vsMain'`\n * - `fragment.entryPoint: 'fsMain'` (if fragment present)\n * - `primitive.topology: 'triangle-list'`\n * - `multisample.count: 1`\n */\nexport function createRenderPipeline(device: GPUDevice, config: RenderPipelineConfig): GPURenderPipeline {\n const layout: GPUPipelineLayout | 'auto' =\n config.layout ??\n (config.bindGroupLayouts ? device.createPipelineLayout({ bindGroupLayouts: [...config.bindGroupLayouts] }) : 'auto');\n\n const vertexStage = getStageModule(device, config.vertex);\n const vertexEntryPoint = vertexStage.entryPoint || DEFAULT_VERTEX_ENTRY;\n\n let fragment: GPUFragmentState | undefined = undefined;\n if (config.fragment) {\n const fragmentStage = getStageModule(device, config.fragment);\n const fragmentEntryPoint = fragmentStage.entryPoint || DEFAULT_FRAGMENT_ENTRY;\n\n let targets: readonly GPUColorTargetState[] | undefined = config.fragment.targets;\n if (!targets) {\n const formats = config.fragment.formats;\n if (!formats) {\n throw new Error(\n \"createRenderPipeline(fragment): provide either `fragment.targets` or `fragment.formats` when a fragment stage is present.\"\n );\n }\n const formatList = Array.isArray(formats) ? formats : [formats];\n targets = formatList.map((format) => ({\n format,\n blend: config.fragment!.blend,\n writeMask: config.fragment!.writeMask,\n }));\n }\n\n fragment = {\n module: fragmentStage.module,\n entryPoint: fragmentEntryPoint,\n targets: [...targets],\n constants: fragmentStage.constants,\n };\n }\n\n const primitive: GPUPrimitiveState = config.primitive ?? { topology: 'triangle-list' };\n const multisample: GPUMultisampleState = config.multisample ?? { count: 1 };\n\n return device.createRenderPipeline({\n label: config.label,\n layout,\n vertex: {\n module: vertexStage.module,\n entryPoint: vertexEntryPoint,\n buffers: config.vertex.buffers ? [...config.vertex.buffers] : [],\n constants: vertexStage.constants,\n },\n fragment,\n primitive,\n depthStencil: config.depthStencil,\n multisample,\n });\n}\n\n/**\n * Creates a uniform buffer suitable for `@group/@binding` uniform bindings.\n *\n * Notes:\n * - WebGPU's `queue.writeBuffer()` requires `byteLength` and offsets to be multiples of 4.\n * - Uniform data layout in WGSL is typically aligned to 16 bytes; we default to a 16-byte size alignment.\n * - If you plan to use this buffer with *dynamic offsets*, you must additionally align offsets to\n * `device.limits.minUniformBufferOffsetAlignment` (commonly 256). This helper does not enforce that.\n */\nexport function createUniformBuffer(\n device: GPUDevice,\n size: number,\n options?: { readonly label?: string; readonly alignment?: number }\n): GPUBuffer {\n if (!Number.isFinite(size) || size <= 0) {\n throw new Error(`createUniformBuffer(size): size must be a positive number. Received: ${String(size)}`);\n }\n\n const alignment = options?.alignment ?? 16;\n const alignedSize = alignTo(size, Math.max(4, alignment));\n\n const maxSize = device.limits.maxUniformBufferBindingSize;\n if (alignedSize > maxSize) {\n throw new Error(\n `createUniformBuffer(size): requested size ${alignedSize} exceeds device.limits.maxUniformBufferBindingSize (${maxSize}).`\n );\n }\n\n return device.createBuffer({\n label: options?.label,\n size: alignedSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n}\n\n/**\n * Writes CPU data into a uniform buffer (default offset 0).\n *\n * `data` must be a `BufferSource`:\n * - `ArrayBuffer` or `ArrayBufferView` (TypedArray/DataView)\n *\n * Important WebGPU constraint:\n * - `queue.writeBuffer()` requires write size (and offsets) to be multiples of 4 bytes.\n */\nexport function writeUniformBuffer(device: GPUDevice, buffer: GPUBuffer, data: BufferSource): void {\n const src =\n data instanceof ArrayBuffer\n ? { arrayBuffer: data, offset: 0, size: data.byteLength }\n : { arrayBuffer: data.buffer, offset: data.byteOffset, size: data.byteLength };\n\n if (src.size === 0) return;\n\n if ((src.offset & 3) !== 0 || (src.size & 3) !== 0) {\n throw new Error(\n `writeUniformBuffer(data): data byteOffset (${src.offset}) and byteLength (${src.size}) must be multiples of 4 for queue.writeBuffer().`\n );\n }\n\n if (src.size > buffer.size) {\n throw new Error(`writeUniformBuffer(data): data byteLength (${src.size}) exceeds buffer.size (${buffer.size}).`);\n }\n\n device.queue.writeBuffer(buffer, 0, src.arrayBuffer, src.offset, src.size);\n}\n","import gridWgsl from '../shaders/grid.wgsl?raw';\nimport type { AxisConfig } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport type { GridArea } from './createGridRenderer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\n\nexport interface AxisRenderer {\n prepare(\n axisConfig: AxisConfig,\n scale: LinearScale,\n orientation: 'x' | 'y',\n gridArea: GridArea,\n axisLineColor?: string,\n axisTickColor?: string,\n tickCount?: number\n ): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface AxisRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_TICK_COUNT = 5;\nconst DEFAULT_TICK_LENGTH_CSS_PX = 6;\nconst DEFAULT_AXIS_RGBA: readonly [number, number, number, number] = [1, 1, 1, 0.8];\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n // Column-major identity mat4x4\n const buffer = new ArrayBuffer(16 * 4);\n new Float32Array(buffer).set([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n ]);\n return buffer;\n};\n\nconst isFiniteGridArea = (gridArea: GridArea): boolean =>\n Number.isFinite(gridArea.left) &&\n Number.isFinite(gridArea.right) &&\n Number.isFinite(gridArea.top) &&\n Number.isFinite(gridArea.bottom) &&\n Number.isFinite(gridArea.canvasWidth) &&\n Number.isFinite(gridArea.canvasHeight);\n\nconst finiteOrUndefined = (v: number | undefined): number | undefined => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);\n\nconst normalizeDomain = (minCandidate: number, maxCandidate: number): { readonly min: number; readonly max: number } => {\n let min = minCandidate;\n let max = maxCandidate;\n\n if (!Number.isFinite(min) || !Number.isFinite(max)) {\n min = 0;\n max = 1;\n }\n\n if (min === max) {\n max = min + 1;\n } else if (min > max) {\n const t = min;\n min = max;\n max = t;\n }\n\n return { min, max };\n};\n\nconst generateAxisVertices = (\n axisConfig: AxisConfig,\n scale: LinearScale,\n orientation: 'x' | 'y',\n gridArea: GridArea,\n tickCountOverride?: number\n): Float32Array => {\n const { left, right, top, bottom, canvasWidth, canvasHeight } = gridArea;\n // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n const devicePixelRatio =\n Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n if (!isFiniteGridArea(gridArea)) {\n throw new Error('AxisRenderer.prepare: gridArea dimensions must be finite numbers.');\n }\n if (canvasWidth <= 0 || canvasHeight <= 0) {\n throw new Error('AxisRenderer.prepare: canvas dimensions must be positive.');\n }\n if (left < 0 || right < 0 || top < 0 || bottom < 0) {\n throw new Error('AxisRenderer.prepare: gridArea margins must be non-negative.');\n }\n\n const plotLeft = left * devicePixelRatio;\n const plotRight = canvasWidth - right * devicePixelRatio;\n const plotTop = top * devicePixelRatio;\n const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n const tickLengthCssPx = axisConfig.tickLength ?? DEFAULT_TICK_LENGTH_CSS_PX;\n if (!Number.isFinite(tickLengthCssPx) || tickLengthCssPx < 0) {\n throw new Error('AxisRenderer.prepare: tickLength must be a finite non-negative number.');\n }\n\n const tickCountRaw = tickCountOverride ?? DEFAULT_TICK_COUNT;\n const tickCount = Math.max(1, Math.floor(tickCountRaw));\n if (!Number.isFinite(tickCountRaw) || tickCount < 1) {\n throw new Error('AxisRenderer.prepare: tickCount must be a finite number >= 1.');\n }\n const tickLengthDevicePx = tickLengthCssPx * devicePixelRatio;\n const tickDeltaClipX = (tickLengthDevicePx / canvasWidth) * 2.0;\n const tickDeltaClipY = (tickLengthDevicePx / canvasHeight) * 2.0;\n\n // IMPORTANT: ignore non-finite overrides to keep GPU ticks consistent with the render coordinator\n // (which also treats min/max as “unset” when non-finite).\n const domainMinRaw =\n finiteOrUndefined(axisConfig.min) ??\n (orientation === 'x' ? scale.invert(plotLeftClip) : scale.invert(plotBottomClip));\n const domainMaxRaw =\n finiteOrUndefined(axisConfig.max) ??\n (orientation === 'x' ? scale.invert(plotRightClip) : scale.invert(plotTopClip));\n const domain = normalizeDomain(domainMinRaw, domainMaxRaw);\n const domainMin = domain.min;\n const domainMax = domain.max;\n\n // Line-list segments:\n // - 1 baseline segment\n // - tickCount tick segments\n const totalSegments = 1 + tickCount;\n const vertices = new Float32Array(totalSegments * 2 * 2); // segments * 2 vertices * vec2<f32>\n\n let idx = 0;\n\n if (orientation === 'x') {\n // Baseline along bottom edge of plot rect.\n vertices[idx++] = plotLeftClip;\n vertices[idx++] = plotBottomClip;\n vertices[idx++] = plotRightClip;\n vertices[idx++] = plotBottomClip;\n\n // Ticks extend downward (outside plot).\n const y0 = plotBottomClip;\n const y1 = y0 - tickDeltaClipY;\n\n for (let i = 0; i < tickCount; i++) {\n const t = tickCount === 1 ? 0.5 : i / (tickCount - 1);\n const v = domainMin + t * (domainMax - domainMin);\n const x = scale.scale(v);\n\n vertices[idx++] = x;\n vertices[idx++] = y0;\n vertices[idx++] = x;\n vertices[idx++] = y1;\n }\n } else {\n // Baseline along left edge of plot rect.\n vertices[idx++] = plotLeftClip;\n vertices[idx++] = plotBottomClip;\n vertices[idx++] = plotLeftClip;\n vertices[idx++] = plotTopClip;\n\n // Ticks extend left (outside plot).\n const x0 = plotLeftClip;\n const x1 = x0 - tickDeltaClipX;\n\n for (let i = 0; i < tickCount; i++) {\n const t = tickCount === 1 ? 0.5 : i / (tickCount - 1);\n const v = domainMin + t * (domainMax - domainMin);\n const y = scale.scale(v);\n\n vertices[idx++] = x0;\n vertices[idx++] = y;\n vertices[idx++] = x1;\n vertices[idx++] = y;\n }\n }\n\n return vertices;\n};\n\nexport function createAxisRenderer(device: GPUDevice, options?: AxisRendererOptions): AxisRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n ],\n });\n\n const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'axisRenderer/vsUniforms' });\n const fsUniformBufferLine = createUniformBuffer(device, 16, { label: 'axisRenderer/fsUniformsLine' });\n const fsUniformBufferTick = createUniformBuffer(device, 16, { label: 'axisRenderer/fsUniformsTick' });\n\n const bindGroupLine = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBufferLine } },\n ],\n });\n\n const bindGroupTick = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBufferTick } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'axisRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: gridWgsl,\n label: 'grid.wgsl',\n buffers: [\n {\n arrayStride: 8,\n stepMode: 'vertex',\n attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n },\n ],\n },\n fragment: {\n code: gridWgsl,\n label: 'grid.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'line-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let vertexBuffer: GPUBuffer | null = null;\n let vertexCount = 0;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('AxisRenderer is disposed.');\n };\n\n const prepare: AxisRenderer['prepare'] = (\n axisConfig,\n scale,\n orientation,\n gridArea,\n axisLineColor,\n axisTickColor,\n tickCount\n ) => {\n assertNotDisposed();\n\n if (orientation !== 'x' && orientation !== 'y') {\n throw new Error(\"AxisRenderer.prepare: orientation must be 'x' or 'y'.\");\n }\n\n const vertices = generateAxisVertices(axisConfig, scale, orientation, gridArea, tickCount);\n const requiredSize = vertices.byteLength;\n const bufferSize = Math.max(4, requiredSize);\n\n if (!vertexBuffer || vertexBuffer.size < bufferSize) {\n if (vertexBuffer) {\n try {\n vertexBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n vertexBuffer = device.createBuffer({\n label: 'axisRenderer/vertexBuffer',\n size: bufferSize,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer, 0, vertices.byteLength);\n vertexCount = vertices.length / 2;\n\n // Identity transform (vertices already in clip-space).\n writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer());\n\n // Separate colors for baseline vs ticks.\n // Gracefully fall back to legacy (slightly brighter than grid) when parsing fails.\n const axisLineColorString = axisLineColor ?? 'rgba(255,255,255,0.8)';\n const axisTickColorString = axisTickColor ?? axisLineColorString;\n\n const axisLineRgba = parseCssColorToRgba01(axisLineColorString) ?? DEFAULT_AXIS_RGBA;\n const axisTickRgba = parseCssColorToRgba01(axisTickColorString) ?? axisLineRgba;\n\n const lineColorBuffer = new ArrayBuffer(4 * 4);\n new Float32Array(lineColorBuffer).set([\n axisLineRgba[0],\n axisLineRgba[1],\n axisLineRgba[2],\n axisLineRgba[3],\n ]);\n writeUniformBuffer(device, fsUniformBufferLine, lineColorBuffer);\n\n const tickColorBuffer = new ArrayBuffer(4 * 4);\n new Float32Array(tickColorBuffer).set([\n axisTickRgba[0],\n axisTickRgba[1],\n axisTickRgba[2],\n axisTickRgba[3],\n ]);\n writeUniformBuffer(device, fsUniformBufferTick, tickColorBuffer);\n };\n\n const render: AxisRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (vertexCount === 0 || !vertexBuffer) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setVertexBuffer(0, vertexBuffer);\n\n // Baseline: first 2 vertices.\n passEncoder.setBindGroup(0, bindGroupLine);\n passEncoder.draw(Math.min(2, vertexCount));\n\n // Ticks: remaining vertices.\n if (vertexCount > 2) {\n passEncoder.setBindGroup(0, bindGroupTick);\n passEncoder.draw(vertexCount - 2, 1, 2, 0);\n }\n };\n\n const dispose: AxisRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBufferLine.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBufferTick.destroy();\n } catch {\n // best-effort\n }\n if (vertexBuffer) {\n try {\n vertexBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n\n vertexBuffer = null;\n vertexCount = 0;\n };\n\n return { prepare, render, dispose };\n}\n\n","import gridWgsl from '../shaders/grid.wgsl?raw';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport { parseCssColorToRgba01 } from '../utils/colors';\n\nexport interface GridRenderer {\n /**\n * Backward compatible:\n * - `prepare(gridArea, lineCount)` where `lineCount` is `{ horizontal?, vertical? }`\n *\n * Preferred:\n * - `prepare(gridArea, { lineCount, color })`\n */\n prepare(gridArea: GridArea, lineCountOrOptions?: GridLineCount | GridPrepareOptions): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface GridArea {\n readonly left: number; // Left margin in CSS pixels\n readonly right: number; // Right margin in CSS pixels\n readonly top: number; // Top margin in CSS pixels\n readonly bottom: number; // Bottom margin in CSS pixels\n readonly canvasWidth: number; // Canvas width in device pixels (canvas.width)\n readonly canvasHeight: number; // Canvas height in device pixels (canvas.height)\n readonly devicePixelRatio: number; // Device pixel ratio for CSS-to-device conversion\n}\n\nexport interface GridLineCount {\n readonly horizontal?: number; // Default: 5\n readonly vertical?: number; // Default: 6\n}\n\nexport interface GridPrepareOptions {\n readonly lineCount?: GridLineCount;\n /**\n * CSS color string used for grid lines.\n *\n * Expected formats: `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb(r,g,b)`, `rgba(r,g,b,a)`.\n */\n readonly color?: string;\n}\n\nexport interface GridRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_HORIZONTAL_LINES = 5;\nconst DEFAULT_VERTICAL_LINES = 6;\nconst DEFAULT_GRID_COLOR = 'rgba(255,255,255,0.15)';\nconst DEFAULT_GRID_RGBA: readonly [number, number, number, number] = [1, 1, 1, 0.15];\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n // Column-major identity mat4x4\n const buffer = new ArrayBuffer(16 * 4);\n new Float32Array(buffer).set([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n ]);\n return buffer;\n};\n\nconst generateGridVertices = (gridArea: GridArea, horizontal: number, vertical: number): Float32Array => {\n const { left, right, top, bottom, canvasWidth, canvasHeight } = gridArea;\n // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n const devicePixelRatio =\n Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n // Calculate plot area in device pixels using explicit DPR\n const plotLeft = left * devicePixelRatio;\n const plotRight = canvasWidth - right * devicePixelRatio;\n const plotTop = top * devicePixelRatio;\n const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n const plotWidth = plotRight - plotLeft;\n const plotHeight = plotBottom - plotTop;\n\n // Total vertices: (horizontal + vertical) * 2 vertices per line\n const totalLines = horizontal + vertical;\n const vertices = new Float32Array(totalLines * 2 * 2); // 2 vertices * 2 floats per vertex\n\n let idx = 0;\n\n // Generate horizontal lines (constant Y, varying X)\n for (let i = 0; i < horizontal; i++) {\n // Calculate t parameter for even spacing\n const t = horizontal === 1 ? 0.5 : i / (horizontal - 1);\n const yDevice = plotTop + t * plotHeight;\n\n // Convert to clip space\n const xClipLeft = (plotLeft / canvasWidth) * 2.0 - 1.0;\n const xClipRight = (plotRight / canvasWidth) * 2.0 - 1.0;\n const yClip = 1.0 - (yDevice / canvasHeight) * 2.0; // Flip Y-axis\n\n // First vertex (left edge)\n vertices[idx++] = xClipLeft;\n vertices[idx++] = yClip;\n\n // Second vertex (right edge)\n vertices[idx++] = xClipRight;\n vertices[idx++] = yClip;\n }\n\n // Generate vertical lines (constant X, varying Y)\n for (let i = 0; i < vertical; i++) {\n // Calculate t parameter for even spacing\n const t = vertical === 1 ? 0.5 : i / (vertical - 1);\n const xDevice = plotLeft + t * plotWidth;\n\n // Convert to clip space\n const xClip = (xDevice / canvasWidth) * 2.0 - 1.0;\n const yClipTop = 1.0 - (plotTop / canvasHeight) * 2.0; // Flip Y-axis\n const yClipBottom = 1.0 - (plotBottom / canvasHeight) * 2.0; // Flip Y-axis\n\n // First vertex (top edge)\n vertices[idx++] = xClip;\n vertices[idx++] = yClipTop;\n\n // Second vertex (bottom edge)\n vertices[idx++] = xClip;\n vertices[idx++] = yClipBottom;\n }\n\n return vertices;\n};\n\nexport function createGridRenderer(device: GPUDevice, options?: GridRendererOptions): GridRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n ],\n });\n\n const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'gridRenderer/vsUniforms' });\n const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'gridRenderer/fsUniforms' });\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBuffer } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'gridRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: gridWgsl,\n label: 'grid.wgsl',\n buffers: [\n {\n arrayStride: 8, // vec2<f32> = 2 * 4 bytes\n stepMode: 'vertex',\n attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n },\n ],\n },\n fragment: {\n code: gridWgsl,\n label: 'grid.wgsl',\n formats: targetFormat,\n // Enable standard alpha blending so `fsUniforms.color.a` behaves as expected\n // (blends into the cleared background instead of making the canvas pixels transparent).\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'line-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let vertexBuffer: GPUBuffer | null = null;\n let vertexCount = 0;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('GridRenderer is disposed.');\n };\n\n const prepare: GridRenderer['prepare'] = (gridArea, lineCountOrOptions) => {\n assertNotDisposed();\n\n const isOptionsObject =\n lineCountOrOptions != null &&\n typeof lineCountOrOptions === 'object' &&\n ('lineCount' in lineCountOrOptions || 'color' in lineCountOrOptions);\n\n const options: GridPrepareOptions | undefined = isOptionsObject\n ? (lineCountOrOptions as GridPrepareOptions)\n : undefined;\n\n const lineCount: GridLineCount | undefined = isOptionsObject\n ? options?.lineCount\n : (lineCountOrOptions as GridLineCount | undefined);\n\n const horizontal = lineCount?.horizontal ?? DEFAULT_HORIZONTAL_LINES;\n const vertical = lineCount?.vertical ?? DEFAULT_VERTICAL_LINES;\n const colorString = options?.color ?? DEFAULT_GRID_COLOR;\n\n // Validate inputs\n if (horizontal < 0 || vertical < 0) {\n throw new Error('GridRenderer.prepare: line counts must be non-negative.');\n }\n if (\n !Number.isFinite(gridArea.left) ||\n !Number.isFinite(gridArea.right) ||\n !Number.isFinite(gridArea.top) ||\n !Number.isFinite(gridArea.bottom) ||\n !Number.isFinite(gridArea.canvasWidth) ||\n !Number.isFinite(gridArea.canvasHeight)\n ) {\n throw new Error('GridRenderer.prepare: gridArea dimensions must be finite numbers.');\n }\n if (gridArea.canvasWidth <= 0 || gridArea.canvasHeight <= 0) {\n throw new Error('GridRenderer.prepare: canvas dimensions must be positive.');\n }\n\n // Early return if no lines to draw\n if (horizontal === 0 && vertical === 0) {\n vertexCount = 0;\n return;\n }\n\n // Generate vertices\n const vertices = generateGridVertices(gridArea, horizontal, vertical);\n const requiredSize = vertices.byteLength;\n\n // Ensure minimum buffer size of 4 bytes\n const bufferSize = Math.max(4, requiredSize);\n\n // Create or recreate vertex buffer if needed\n if (!vertexBuffer || vertexBuffer.size < bufferSize) {\n if (vertexBuffer) {\n try {\n vertexBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n\n vertexBuffer = device.createBuffer({\n label: 'gridRenderer/vertexBuffer',\n size: bufferSize,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n // Write vertex data\n device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer, 0, vertices.byteLength);\n vertexCount = (horizontal + vertical) * 2;\n\n // Write uniforms\n // VS uniform: identity transform (vertices already in clip space)\n const transformBuffer = createIdentityMat4Buffer();\n writeUniformBuffer(device, vsUniformBuffer, transformBuffer);\n\n // FS uniform: theme-driven (grid lines)\n const rgba = parseCssColorToRgba01(colorString) ?? DEFAULT_GRID_RGBA;\n const colorBuffer = new ArrayBuffer(4 * 4);\n new Float32Array(colorBuffer).set([rgba[0], rgba[1], rgba[2], rgba[3]]);\n writeUniformBuffer(device, fsUniformBuffer, colorBuffer);\n };\n\n const render: GridRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (vertexCount === 0 || !vertexBuffer) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, vertexBuffer);\n passEncoder.draw(vertexCount);\n };\n\n const dispose: GridRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n if (vertexBuffer) {\n try {\n vertexBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n\n vertexBuffer = null;\n vertexCount = 0;\n };\n\n return { prepare, render, dispose };\n}\n","export default \"// area.wgsl\\n// Minimal area-fill shader (triangle-strip):\\n// - Vertex input: vec2<f32> position in data coords\\n// - Uniforms: clip-space transform + baseline value + solid RGBA color\\n// - Topology: triangle-strip\\n// - CPU duplicates vertices as p0,p0,p1,p1,... and we use vertex_index parity:\\n// even index -> \\\"top\\\" vertex (original y)\\n// odd index -> \\\"baseline\\\" vertex (uniform baseline)\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n baseline: f32,\\n // Pad to 16-byte multiple (uniform buffer layout requirements).\\n _pad0: vec3<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n var out: VSOut;\\n let useBaseline = (vertexIndex & 1u) == 1u;\\n let y = select(in.position.y, vsUniforms.baseline, useBaseline);\\n let pos = vec2<f32>(in.position.x, y);\\n out.clipPosition = vsUniforms.transform * vec4<f32>(pos, 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n return fsUniforms.color;\\n}\\n\\n\"","import areaWgsl from '../shaders/area.wgsl?raw';\nimport type { ResolvedAreaSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface AreaRenderer {\n prepare(\n seriesConfig: ResolvedAreaSeriesConfig,\n // TODO(step 2): This will accept normalized ReadonlyArray<DataPoint>\n data: ReadonlyArray<DataPoint>,\n xScale: LinearScale,\n yScale: LinearScale,\n baseline?: number\n ): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface AreaRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst isTupleDataPoint = (point: DataPoint): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (\n point: DataPoint\n): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(point)) return { x: point[0], y: point[1] };\n return { x: point.x, y: point.y };\n};\n\nconst computeDataBounds = (\n data: ReadonlyArray<DataPoint>\n): { readonly xMin: number; readonly xMax: number; readonly yMin: number; readonly yMax: number } => {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < data.length; i++) {\n const { x, y } = getPointXY(data[i]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n }\n\n // Avoid degenerate domains for affine derivation (handled later too, but keep stable samples).\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst computeClipAffineFromScale = (\n scale: LinearScale,\n v0: number,\n v1: number\n): { readonly a: number; readonly b: number } => {\n const p0 = scale.scale(v0);\n const p1 = scale.scale(v1);\n\n // If the domain sample is degenerate or non-finite, fall back to constant output.\n if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n }\n\n const a = (p1 - p0) / (v1 - v0);\n const b = p0 - a * v0;\n return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n out[0] = ax;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0; // col0\n out[4] = 0;\n out[5] = ay;\n out[6] = 0;\n out[7] = 0; // col1\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0; // col2\n out[12] = bx;\n out[13] = by;\n out[14] = 0;\n out[15] = 1; // col3\n};\n\nconst createAreaVertices = (data: ReadonlyArray<DataPoint>): Float32Array => {\n // Triangle-strip expects duplicated vertices:\n // p0,p0,p1,p1,... and WGSL uses vertex_index parity to swap y to baseline for odd indices.\n const n = data.length;\n const out = new Float32Array(n * 2 * 2); // n * 2 vertices * vec2<f32>\n\n let idx = 0;\n for (let i = 0; i < n; i++) {\n const { x, y } = getPointXY(data[i]);\n out[idx++] = x;\n out[idx++] = y;\n out[idx++] = x;\n out[idx++] = y;\n }\n\n return out;\n};\n\nexport function createAreaRenderer(device: GPUDevice, options?: AreaRendererOptions): AreaRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n ],\n });\n\n const vsUniformBuffer = createUniformBuffer(device, 96, { label: 'areaRenderer/vsUniforms' });\n const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'areaRenderer/fsUniforms' });\n\n // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n const vsUniformScratchBuffer = new ArrayBuffer(96);\n const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n const fsUniformScratchF32 = new Float32Array(4);\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBuffer } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'areaRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: areaWgsl,\n label: 'area.wgsl',\n buffers: [\n {\n arrayStride: 8,\n stepMode: 'vertex',\n attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n },\n ],\n },\n fragment: {\n code: areaWgsl,\n label: 'area.wgsl',\n formats: targetFormat,\n // Enable standard alpha blending so `areaStyle.opacity` behaves correctly.\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-strip', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let vertexBuffer: GPUBuffer | null = null;\n let vertexCount = 0;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('AreaRenderer is disposed.');\n };\n\n const writeVsUniforms = (ax: number, bx: number, ay: number, by: number, baseline: number): void => {\n // VSUniforms:\n // - mat4x4<f32> (64 bytes)\n // - baseline: f32 (4 bytes)\n // - (implicit padding to next 16B boundary) (12 bytes)\n // - _pad0: vec3<f32> (occupies 16 bytes in a uniform buffer)\n // Total: 96 bytes.\n //\n // Layout details (uniform address space):\n // - transform at byte offset 0\n // - baseline at byte offset 64 (f32[16])\n // - _pad0 at byte offset 80 (f32[20..22]) with trailing 4B padding\n writeTransformMat4F32(vsUniformScratchF32, ax, bx, ay, by);\n vsUniformScratchF32[16] = baseline;\n vsUniformScratchF32[17] = 0;\n vsUniformScratchF32[18] = 0;\n vsUniformScratchF32[19] = 0;\n vsUniformScratchF32[20] = 0;\n vsUniformScratchF32[21] = 0;\n vsUniformScratchF32[22] = 0;\n vsUniformScratchF32[23] = 0;\n writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n };\n\n const prepare: AreaRenderer['prepare'] = (seriesConfig, data, xScale, yScale, baseline) => {\n assertNotDisposed();\n\n const vertices = createAreaVertices(data);\n const requiredSize = vertices.byteLength;\n const bufferSize = Math.max(4, requiredSize);\n\n if (!vertexBuffer || vertexBuffer.size < bufferSize) {\n if (vertexBuffer) {\n try {\n vertexBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n vertexBuffer = device.createBuffer({\n label: 'areaRenderer/vertexBuffer',\n size: bufferSize,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n if (vertices.byteLength > 0) {\n device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer, 0, vertices.byteLength);\n }\n vertexCount = vertices.length / 2;\n\n const { xMin, xMax, yMin, yMax } = computeDataBounds(data);\n const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n const baselineValue =\n Number.isFinite(baseline ?? Number.NaN) ? (baseline as number) : Number.isFinite(yMin) ? yMin : 0;\n\n writeVsUniforms(ax, bx, ay, by, baselineValue);\n\n // Use the resolved fill color from areaStyle.color (not seriesConfig.color).\n const [r, g, b, a] = parseSeriesColorToRgba01(seriesConfig.areaStyle.color);\n const opacity = clamp01(seriesConfig.areaStyle.opacity);\n fsUniformScratchF32[0] = r;\n fsUniformScratchF32[1] = g;\n fsUniformScratchF32[2] = b;\n fsUniformScratchF32[3] = clamp01(a * opacity);\n writeUniformBuffer(device, fsUniformBuffer, fsUniformScratchF32);\n };\n\n const render: AreaRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!vertexBuffer || vertexCount < 4) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, vertexBuffer);\n passEncoder.draw(vertexCount);\n };\n\n const dispose: AreaRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n if (vertexBuffer) {\n try {\n vertexBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n vertexBuffer = null;\n vertexCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n };\n\n return { prepare, render, dispose };\n}\n\n","export default \"// line.wgsl\\n// Minimal line-strip shader:\\n// - Vertex input: vec2<f32> position in data coords\\n// - Uniforms: clip-space transform + solid RGBA color\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn) -> VSOut {\\n var out: VSOut;\\n out.clipPosition = vsUniforms.transform * vec4<f32>(in.position, 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n return fsUniforms.color;\\n}\\n\\n\"","import lineWgsl from '../shaders/line.wgsl?raw';\nimport type { ResolvedLineSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface LineRenderer {\n prepare(\n seriesConfig: ResolvedLineSeriesConfig,\n dataBuffer: GPUBuffer,\n xScale: LinearScale,\n yScale: LinearScale,\n xOffset?: number\n ): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface LineRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst isTupleDataPoint = (\n point: DataPoint\n): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (point: DataPoint): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(point)) return { x: point[0], y: point[1] };\n return { x: point.x, y: point.y };\n};\n\nconst computeDataBounds = (\n data: ReadonlyArray<DataPoint>\n): { readonly xMin: number; readonly xMax: number; readonly yMin: number; readonly yMax: number } => {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < data.length; i++) {\n const { x, y } = getPointXY(data[i]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n }\n\n // Avoid degenerate domains for affine derivation (handled later too, but keep stable samples).\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst computeClipAffineFromScale = (\n scale: LinearScale,\n v0: number,\n v1: number\n): { readonly a: number; readonly b: number } => {\n const p0 = scale.scale(v0);\n const p1 = scale.scale(v1);\n\n // If the domain sample is degenerate or non-finite, fall back to constant output.\n if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n }\n\n const a = (p1 - p0) / (v1 - v0);\n const b = p0 - a * v0;\n return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n out[0] = ax;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0; // col0\n out[4] = 0;\n out[5] = ay;\n out[6] = 0;\n out[7] = 0; // col1\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0; // col2\n out[12] = bx;\n out[13] = by;\n out[14] = 0;\n out[15] = 1; // col3\n};\n\nexport function createLineRenderer(device: GPUDevice, options?: LineRendererOptions): LineRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n ],\n });\n\n const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'lineRenderer/vsUniforms' });\n const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'lineRenderer/fsUniforms' });\n\n // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n const vsUniformScratchBuffer = new ArrayBuffer(64);\n const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n const fsUniformScratchF32 = new Float32Array(4);\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBuffer } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'lineRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: lineWgsl,\n label: 'line.wgsl',\n buffers: [\n {\n arrayStride: 8,\n stepMode: 'vertex',\n attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n },\n ],\n },\n fragment: {\n code: lineWgsl,\n label: 'line.wgsl',\n formats: targetFormat,\n // Enable standard alpha blending so per-series `lineStyle.opacity` behaves\n // correctly against an opaque cleared background.\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'line-strip', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let currentVertexBuffer: GPUBuffer | null = null;\n let currentVertexCount = 0;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('LineRenderer is disposed.');\n };\n\n const prepare: LineRenderer['prepare'] = (seriesConfig, dataBuffer, xScale, yScale, xOffset = 0) => {\n assertNotDisposed();\n\n currentVertexBuffer = dataBuffer;\n // TODO(step 2): data will already be normalized to ReadonlyArray<DataPoint>\n const dataArray = seriesConfig.data as ReadonlyArray<DataPoint>;\n currentVertexCount = dataArray.length;\n\n const { xMin, xMax, yMin, yMax } = computeDataBounds(dataArray);\n const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n // When the vertex buffer packs x as (x - xOffset) (to preserve Float32 precision for large\n // domains like epoch-ms), fold the offset back into the affine's intercept in f64 on CPU:\n // clipX = ax * (x - xOffset) + (bx + ax * xOffset)\n const bxAdjusted = bx + ax * xOffset;\n writeTransformMat4F32(vsUniformScratchF32, ax, bxAdjusted, ay, by);\n writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n\n const [r, g, b, a] = parseSeriesColorToRgba01(seriesConfig.color);\n const opacity = clamp01(seriesConfig.lineStyle.opacity);\n fsUniformScratchF32[0] = r;\n fsUniformScratchF32[1] = g;\n fsUniformScratchF32[2] = b;\n fsUniformScratchF32[3] = clamp01(a * opacity);\n writeUniformBuffer(device, fsUniformBuffer, fsUniformScratchF32);\n };\n\n const render: LineRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!currentVertexBuffer || currentVertexCount < 2) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, currentVertexBuffer);\n passEncoder.draw(currentVertexCount);\n };\n\n const dispose: LineRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n currentVertexBuffer = null;\n currentVertexCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n };\n\n return { prepare, render, dispose };\n}\n","export default \"// bar.wgsl\\n// Instanced bar/rect shader:\\n// - Per-instance vertex input:\\n// - rect = vec4<f32>(x, y, width, height) in CLIP space\\n// - color = vec4<f32>(r, g, b, a) in [0..1]\\n// - Draw call: draw(6, instanceCount) using triangle-list expansion in VS\\n// - Uniforms:\\n// - @group(0) @binding(0): VSUniforms { transform }\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n // rect.xy = origin, rect.zw = size (width, height)\\n @location(0) rect: vec4<f32>,\\n @location(1) color: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n @location(0) color: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n // Fixed local corners for 2 triangles (triangle-list).\\n let corners = array<vec2<f32>, 6>(\\n vec2<f32>(0.0, 0.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(1.0, 1.0)\\n );\\n\\n // Normalize negative width/height by computing min/max extents.\\n let p0 = in.rect.xy;\\n let p1 = in.rect.xy + in.rect.zw;\\n let rectMin = min(p0, p1);\\n let rectMax = max(p0, p1);\\n let rectSize = rectMax - rectMin;\\n\\n let corner = corners[vertexIndex];\\n let pos = rectMin + corner * rectSize;\\n\\n var out: VSOut;\\n out.clipPosition = vsUniforms.transform * vec4<f32>(pos, 0.0, 1.0);\\n out.color = in.color;\\n return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n return in.color;\\n}\\n\\n\"","import barWgsl from '../shaders/bar.wgsl?raw';\nimport type { ResolvedBarSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport type { GridArea } from './createGridRenderer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { DataStore } from '../data/createDataStore';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface BarRenderer {\n prepare(\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n dataStore: DataStore,\n xScale: LinearScale,\n yScale: LinearScale,\n gridArea: GridArea\n ): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface BarRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_BAR_GAP = 0.01; // Minimal gap between bars within a group (was 0.1)\nconst DEFAULT_BAR_CATEGORY_GAP = 0.2;\nconst INSTANCE_STRIDE_BYTES = 32; // rect vec4 + color vec4\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst nextPow2 = (v: number): number => {\n if (!Number.isFinite(v) || v <= 0) return 1;\n const n = Math.ceil(v);\n return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n // Column-major identity mat4x4\n const buffer = new ArrayBuffer(16 * 4);\n new Float32Array(buffer).set([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n ]);\n return buffer;\n};\n\nconst parsePercent = (value: string): number | null => {\n const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n if (!m) return null;\n const p = Number(m[1]) / 100;\n return Number.isFinite(p) ? p : null;\n};\n\nconst normalizeStackId = (stack: unknown): string => {\n if (typeof stack !== 'string') return '';\n const trimmed = stack.trim();\n return trimmed.length > 0 ? trimmed : '';\n};\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n return { x: p.x, y: p.y };\n};\n\nconst computePlotSizeCssPx = (gridArea: GridArea): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n const dpr = gridArea.devicePixelRatio;\n if (!(dpr > 0)) return null;\n const canvasCssWidth = gridArea.canvasWidth / dpr;\n const canvasCssHeight = gridArea.canvasHeight / dpr;\n const plotWidthCss = canvasCssWidth - gridArea.left - gridArea.right;\n const plotHeightCss = canvasCssHeight - gridArea.top - gridArea.bottom;\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return null;\n return { plotWidthCss, plotHeightCss };\n};\n\nconst computePlotClipRect = (\n gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number } => {\n const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeft = left * devicePixelRatio;\n const plotRight = canvasWidth - right * devicePixelRatio;\n const plotTop = top * devicePixelRatio;\n const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n return { left: plotLeftClip, right: plotRightClip, top: plotTopClip, bottom: plotBottomClip };\n};\n\nconst computeCategoryWidthClip = (\n xScale: LinearScale,\n categoryStep: number,\n plotClipRect: Readonly<{ left: number; right: number }>,\n fallbackCategoryCount: number\n): number => {\n if (Number.isFinite(categoryStep) && categoryStep > 0) {\n const x0 = 0;\n const p0 = xScale.scale(x0);\n const p1 = xScale.scale(x0 + categoryStep);\n const w = Math.abs(p1 - p0);\n if (Number.isFinite(w) && w > 0) return w;\n }\n\n const clipWidth = Math.abs(plotClipRect.right - plotClipRect.left);\n if (!(clipWidth > 0)) return 0;\n const n = Math.max(1, Math.floor(fallbackCategoryCount));\n return clipWidth / n;\n};\n\nexport function createBarRenderer(device: GPUDevice, options?: BarRendererOptions): BarRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n ],\n });\n\n const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'barRenderer/vsUniforms' });\n // Default to identity: we upload rects in clip-space.\n writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer());\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'barRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: barWgsl,\n label: 'bar.wgsl',\n buffers: [\n {\n arrayStride: INSTANCE_STRIDE_BYTES, // rect vec4 + color vec4\n stepMode: 'instance',\n attributes: [\n { shaderLocation: 0, format: 'float32x4', offset: 0 },\n { shaderLocation: 1, format: 'float32x4', offset: 16 },\n ],\n },\n ],\n },\n fragment: {\n code: barWgsl,\n label: 'bar.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let instanceBuffer: GPUBuffer | null = null;\n let instanceCount = 0;\n let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n const categoryXScratch: number[] = [];\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('BarRenderer is disposed.');\n };\n\n const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n if (requiredFloats <= cpuInstanceStagingF32.length) return;\n // Grow geometrically (power-of-two) to reduce churn.\n const nextFloats = Math.max(8, nextPow2(requiredFloats));\n cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n };\n\n const computeBarCategoryStep = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n categoryXScratch.length = 0;\n for (let s = 0; s < seriesConfigs.length; s++) {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = seriesConfigs[s].data as ReadonlyArray<DataPoint>;\n for (let i = 0; i < data.length; i++) {\n const { x } = getPointXY(data[i]);\n if (Number.isFinite(x)) categoryXScratch.push(x);\n }\n }\n\n if (categoryXScratch.length < 2) return 1;\n categoryXScratch.sort((a, b) => a - b);\n\n let minStep = Number.POSITIVE_INFINITY;\n for (let i = 1; i < categoryXScratch.length; i++) {\n const d = categoryXScratch[i] - categoryXScratch[i - 1];\n if (d > 0 && d < minStep) minStep = d;\n }\n return Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n };\n\n const computeSharedBarLayout = (\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>\n ): { readonly barWidth?: number | string; readonly barGap?: number; readonly barCategoryGap?: number } => {\n let barWidth: number | string | undefined = undefined;\n let barGap: number | undefined = undefined;\n let barCategoryGap: number | undefined = undefined;\n\n for (let i = 0; i < seriesConfigs.length; i++) {\n const s = seriesConfigs[i];\n if (barWidth === undefined && s.barWidth !== undefined) barWidth = s.barWidth;\n if (barGap === undefined && s.barGap !== undefined) barGap = s.barGap;\n if (barCategoryGap === undefined && s.barCategoryGap !== undefined) barCategoryGap = s.barCategoryGap;\n }\n\n return { barWidth, barGap, barCategoryGap };\n };\n\n const computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let s = 0; s < seriesConfigs.length; s++) {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = seriesConfigs[s].data as ReadonlyArray<DataPoint>;\n for (let i = 0; i < data.length; i++) {\n const { y } = getPointXY(data[i]);\n if (!Number.isFinite(y)) continue;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n }\n\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) return 0;\n if (yMin <= 0 && 0 <= yMax) return 0;\n return Math.abs(yMin) < Math.abs(yMax) ? yMin : yMax;\n };\n\n const computeBaselineForBarsFromAxis = (\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n yScale: LinearScale,\n plotClipRect: Readonly<{ top: number; bottom: number }>\n ): number => {\n // Determine the visible y-domain from the yScale + plot clip rect (clip-space).\n const yDomainA = yScale.invert(plotClipRect.bottom);\n const yDomainB = yScale.invert(plotClipRect.top);\n const yMin = Math.min(yDomainA, yDomainB);\n const yMax = Math.max(yDomainA, yDomainB);\n\n // If scale/range is degenerate, fall back.\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return computeBaselineForBarsFromData(seriesConfigs);\n }\n\n if (yMin <= 0 && 0 <= yMax) return 0;\n if (yMin > 0) return yMin;\n if (yMax < 0) return yMax;\n\n // Should be unreachable with finite min/max, but keep a safe fallback.\n return computeBaselineForBarsFromData(seriesConfigs);\n };\n\n const prepare: BarRenderer['prepare'] = (seriesConfigs, dataStore, xScale, yScale, gridArea) => {\n assertNotDisposed();\n void dataStore;\n\n if (seriesConfigs.length === 0) {\n instanceCount = 0;\n return;\n }\n\n const plotSize = computePlotSizeCssPx(gridArea);\n if (!plotSize) {\n instanceCount = 0;\n return;\n }\n\n const plotClipRect = computePlotClipRect(gridArea);\n const plotClipWidth = plotClipRect.right - plotClipRect.left;\n const plotClipHeight = plotClipRect.top - plotClipRect.bottom;\n const clipPerCssX = plotSize.plotWidthCss > 0 ? plotClipWidth / plotSize.plotWidthCss : 0;\n void plotClipHeight; // reserved for future y-size conversions (e.g. border radius)\n\n // Cluster slots:\n // - Each unique non-empty stackId gets a single cluster slot.\n // - Each unstacked series gets its own cluster slot.\n const stackIdToClusterIndex = new Map<string, number>();\n const clusterIndexBySeries: number[] = new Array(seriesConfigs.length);\n let clusterCount = 0;\n for (let i = 0; i < seriesConfigs.length; i++) {\n const stackId = normalizeStackId(seriesConfigs[i].stack);\n if (stackId !== '') {\n const existing = stackIdToClusterIndex.get(stackId);\n if (existing !== undefined) {\n clusterIndexBySeries[i] = existing;\n } else {\n const idx = clusterCount++;\n stackIdToClusterIndex.set(stackId, idx);\n clusterIndexBySeries[i] = idx;\n }\n } else {\n clusterIndexBySeries[i] = clusterCount++;\n }\n }\n clusterCount = Math.max(1, clusterCount);\n\n const categoryStep = computeBarCategoryStep(seriesConfigs);\n const layout = computeSharedBarLayout(seriesConfigs);\n const barGap = clamp01(layout.barGap ?? DEFAULT_BAR_GAP);\n const barCategoryGap = clamp01(layout.barCategoryGap ?? DEFAULT_BAR_CATEGORY_GAP);\n\n let fallbackCategoryCount = 1;\n for (let s = 0; s < seriesConfigs.length; s++) {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const dataLength = (seriesConfigs[s].data as ReadonlyArray<DataPoint>).length;\n fallbackCategoryCount = Math.max(fallbackCategoryCount, Math.floor(dataLength));\n }\n\n const categoryWidthClip = computeCategoryWidthClip(xScale, categoryStep, plotClipRect, fallbackCategoryCount);\n const categoryInnerWidthClip = Math.max(0, categoryWidthClip * (1 - barCategoryGap));\n\n const denom = clusterCount + Math.max(0, clusterCount - 1) * barGap;\n const maxBarWidthClip = denom > 0 ? categoryInnerWidthClip / denom : 0;\n\n let barWidthClip = 0;\n const rawBarWidth = layout.barWidth;\n if (typeof rawBarWidth === 'number') {\n barWidthClip = Math.max(0, rawBarWidth) * clipPerCssX;\n barWidthClip = Math.min(barWidthClip, maxBarWidthClip);\n } else if (typeof rawBarWidth === 'string') {\n const p = parsePercent(rawBarWidth);\n barWidthClip = p == null ? 0 : maxBarWidthClip * clamp01(p);\n }\n\n if (!(barWidthClip > 0)) {\n // Auto-width: max per-bar width that still avoids overlap (given clusterCount and barGap).\n barWidthClip = maxBarWidthClip;\n }\n\n const gapClip = barWidthClip * barGap;\n const clusterWidthClip = clusterCount * barWidthClip + Math.max(0, clusterCount - 1) * gapClip;\n\n let baselineDomain = computeBaselineForBarsFromAxis(seriesConfigs, yScale, plotClipRect);\n let baselineClip = yScale.scale(baselineDomain);\n if (!Number.isFinite(baselineClip)) {\n // Fallback for pathological scales: revert to data-derived baseline, then 0.\n const fallbackBaselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n baselineDomain = fallbackBaselineDomain;\n baselineClip = yScale.scale(fallbackBaselineDomain);\n if (!Number.isFinite(baselineClip)) {\n baselineDomain = 0;\n baselineClip = yScale.scale(0);\n }\n if (!Number.isFinite(baselineClip)) {\n instanceCount = 0;\n return;\n }\n }\n\n let maxBars = 0;\n for (let s = 0; s < seriesConfigs.length; s++) {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n maxBars += Math.max(0, (seriesConfigs[s].data as ReadonlyArray<DataPoint>).length);\n }\n\n ensureCpuInstanceCapacityFloats(maxBars * INSTANCE_STRIDE_FLOATS);\n const f32 = cpuInstanceStagingF32;\n let outFloats = 0;\n\n // Per-stack, per-x running sums in domain units (supports negative stacking too).\n const stackSumsByStackId = new Map<string, Map<number, { posSum: number; negSum: number }>>();\n\n for (let seriesIndex = 0; seriesIndex < seriesConfigs.length; seriesIndex++) {\n const series = seriesConfigs[seriesIndex];\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = series.data as ReadonlyArray<DataPoint>;\n const [r, g, b, a] = parseSeriesColorToRgba01(series.color);\n const stackId = normalizeStackId(series.stack);\n const clusterIndex = clusterIndexBySeries[seriesIndex] ?? 0;\n\n for (let i = 0; i < data.length; i++) {\n const { x, y } = getPointXY(data[i]);\n const xClipCenter = xScale.scale(x);\n if (!Number.isFinite(xClipCenter) || !Number.isFinite(y)) continue;\n\n const left = xClipCenter - clusterWidthClip / 2 + clusterIndex * (barWidthClip + gapClip);\n\n let baseClip = baselineClip;\n let height = 0;\n\n if (stackId !== '') {\n let sumsForX = stackSumsByStackId.get(stackId);\n if (!sumsForX) {\n sumsForX = new Map<number, { posSum: number; negSum: number }>();\n stackSumsByStackId.set(stackId, sumsForX);\n }\n\n // NOTE: Never key stacks by raw `x` (float equality is fragile). Instead, compute a stable\n // integer \"category\" key so visually-equivalent bars stack together even with tiny noise.\n let xKey: number;\n if (Number.isFinite(categoryWidthClip) && categoryWidthClip > 0 && Number.isFinite(xClipCenter)) {\n xKey = Math.round((xClipCenter - plotClipRect.left) / categoryWidthClip);\n } else if (Number.isFinite(categoryStep) && categoryStep > 0) {\n xKey = Math.round(x / categoryStep);\n } else {\n // Last-resort: stable-ish quantization in domain space.\n xKey = Math.round(x * 1e6);\n }\n\n let sums = sumsForX.get(xKey);\n if (!sums) {\n sums = { posSum: baselineDomain, negSum: baselineDomain };\n sumsForX.set(xKey, sums);\n }\n\n // Stack upward for y>=0, downward for y<0 (domain units).\n let baseDomain: number;\n let topDomain: number;\n if (y >= 0) {\n baseDomain = sums.posSum;\n topDomain = baseDomain + y;\n sums.posSum = topDomain;\n } else {\n baseDomain = sums.negSum;\n topDomain = baseDomain + y;\n sums.negSum = topDomain;\n }\n\n const bClip = yScale.scale(baseDomain);\n const tClip = yScale.scale(topDomain);\n if (!Number.isFinite(bClip) || !Number.isFinite(tClip)) continue;\n baseClip = bClip;\n height = tClip - bClip;\n } else {\n const yClip = yScale.scale(y);\n if (!Number.isFinite(yClip)) continue;\n height = yClip - baselineClip;\n }\n\n f32[outFloats + 0] = left;\n f32[outFloats + 1] = baseClip;\n f32[outFloats + 2] = barWidthClip;\n f32[outFloats + 3] = height;\n f32[outFloats + 4] = r;\n f32[outFloats + 5] = g;\n f32[outFloats + 6] = b;\n f32[outFloats + 7] = a;\n outFloats += INSTANCE_STRIDE_FLOATS;\n }\n }\n\n // If we skipped invalid points, resize the effective instance count.\n instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = device.createBuffer({\n label: 'barRenderer/instanceBuffer',\n size: grownBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n if (instanceCount > 0) {\n device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n }\n };\n\n const render: BarRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!instanceBuffer || instanceCount === 0) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, instanceBuffer);\n passEncoder.draw(6, instanceCount);\n };\n\n const dispose: BarRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = null;\n instanceCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n };\n\n return { prepare, render, dispose };\n}\n\n","export default \"// scatter.wgsl\\n// Instanced anti-aliased circle shader (SDF):\\n// - Per-instance vertex input:\\n// - center = vec2<f32> point center (transformed by VSUniforms.transform)\\n// - radiusPx = f32 circle radius in pixels\\n// - Draw call: draw(6, instanceCount) using triangle-list expansion in VS\\n// - Uniforms:\\n// - @group(0) @binding(0): VSUniforms { transform, viewportPx }\\n// - @group(0) @binding(1): FSUniforms { color }\\n//\\n// Notes:\\n// - `viewportPx` is the current render target size in pixels (width, height).\\n// - The quad is expanded in clip space using `radiusPx` and `viewportPx`.\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n viewportPx: vec2<f32>,\\n // Pad to 16-byte alignment (mat4x4 is 64B; vec2 adds 8B; pad to 80B).\\n _pad0: vec2<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n @location(0) center: vec2<f32>,\\n @location(1) radiusPx: f32,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n @location(0) localPx: vec2<f32>,\\n @location(1) radiusPx: f32,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n // Fixed local corners for 2 triangles (triangle-list).\\n // `localNdc` is a quad in [-1, 1]^2; we convert it to pixel offsets via radiusPx.\\n let localNdc = array<vec2<f32>, 6>(\\n vec2<f32>(-1.0, -1.0),\\n vec2<f32>( 1.0, -1.0),\\n vec2<f32>(-1.0, 1.0),\\n vec2<f32>(-1.0, 1.0),\\n vec2<f32>( 1.0, -1.0),\\n vec2<f32>( 1.0, 1.0)\\n );\\n\\n let corner = localNdc[vertexIndex];\\n let localPx = corner * in.radiusPx;\\n\\n // Convert pixel offset to clip-space offset.\\n // Clip space spans [-1, 1] across the viewport, so px -> clip is (2 / viewportPx).\\n let localClip = localPx * (2.0 / vsUniforms.viewportPx);\\n\\n let centerClip = (vsUniforms.transform * vec4<f32>(in.center, 0.0, 1.0)).xy;\\n\\n var out: VSOut;\\n out.clipPosition = vec4<f32>(centerClip + localClip, 0.0, 1.0);\\n out.localPx = localPx;\\n out.radiusPx = in.radiusPx;\\n return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n // Signed distance to the circle boundary (negative inside).\\n let dist = length(in.localPx) - in.radiusPx;\\n\\n // Analytic-ish AA: smooth edge based on derivative of dist in screen space.\\n let w = fwidth(dist);\\n let a = 1.0 - smoothstep(0.0, w, dist);\\n\\n // Discard fully outside to avoid unnecessary blending work.\\n if (a <= 0.0) {\\n discard;\\n }\\n\\n return vec4<f32>(fsUniforms.color.rgb, fsUniforms.color.a * a);\\n}\\n\\n\"","import scatterWgsl from '../shaders/scatter.wgsl?raw';\nimport type { ResolvedScatterSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple, ScatterPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { GridArea } from './createGridRenderer';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface ScatterRenderer {\n prepare(\n seriesConfig: ResolvedScatterSeriesConfig,\n // TODO(step 2): This will accept normalized ReadonlyArray<DataPoint>\n data: ReadonlyArray<DataPoint>,\n xScale: LinearScale,\n yScale: LinearScale,\n gridArea?: GridArea\n ): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface ScatterRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_SCATTER_RADIUS_CSS_PX = 4;\nconst INSTANCE_STRIDE_BYTES = 16; // center.xy, radiusPx, pad\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst nextPow2 = (v: number): number => {\n if (!Number.isFinite(v) || v <= 0) return 1;\n const n = Math.ceil(v);\n return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst isTupleDataPoint = (point: DataPoint): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (point: DataPoint): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(point)) return { x: point[0], y: point[1] };\n return { x: point.x, y: point.y };\n};\n\nconst getPointSizeCssPx = (point: DataPoint): number | null => {\n if (isTupleDataPoint(point)) {\n const s = point[2];\n return typeof s === 'number' && Number.isFinite(s) ? s : null;\n }\n const s = point.size;\n return typeof s === 'number' && Number.isFinite(s) ? s : null;\n};\n\nconst toScatterTuple = (point: DataPoint): ScatterPointTuple => {\n if (isTupleDataPoint(point)) return point;\n return [point.x, point.y, point.size] as const;\n};\n\nconst computeDataBounds = (\n data: ReadonlyArray<DataPoint>\n): { readonly xMin: number; readonly xMax: number; readonly yMin: number; readonly yMax: number } => {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < data.length; i++) {\n const { x, y } = getPointXY(data[i]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n }\n\n // Avoid degenerate domains for affine derivation (handled later too, but keep stable samples).\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst computeClipAffineFromScale = (\n scale: LinearScale,\n v0: number,\n v1: number\n): { readonly a: number; readonly b: number } => {\n const p0 = scale.scale(v0);\n const p1 = scale.scale(v1);\n\n // If the domain sample is degenerate or non-finite, fall back to constant output.\n if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n }\n\n const a = (p1 - p0) / (v1 - v0);\n const b = p0 - a * v0;\n return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n out[0] = ax;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0; // col0\n out[4] = 0;\n out[5] = ay;\n out[6] = 0;\n out[7] = 0; // col1\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0; // col2\n out[12] = bx;\n out[13] = by;\n out[14] = 0;\n out[15] = 1; // col3\n};\n\nconst computePlotScissorDevicePx = (\n gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nexport function createScatterRenderer(device: GPUDevice, options?: ScatterRendererOptions): ScatterRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n ],\n });\n\n // VSUniforms: mat4x4 (64) + viewportPx vec2 (8) + pad vec2 (8) = 80 bytes.\n const vsUniformBuffer = createUniformBuffer(device, 80, { label: 'scatterRenderer/vsUniforms' });\n const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'scatterRenderer/fsUniforms' });\n\n // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n const vsUniformScratchBuffer = new ArrayBuffer(80);\n const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n const fsUniformScratchF32 = new Float32Array(4);\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBuffer } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'scatterRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: scatterWgsl,\n label: 'scatter.wgsl',\n buffers: [\n {\n arrayStride: INSTANCE_STRIDE_BYTES,\n stepMode: 'instance',\n attributes: [\n { shaderLocation: 0, format: 'float32x2', offset: 0 },\n { shaderLocation: 1, format: 'float32', offset: 8 },\n ],\n },\n ],\n },\n fragment: {\n code: scatterWgsl,\n label: 'scatter.wgsl',\n formats: targetFormat,\n // Standard alpha blending (circle AA uses alpha, and series color may be translucent).\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let instanceBuffer: GPUBuffer | null = null;\n let instanceCount = 0;\n let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n let lastCanvasWidth = 0;\n let lastCanvasHeight = 0;\n let lastViewportPx: readonly [number, number] = [1, 1];\n let lastScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('ScatterRenderer is disposed.');\n };\n\n const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n if (requiredFloats <= cpuInstanceStagingF32.length) return;\n const nextFloats = Math.max(8, nextPow2(requiredFloats));\n cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n };\n\n const writeVsUniforms = (\n ax: number,\n bx: number,\n ay: number,\n by: number,\n viewportW: number,\n viewportH: number\n ): void => {\n const w = Number.isFinite(viewportW) && viewportW > 0 ? viewportW : 1;\n const h = Number.isFinite(viewportH) && viewportH > 0 ? viewportH : 1;\n\n writeTransformMat4F32(vsUniformScratchF32, ax, bx, ay, by);\n vsUniformScratchF32[16] = w;\n vsUniformScratchF32[17] = h;\n vsUniformScratchF32[18] = 0;\n vsUniformScratchF32[19] = 0;\n writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n\n lastViewportPx = [w, h];\n };\n\n const prepare: ScatterRenderer['prepare'] = (seriesConfig, data, xScale, yScale, gridArea) => {\n assertNotDisposed();\n\n const { xMin, xMax, yMin, yMax } = computeDataBounds(data);\n const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n if (gridArea) {\n lastCanvasWidth = gridArea.canvasWidth;\n lastCanvasHeight = gridArea.canvasHeight;\n writeVsUniforms(ax, bx, ay, by, gridArea.canvasWidth, gridArea.canvasHeight);\n lastScissor = computePlotScissorDevicePx(gridArea);\n } else {\n // Backward-compatible: keep rendering with the last known viewport (or safe default).\n writeVsUniforms(ax, bx, ay, by, lastViewportPx[0], lastViewportPx[1]);\n lastScissor = null;\n }\n\n const [r, g, b, a] = parseSeriesColorToRgba01(seriesConfig.color);\n fsUniformScratchF32[0] = r;\n fsUniformScratchF32[1] = g;\n fsUniformScratchF32[2] = b;\n fsUniformScratchF32[3] = clamp01(a);\n writeUniformBuffer(device, fsUniformBuffer, fsUniformScratchF32);\n\n const dpr = gridArea?.devicePixelRatio ?? 1;\n const hasValidDpr = dpr > 0 && Number.isFinite(dpr);\n\n const seriesSymbolSize = seriesConfig.symbolSize;\n const getSeriesSizeCssPx =\n typeof seriesSymbolSize === 'function'\n ? (point: DataPoint): number => {\n const v = seriesSymbolSize(toScatterTuple(point));\n return typeof v === 'number' && Number.isFinite(v) ? v : DEFAULT_SCATTER_RADIUS_CSS_PX;\n }\n : typeof seriesSymbolSize === 'number' && Number.isFinite(seriesSymbolSize)\n ? (): number => seriesSymbolSize\n : (): number => DEFAULT_SCATTER_RADIUS_CSS_PX;\n\n ensureCpuInstanceCapacityFloats(data.length * INSTANCE_STRIDE_FLOATS);\n const f32 = cpuInstanceStagingF32;\n let outFloats = 0;\n\n for (let i = 0; i < data.length; i++) {\n const p = data[i];\n const { x, y } = getPointXY(p);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\n const sizeCss = getPointSizeCssPx(p) ?? getSeriesSizeCssPx(p);\n const radiusCss = Number.isFinite(sizeCss) ? Math.max(0, sizeCss) : DEFAULT_SCATTER_RADIUS_CSS_PX;\n const radiusDevicePx = hasValidDpr ? radiusCss * dpr : radiusCss;\n if (!(radiusDevicePx > 0)) continue;\n\n f32[outFloats + 0] = x;\n f32[outFloats + 1] = y;\n f32[outFloats + 2] = radiusDevicePx;\n f32[outFloats + 3] = 0; // pad\n outFloats += INSTANCE_STRIDE_FLOATS;\n }\n\n instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = device.createBuffer({\n label: 'scatterRenderer/instanceBuffer',\n size: grownBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n if (instanceBuffer && instanceCount > 0) {\n device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n }\n };\n\n const render: ScatterRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!instanceBuffer || instanceCount === 0) return;\n\n // Clip to plot area when available.\n if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n }\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, instanceBuffer);\n passEncoder.draw(6, instanceCount);\n\n // Reset scissor to full canvas to avoid impacting later renderers.\n if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n }\n };\n\n const dispose: ScatterRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = null;\n instanceCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n\n lastCanvasWidth = 0;\n lastCanvasHeight = 0;\n lastViewportPx = [1, 1];\n lastScissor = null;\n };\n\n return { prepare, render, dispose };\n}\n\n","export default \"struct ComputeUniforms {\\n transform: mat4x4<f32>,\\n viewportPx: vec2f,\\n _pad0: vec2f,\\n plotOriginPx: vec2<u32>,\\n plotSizePx: vec2<u32>,\\n binSizePx: u32,\\n binCountX: u32,\\n binCountY: u32,\\n visibleStart: u32,\\n visibleEnd: u32,\\n normalization: u32,\\n _pad1: vec2<u32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> u: ComputeUniforms;\\n@group(0) @binding(1) var<storage, read> points: array<vec2f>;\\n@group(0) @binding(2) var<storage, read_write> bins: array<atomic<u32>>;\\n\\nstruct MaxBuffer {\\n value: atomic<u32>,\\n};\\n@group(0) @binding(3) var<storage, read_write> maxBuf: MaxBuffer;\\n\\nfn clipToDevicePx(clip: vec2f) -> vec2f {\\n // clip in [-1,1] -> device pixel in [0, viewport]\\n return vec2f(\\n (clip.x * 0.5 + 0.5) * u.viewportPx.x,\\n (-clip.y * 0.5 + 0.5) * u.viewportPx.y\\n );\\n}\\n\\n@compute @workgroup_size(256)\\nfn binPoints(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let idx = u.visibleStart + gid.x;\\n if (idx >= u.visibleEnd) {\\n return;\\n }\\n\\n let p = points[idx];\\n let clip4 = u.transform * vec4f(p.x, p.y, 0.0, 1.0);\\n let clip = clip4.xy / max(1e-9, clip4.w);\\n let px = clipToDevicePx(clip);\\n\\n // Scissor bounds in device px\\n let left = f32(u.plotOriginPx.x);\\n let top = f32(u.plotOriginPx.y);\\n let right = left + f32(u.plotSizePx.x);\\n let bottom = top + f32(u.plotSizePx.y);\\n\\n if (px.x < left || px.x >= right || px.y < top || px.y >= bottom) {\\n return;\\n }\\n\\n let localX = u32((px.x - left) / f32(u.binSizePx));\\n let localY = u32((px.y - top) / f32(u.binSizePx));\\n if (localX >= u.binCountX || localY >= u.binCountY) {\\n return;\\n }\\n\\n let binIndex = localY * u.binCountX + localX;\\n atomicAdd(&bins[binIndex], 1u);\\n}\\n\\n@compute @workgroup_size(256)\\nfn reduceMax(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let binTotal = u.binCountX * u.binCountY;\\n let i = gid.x;\\n if (i >= binTotal) {\\n return;\\n }\\n\\n let v = atomicLoad(&bins[i]);\\n atomicMax(&maxBuf.value, v);\\n}\\n\\n\"","export default \"struct RenderUniforms {\\n plotOriginPx: vec2<u32>,\\n plotSizePx: vec2<u32>,\\n binSizePx: u32,\\n binCountX: u32,\\n binCountY: u32,\\n normalization: u32,\\n _pad: vec2<u32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> u: RenderUniforms;\\n@group(0) @binding(1) var<storage, read> bins: array<u32>;\\n@group(0) @binding(2) var<storage, read> maxBuf: array<u32>;\\n@group(0) @binding(3) var lutTex: texture_2d<f32>;\\n\\nstruct VsOut {\\n @builtin(position) position: vec4f,\\n};\\n\\n@vertex\\nfn vsMain(@builtin(vertex_index) vid: u32) -> VsOut {\\n // Fullscreen triangle (covers clip space).\\n // (0,0)->(-1,-1), (2,0)->(3,-1), (0,2)->(-1,3)\\n var pos = array<vec2f, 3>(\\n vec2f(-1.0, -1.0),\\n vec2f(3.0, -1.0),\\n vec2f(-1.0, 3.0)\\n );\\n var out: VsOut;\\n out.position = vec4f(pos[vid], 0.0, 1.0);\\n return out;\\n}\\n\\nfn applyNormalization(count: f32, maxCount: f32, mode: u32) -> f32 {\\n if (maxCount <= 0.0) {\\n return 0.0;\\n }\\n let t = clamp(count / maxCount, 0.0, 1.0);\\n if (mode == 1u) { // sqrt\\n return sqrt(t);\\n }\\n if (mode == 2u) { // log\\n // log1p(count) / log1p(max)\\n return clamp(log(1.0 + count) / max(1e-9, log(1.0 + maxCount)), 0.0, 1.0);\\n }\\n return t; // linear\\n}\\n\\n@fragment\\nfn fsMain(@builtin(position) pos: vec4f) -> @location(0) vec4f {\\n // pos.xy is framebuffer pixel coords (device px) with origin top-left.\\n let x = pos.x;\\n let y = pos.y;\\n\\n let left = f32(u.plotOriginPx.x);\\n let top = f32(u.plotOriginPx.y);\\n // plot scissor also applied on CPU; keep a guard anyway.\\n if (x < left || y < top) {\\n return vec4f(0.0);\\n }\\n\\n let localX = u32((x - left) / f32(u.binSizePx));\\n let localY = u32((y - top) / f32(u.binSizePx));\\n if (localX >= u.binCountX || localY >= u.binCountY) {\\n return vec4f(0.0);\\n }\\n\\n let idx = localY * u.binCountX + localX;\\n let c = f32(bins[idx]);\\n let maxC = f32(maxBuf[0]);\\n\\n let t = applyNormalization(c, maxC, u.normalization);\\n let lutX = i32(round(t * 255.0));\\n let lut = textureLoad(lutTex, vec2<i32>(lutX, 0), 0);\\n return vec4f(lut.rgb, 1.0);\\n}\\n\\n\"","import scatterDensityBinningWgsl from '../shaders/scatterDensityBinning.wgsl?raw';\nimport scatterDensityColormapWgsl from '../shaders/scatterDensityColormap.wgsl?raw';\nimport type { RawBounds, ResolvedScatterSeriesConfig } from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { GridArea } from './createGridRenderer';\nimport { createRenderPipeline, createShaderModule, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface ScatterDensityRenderer {\n prepare(\n seriesConfig: ResolvedScatterSeriesConfig,\n pointBuffer: GPUBuffer,\n pointCount: number,\n visibleStartIndex: number,\n visibleEndIndex: number,\n xScale: LinearScale,\n yScale: LinearScale,\n gridArea: GridArea,\n rawBounds?: RawBounds\n ): void;\n encodeCompute(encoder: GPUCommandEncoder): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface ScatterDensityRendererOptions {\n readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst nextPow2 = (v: number): number => {\n if (!Number.isFinite(v) || v <= 0) return 1;\n const n = Math.ceil(v);\n return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst computeClipAffineFromScale = (\n scale: LinearScale,\n v0: number,\n v1: number\n): { readonly a: number; readonly b: number } => {\n const p0 = scale.scale(v0);\n const p1 = scale.scale(v1);\n\n if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n }\n\n const a = (p1 - p0) / (v1 - v0);\n const b = p0 - a * v0;\n return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n out[0] = ax;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = ay;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = bx;\n out[13] = by;\n out[14] = 0;\n out[15] = 1;\n};\n\nconst computePlotScissorDevicePx = (\n gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\ntype Rgba01 = readonly [r: number, g: number, b: number, a: number];\n\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\nconst lerpRgba = (a: Rgba01, b: Rgba01, t: number): Rgba01 =>\n [lerp(a[0], b[0], t), lerp(a[1], b[1], t), lerp(a[2], b[2], t), lerp(a[3], b[3], t)] as const;\n\nconst parseColorStop = (css: string): Rgba01 => parseCssColorToRgba01(css) ?? ([0, 0, 0, 1] as const);\n\nconst getNamedStops = (name: 'viridis' | 'plasma' | 'inferno'): readonly string[] => {\n // Compact stop lists (interpolated to 256 entries). These are standard-ish anchors.\n if (name === 'plasma') {\n return ['#0d0887', '#6a00a8', '#b12a90', '#e16462', '#fca636', '#f0f921'] as const;\n }\n if (name === 'inferno') {\n return ['#000004', '#420a68', '#932667', '#dd513a', '#fca50a', '#fcffa4'] as const;\n }\n // viridis\n return ['#440154', '#3b528b', '#21918c', '#5ec962', '#fde725'] as const;\n};\n\nconst buildLutRGBA8 = (colormap: ResolvedScatterSeriesConfig['densityColormap']): Uint8Array<ArrayBuffer> => {\n const stopsCss =\n typeof colormap === 'string'\n ? getNamedStops(colormap)\n : Array.isArray(colormap) && colormap.length > 0\n ? colormap\n : (getNamedStops('viridis') as readonly string[]);\n\n const stops = stopsCss.map(parseColorStop);\n const n = Math.max(2, stops.length);\n\n // Ensure the underlying buffer is a plain ArrayBuffer (not SharedArrayBuffer) for WebGPU typings.\n const out: Uint8Array<ArrayBuffer> = new Uint8Array(new ArrayBuffer(256 * 4));\n for (let i = 0; i < 256; i++) {\n const t = i / 255;\n const x = t * (n - 1);\n const seg = Math.min(n - 2, Math.max(0, Math.floor(x)));\n const localT = x - seg;\n const c = lerpRgba(stops[seg]!, stops[seg + 1]!, localT);\n\n out[i * 4 + 0] = clampInt(Math.round(clamp01(c[0]) * 255), 0, 255);\n out[i * 4 + 1] = clampInt(Math.round(clamp01(c[1]) * 255), 0, 255);\n out[i * 4 + 2] = clampInt(Math.round(clamp01(c[2]) * 255), 0, 255);\n out[i * 4 + 3] = clampInt(Math.round(clamp01(c[3]) * 255), 0, 255);\n }\n return out;\n};\n\nconst colormapKey = (colormap: ResolvedScatterSeriesConfig['densityColormap']): string => {\n if (typeof colormap === 'string') return colormap;\n try {\n return JSON.stringify(colormap);\n } catch {\n return 'custom';\n }\n};\n\nconst normalizationToU32 = (n: ResolvedScatterSeriesConfig['densityNormalization']): number => {\n // Must match shader:\n // 0: linear, 1: sqrt, 2: log\n if (n === 'sqrt') return 1;\n if (n === 'log') return 2;\n return 0;\n};\n\nexport function createScatterDensityRenderer(\n device: GPUDevice,\n options?: ScatterDensityRendererOptions\n): ScatterDensityRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const computeBindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } },\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } },\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } },\n ],\n });\n\n const renderBindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n // `scatterDensityColormap.wgsl` declares these as `var<storage, read>`, so they must be read-only-storage.\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } },\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } },\n { binding: 3, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'unfilterable-float' } },\n ],\n });\n\n // Compute uniforms:\n // transform(64) + viewportPx(8)+pad(8)=80\n // plotOriginPx u32x2(8) + plotSizePx u32x2(8) = 16 => 96\n // binSize/binCountX/binCountY/start/end/norm u32*6 (24) + pad u32x2 (8) => 128\n const computeUniformBuffer = createUniformBuffer(device, 128, { label: 'scatterDensity/computeUniforms' });\n const computeUniformScratch = new ArrayBuffer(128);\n const computeUniformF32 = new Float32Array(computeUniformScratch, 0, 20); // first 80 bytes (20 f32)\n const computeUniformU32 = new Uint32Array(computeUniformScratch);\n\n // Render uniforms: plotOriginPx(8)+plotSizePx(8)=16; u32*4 (16) + padding to 48.\n const renderUniformBuffer = createUniformBuffer(device, 48, { label: 'scatterDensity/renderUniforms' });\n const renderUniformScratch = new ArrayBuffer(48);\n const renderUniformU32 = new Uint32Array(renderUniformScratch);\n\n const binningModule = createShaderModule(device, scatterDensityBinningWgsl, 'scatterDensityBinning.wgsl');\n const binPointsPipeline = device.createComputePipeline({\n label: 'scatterDensity/binPointsPipeline',\n layout: device.createPipelineLayout({ bindGroupLayouts: [computeBindGroupLayout] }),\n compute: { module: binningModule, entryPoint: 'binPoints' },\n });\n const reduceMaxPipeline = device.createComputePipeline({\n label: 'scatterDensity/reduceMaxPipeline',\n layout: device.createPipelineLayout({ bindGroupLayouts: [computeBindGroupLayout] }),\n compute: { module: binningModule, entryPoint: 'reduceMax' },\n });\n\n const renderPipeline = createRenderPipeline(device, {\n label: 'scatterDensity/renderPipeline',\n bindGroupLayouts: [renderBindGroupLayout],\n vertex: { code: scatterDensityColormapWgsl, label: 'scatterDensityColormap.wgsl' },\n fragment: {\n code: scatterDensityColormapWgsl,\n label: 'scatterDensityColormap.wgsl',\n formats: targetFormat,\n blend: undefined,\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let binsBuffer: GPUBuffer | null = null;\n let maxBuffer: GPUBuffer | null = null;\n let binsCapacityU32 = 0;\n\n let lutTexture: GPUTexture | null = null;\n let lutView: GPUTextureView | null = null;\n let lastColormapKey = '';\n\n let computeBindGroup: GPUBindGroup | null = null;\n let renderBindGroup: GPUBindGroup | null = null;\n\n // Cached state to decide when to recompute.\n let lastPointBuffer: GPUBuffer | null = null;\n let lastPointCount = -1;\n let lastVisibleStart = 0;\n let lastVisibleEnd = 0;\n let lastBinSizePx = 0;\n let lastBinCountX = 0;\n let lastBinCountY = 0;\n let lastPlotScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n let lastCanvasWidth = 0;\n let lastCanvasHeight = 0;\n let lastNormalizationU32 = 2; // default 'log'\n\n let computeDirty = true;\n let hasPrepared = false;\n\n // Zero staging for fast clear (reallocated to match bins size).\n let zeroBinsStaging = new Uint32Array(0);\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('ScatterDensityRenderer is disposed.');\n };\n\n const ensureLut = (seriesConfig: ResolvedScatterSeriesConfig): void => {\n const key = colormapKey(seriesConfig.densityColormap);\n if (!lutTexture) {\n lutTexture = device.createTexture({\n label: 'scatterDensity/lutTexture',\n size: { width: 256, height: 1, depthOrArrayLayers: 1 },\n format: 'rgba8unorm',\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\n });\n lutView = lutTexture.createView();\n lastColormapKey = '';\n }\n if (key === lastColormapKey) return;\n\n const data = buildLutRGBA8(seriesConfig.densityColormap);\n device.queue.writeTexture(\n { texture: lutTexture! },\n data,\n { bytesPerRow: 256 * 4, rowsPerImage: 1 },\n { width: 256, height: 1, depthOrArrayLayers: 1 }\n );\n lastColormapKey = key;\n };\n\n const ensureBins = (binCountX: number, binCountY: number): void => {\n const n = Math.max(1, binCountX | 0) * Math.max(1, binCountY | 0);\n if (binsBuffer && maxBuffer && n <= binsCapacityU32) return;\n\n const requiredU32 = Math.max(1, n);\n const grownU32 = Math.max(256, nextPow2(requiredU32));\n binsCapacityU32 = grownU32;\n\n if (binsBuffer) {\n try {\n binsBuffer.destroy();\n } catch {\n // best-effort\n }\n binsBuffer = null;\n }\n if (maxBuffer) {\n try {\n maxBuffer.destroy();\n } catch {\n // best-effort\n }\n maxBuffer = null;\n }\n\n binsBuffer = device.createBuffer({\n label: 'scatterDensity/binsBuffer',\n size: binsCapacityU32 * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n maxBuffer = device.createBuffer({\n label: 'scatterDensity/maxBuffer',\n size: 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n\n // Refresh clear staging.\n zeroBinsStaging = new Uint32Array(binsCapacityU32);\n\n // Bind groups depend on buffers, so force re-create.\n computeBindGroup = null;\n renderBindGroup = null;\n computeDirty = true;\n };\n\n const ensureBindGroups = (): void => {\n if (!binsBuffer || !maxBuffer || !lutView || !lastPointBuffer) return;\n if (!computeBindGroup) {\n computeBindGroup = device.createBindGroup({\n label: 'scatterDensity/computeBindGroup',\n layout: computeBindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: computeUniformBuffer } },\n { binding: 1, resource: { buffer: lastPointBuffer } },\n { binding: 2, resource: { buffer: binsBuffer } },\n { binding: 3, resource: { buffer: maxBuffer } },\n ],\n });\n }\n if (!renderBindGroup) {\n renderBindGroup = device.createBindGroup({\n label: 'scatterDensity/renderBindGroup',\n layout: renderBindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: renderUniformBuffer } },\n { binding: 1, resource: { buffer: binsBuffer } },\n { binding: 2, resource: { buffer: maxBuffer } },\n { binding: 3, resource: lutView },\n ],\n });\n }\n };\n\n const prepare: ScatterDensityRenderer['prepare'] = (\n seriesConfig,\n pointBuffer,\n pointCount,\n visibleStartIndex,\n visibleEndIndex,\n xScale,\n yScale,\n gridArea,\n rawBounds\n ) => {\n assertNotDisposed();\n hasPrepared = true;\n\n const plotScissor = computePlotScissorDevicePx(gridArea);\n const dpr = gridArea.devicePixelRatio;\n const binSizeCss = Number.isFinite(seriesConfig.binSize) ? Math.max(1e-6, seriesConfig.binSize) : 2;\n const binSizePx = Math.max(1, Math.round(binSizeCss * (Number.isFinite(dpr) && dpr > 0 ? dpr : 1)));\n\n const binCountX = Math.max(1, Math.ceil(plotScissor.w / binSizePx));\n const binCountY = Math.max(1, Math.ceil(plotScissor.h / binSizePx));\n\n ensureBins(binCountX, binCountY);\n ensureLut(seriesConfig);\n\n const normU32 = normalizationToU32(seriesConfig.densityNormalization);\n\n // Dirty detection.\n if (lastPointBuffer !== pointBuffer) {\n lastPointBuffer = pointBuffer;\n computeBindGroup = null;\n renderBindGroup = null;\n computeDirty = true;\n }\n if (lastPointCount !== pointCount) {\n lastPointCount = pointCount;\n computeDirty = true;\n }\n if (lastVisibleStart !== visibleStartIndex || lastVisibleEnd !== visibleEndIndex) {\n lastVisibleStart = visibleStartIndex;\n lastVisibleEnd = visibleEndIndex;\n computeDirty = true;\n }\n if (lastBinSizePx !== binSizePx || lastBinCountX !== binCountX || lastBinCountY !== binCountY) {\n lastBinSizePx = binSizePx;\n lastBinCountX = binCountX;\n lastBinCountY = binCountY;\n computeDirty = true;\n }\n if (\n !lastPlotScissor ||\n lastPlotScissor.x !== plotScissor.x ||\n lastPlotScissor.y !== plotScissor.y ||\n lastPlotScissor.w !== plotScissor.w ||\n lastPlotScissor.h !== plotScissor.h\n ) {\n lastPlotScissor = plotScissor;\n computeDirty = true;\n }\n if (lastCanvasWidth !== gridArea.canvasWidth || lastCanvasHeight !== gridArea.canvasHeight) {\n lastCanvasWidth = gridArea.canvasWidth;\n lastCanvasHeight = gridArea.canvasHeight;\n computeDirty = true;\n }\n if (lastNormalizationU32 !== normU32) {\n lastNormalizationU32 = normU32;\n computeDirty = true;\n }\n\n // Write uniforms.\n const rb = rawBounds;\n const xMin = rb?.xMin ?? 0;\n const xMax = rb?.xMax ?? 1;\n const yMin = rb?.yMin ?? 0;\n const yMax = rb?.yMax ?? 1;\n\n const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n writeTransformMat4F32(computeUniformF32, ax, bx, ay, by);\n computeUniformF32[16] = gridArea.canvasWidth > 0 ? gridArea.canvasWidth : 1;\n computeUniformF32[17] = gridArea.canvasHeight > 0 ? gridArea.canvasHeight : 1;\n computeUniformF32[18] = 0;\n computeUniformF32[19] = 0;\n\n computeUniformU32[20] = plotScissor.x >>> 0;\n computeUniformU32[21] = plotScissor.y >>> 0;\n computeUniformU32[22] = plotScissor.w >>> 0;\n computeUniformU32[23] = plotScissor.h >>> 0;\n computeUniformU32[24] = binSizePx >>> 0;\n computeUniformU32[25] = binCountX >>> 0;\n computeUniformU32[26] = binCountY >>> 0;\n computeUniformU32[27] = (Math.max(0, visibleStartIndex) | 0) >>> 0;\n computeUniformU32[28] = (Math.max(0, visibleEndIndex) | 0) >>> 0;\n computeUniformU32[29] = normU32 >>> 0;\n\n writeUniformBuffer(device, computeUniformBuffer, computeUniformScratch);\n\n renderUniformU32[0] = plotScissor.x >>> 0;\n renderUniformU32[1] = plotScissor.y >>> 0;\n renderUniformU32[2] = plotScissor.w >>> 0;\n renderUniformU32[3] = plotScissor.h >>> 0;\n renderUniformU32[4] = binSizePx >>> 0;\n renderUniformU32[5] = binCountX >>> 0;\n renderUniformU32[6] = binCountY >>> 0;\n renderUniformU32[7] = normU32 >>> 0;\n writeUniformBuffer(device, renderUniformBuffer, renderUniformScratch);\n\n ensureBindGroups();\n };\n\n const encodeCompute: ScatterDensityRenderer['encodeCompute'] = (encoder) => {\n assertNotDisposed();\n if (!hasPrepared) return;\n if (!computeDirty) return;\n if (!binsBuffer || !maxBuffer || !computeBindGroup || lastPointCount <= 0) {\n computeDirty = false;\n return;\n }\n if (!lastPlotScissor || lastPlotScissor.w <= 0 || lastPlotScissor.h <= 0) {\n computeDirty = false;\n return;\n }\n\n // Clear bins + max.\n device.queue.writeBuffer(binsBuffer, 0, zeroBinsStaging.buffer, 0, binsCapacityU32 * 4);\n device.queue.writeBuffer(maxBuffer, 0, new Uint32Array([0]).buffer);\n\n const binTotal = (lastBinCountX * lastBinCountY) | 0;\n const visibleCount = Math.max(0, (lastVisibleEnd - lastVisibleStart) | 0);\n\n const pass = encoder.beginComputePass({ label: 'scatterDensity/computePass' });\n pass.setBindGroup(0, computeBindGroup);\n\n pass.setPipeline(binPointsPipeline);\n const wg = 256;\n const groupsPoints = Math.ceil(visibleCount / wg);\n if (groupsPoints > 0) pass.dispatchWorkgroups(groupsPoints);\n\n pass.setPipeline(reduceMaxPipeline);\n const groupsBins = Math.ceil(binTotal / wg);\n if (groupsBins > 0) pass.dispatchWorkgroups(groupsBins);\n\n pass.end();\n computeDirty = false;\n };\n\n const render: ScatterDensityRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!hasPrepared) return;\n if (!renderBindGroup || !lastPlotScissor || !lutView) return;\n if (lastPlotScissor.w <= 0 || lastPlotScissor.h <= 0) return;\n\n passEncoder.setScissorRect(lastPlotScissor.x, lastPlotScissor.y, lastPlotScissor.w, lastPlotScissor.h);\n passEncoder.setPipeline(renderPipeline);\n passEncoder.setBindGroup(0, renderBindGroup);\n passEncoder.draw(3);\n\n if (lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n }\n };\n\n const dispose: ScatterDensityRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n computeUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n renderUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n\n if (binsBuffer) {\n try {\n binsBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n if (maxBuffer) {\n try {\n maxBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n binsBuffer = null;\n maxBuffer = null;\n binsCapacityU32 = 0;\n\n if (lutTexture) {\n try {\n lutTexture.destroy();\n } catch {\n // best-effort\n }\n }\n lutTexture = null;\n lutView = null;\n\n computeBindGroup = null;\n renderBindGroup = null;\n lastPointBuffer = null;\n };\n\n return { prepare, encodeCompute, render, dispose };\n}\n\n","export default \"// pie.wgsl\\n// Instanced anti-aliased pie-slice shader (instanced quad + SDF mask).\\n//\\n// - Per-instance vertex input:\\n// - center = vec2<f32> slice center (transformed by VSUniforms.transform)\\n// - startAngleRad = f32 start angle in radians\\n// - endAngleRad = f32 end angle in radians\\n// - radiiPx = vec2<f32>(innerRadiusPx, outerRadiusPx) in *device pixels*\\n// - color = vec4<f32> RGBA color in [0..1]\\n//\\n// - Draw call: draw(6, instanceCount) using triangle-list expansion in VS\\n//\\n// - Uniforms:\\n// - @group(0) @binding(0): VSUniforms { transform, viewportPx }\\n//\\n// Notes:\\n// - The quad is expanded in clip space using `radiusPx` and `viewportPx`.\\n// - Fragment uses an SDF mask for the circle boundary + an angular wedge mask.\\n// - Fully outside fragments are discarded to avoid unnecessary blending work.\\n//\\n// Conventions: matches other shaders in this repo (vsMain/fsMain, group 0 bindings,\\n// and explicit uniform padding/alignment where needed).\\n\\nconst PI: f32 = 3.141592653589793;\\nconst TAU: f32 = 6.283185307179586; // 2*pi\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n viewportPx: vec2<f32>,\\n // Pad to 16-byte alignment (mat4x4 is 64B; vec2 adds 8B; pad to 80B).\\n _pad0: vec2<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n @location(0) center: vec2<f32>,\\n @location(1) startAngleRad: f32,\\n @location(2) endAngleRad: f32,\\n @location(3) radiiPx: vec2<f32>, // (innerPx, outerPx)\\n @location(4) color: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n @location(0) localPx: vec2<f32>,\\n @location(1) startAngleRad: f32,\\n @location(2) endAngleRad: f32,\\n @location(3) radiiPx: vec2<f32>,\\n @location(4) color: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n // Fixed local corners for 2 triangles (triangle-list).\\n // `localNdc` is a quad in [-1, 1]^2; we convert it to pixel offsets via radiusPx.\\n let localNdc = array<vec2<f32>, 6>(\\n vec2<f32>(-1.0, -1.0),\\n vec2<f32>( 1.0, -1.0),\\n vec2<f32>(-1.0, 1.0),\\n vec2<f32>(-1.0, 1.0),\\n vec2<f32>( 1.0, -1.0),\\n vec2<f32>( 1.0, 1.0)\\n );\\n\\n let corner = localNdc[vertexIndex];\\n let outerPx = in.radiiPx.y;\\n let localPx = corner * outerPx;\\n\\n // Convert pixel offset to clip-space offset.\\n // Clip space spans [-1, 1] across the viewport, so px -> clip is (2 / viewportPx).\\n let localClip = localPx * (2.0 / vsUniforms.viewportPx);\\n\\n let centerClip = (vsUniforms.transform * vec4<f32>(in.center, 0.0, 1.0)).xy;\\n\\n var out: VSOut;\\n out.clipPosition = vec4<f32>(centerClip + localClip, 0.0, 1.0);\\n out.localPx = localPx;\\n out.startAngleRad = in.startAngleRad;\\n out.endAngleRad = in.endAngleRad;\\n out.radiiPx = in.radiiPx;\\n out.color = in.color;\\n return out;\\n}\\n\\nfn wrapToTau(theta: f32) -> f32 {\\n // Maps theta to [0, TAU). (Input often comes from atan2 in [-PI, PI].)\\n return select(theta, theta + TAU, theta < 0.0);\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n let p = in.localPx;\\n let r = length(p);\\n\\n let innerPx = in.radiiPx.x;\\n let outerPx = in.radiiPx.y;\\n\\n // --- Radial mask: ring between inner and outer radii (inner==0 => pie) ---\\n // Positive inside the ring, negative outside.\\n let radialDist = min(r - innerPx, outerPx - r);\\n let radialW = fwidth(radialDist);\\n let radialA = smoothstep(-radialW, radialW, radialDist);\\n\\n if (radialA <= 0.0) {\\n discard;\\n }\\n\\n // Compute fragment angle in [0, TAU).\\n let angle = wrapToTau(atan2(p.y, p.x));\\n\\n // --- Angular mask: wedge between start/end angles with wrap ---\\n let start = in.startAngleRad;\\n let end = in.endAngleRad;\\n\\n // Compute span in [0, 2π) with wrap.\\n var span = end - start;\\n span = span + select(0.0, TAU, span < 0.0);\\n\\n // Compute rel in [0, 2π) with wrap.\\n var rel = angle - start;\\n rel = rel + select(0.0, TAU, rel < 0.0);\\n\\n let inside = rel <= span;\\n\\n // Signed angular distance (in radians) to nearest boundary.\\n // - Inside: +min(rel, span-rel)\\n // - Outside: -min(rel-span, 2π-rel)\\n let dIn = min(rel, max(span - rel, 0.0));\\n let dOutA = max(rel - span, 0.0);\\n let dOutB = max(TAU - rel, 0.0);\\n let dOut = min(dOutA, dOutB);\\n\\n let signedAngleDist = select(-dOut, dIn, inside);\\n\\n // Convert to approximate pixel distance to the boundary ray.\\n // (For small angles, perpendicular distance to a ray ≈ r * angle.)\\n let angleDistPx = signedAngleDist * max(r, 1.0);\\n\\n let angW = fwidth(angleDistPx);\\n let angularA = smoothstep(-angW, angW, angleDistPx);\\n\\n let aOut = radialA * angularA;\\n if (aOut <= 0.0) {\\n discard;\\n }\\n\\n return vec4<f32>(in.color.rgb, in.color.a * aOut);\\n}\\n\\n\"","import pieWgsl from '../shaders/pie.wgsl?raw';\nimport type { ResolvedPieSeriesConfig } from '../config/OptionResolver';\nimport type { PieCenter, PieRadius } from '../config/types';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { GridArea } from './createGridRenderer';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface PieRenderer {\n prepare(seriesConfig: ResolvedPieSeriesConfig, gridArea: GridArea): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface PieRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\n// Instance layout (must match `pie.wgsl` locations):\n// @location(0) center: vec2<f32>\n// @location(1) startAngleRad: f32\n// @location(2) endAngleRad: f32\n// @location(3) radiiPx: vec2<f32> (innerPx, outerPx) in device pixels\n// @location(4) color: vec4<f32>\nconst INSTANCE_STRIDE_BYTES = 40;\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst TAU = Math.PI * 2;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst nextPow2 = (v: number): number => {\n if (!Number.isFinite(v) || v <= 0) return 1;\n const n = Math.ceil(v);\n return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst wrapToTau = (thetaRad: number): number => {\n if (!Number.isFinite(thetaRad)) return 0;\n const t = thetaRad % TAU;\n return t < 0 ? t + TAU : t;\n};\n\nconst parseColor = (cssColor: string, fallbackCssColor: string): Rgba => {\n const parsed = parseCssColorToRgba01(cssColor);\n if (parsed) return [parsed[0], parsed[1], parsed[2], clamp01(parsed[3])] as const;\n\n const fb = parseCssColorToRgba01(fallbackCssColor);\n if (fb) return [fb[0], fb[1], fb[2], clamp01(fb[3])] as const;\n\n return [0, 0, 0, 1] as const;\n};\n\nconst parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (typeof value !== 'string') return null;\n\n const s = value.trim();\n if (s.length === 0) return null;\n\n if (s.endsWith('%')) {\n const pct = Number.parseFloat(s.slice(0, -1));\n if (!Number.isFinite(pct)) return null;\n return (pct / 100) * basis;\n }\n\n // Be permissive: allow numeric strings like \"120\" even though the public type primarily documents percent strings.\n const n = Number.parseFloat(s);\n return Number.isFinite(n) ? n : null;\n};\n\nconst resolveCenterPlotCss = (\n center: PieCenter | undefined,\n plotWidthCss: number,\n plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n const xRaw = center?.[0] ?? '50%';\n const yRaw = center?.[1] ?? '50%';\n\n const x = parseNumberOrPercent(xRaw, plotWidthCss);\n const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n return {\n x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n };\n};\n\nconst isRadiusTuple = (\n radius: PieRadius\n): radius is readonly [inner: number | string, outer: number | string] => Array.isArray(radius);\n\nconst resolveRadiiCss = (\n radius: PieRadius | undefined,\n maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n // Default similar to common chart libs.\n if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n if (isRadiusTuple(radius)) {\n const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n }\n\n const outer = parseNumberOrPercent(radius, maxRadiusCss);\n const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\nconst computePlotScissorDevicePx = (\n gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nconst IDENTITY_MAT4_F32 = new Float32Array([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n]);\n\nexport function createPieRenderer(device: GPUDevice, options?: PieRendererOptions): PieRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n });\n\n // VSUniforms in `pie.wgsl`: mat4x4 (64) + viewportPx vec2 (8) + pad vec2 (8) = 80 bytes.\n const vsUniformBuffer = createUniformBuffer(device, 80, { label: 'pieRenderer/vsUniforms' });\n\n // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n const vsUniformScratchBuffer = new ArrayBuffer(80);\n const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'pieRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: pieWgsl,\n label: 'pie.wgsl',\n buffers: [\n {\n arrayStride: INSTANCE_STRIDE_BYTES,\n stepMode: 'instance',\n attributes: [\n { shaderLocation: 0, format: 'float32x2', offset: 0 }, // center\n { shaderLocation: 1, format: 'float32', offset: 8 }, // startAngleRad\n { shaderLocation: 2, format: 'float32', offset: 12 }, // endAngleRad\n { shaderLocation: 3, format: 'float32x2', offset: 16 }, // radiiPx\n { shaderLocation: 4, format: 'float32x4', offset: 24 }, // color\n ],\n },\n ],\n },\n fragment: {\n code: pieWgsl,\n label: 'pie.wgsl',\n formats: targetFormat,\n // Standard alpha blending for AA edges and translucent slice colors.\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let instanceBuffer: GPUBuffer | null = null;\n let instanceCount = 0;\n let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n let lastCanvasWidth = 0;\n let lastCanvasHeight = 0;\n let lastScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('PieRenderer is disposed.');\n };\n\n const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n if (requiredFloats <= cpuInstanceStagingF32.length) return;\n const nextFloats = Math.max(8, nextPow2(requiredFloats));\n cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n };\n\n const writeVsUniforms = (viewportWDevicePx: number, viewportHDevicePx: number): void => {\n const w = Number.isFinite(viewportWDevicePx) && viewportWDevicePx > 0 ? viewportWDevicePx : 1;\n const h = Number.isFinite(viewportHDevicePx) && viewportHDevicePx > 0 ? viewportHDevicePx : 1;\n\n vsUniformScratchF32.set(IDENTITY_MAT4_F32, 0);\n vsUniformScratchF32[16] = w;\n vsUniformScratchF32[17] = h;\n vsUniformScratchF32[18] = 0;\n vsUniformScratchF32[19] = 0;\n writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n };\n\n const prepare: PieRenderer['prepare'] = (seriesConfig, gridArea) => {\n assertNotDisposed();\n\n const dprRaw = gridArea.devicePixelRatio;\n const dpr = dprRaw > 0 && Number.isFinite(dprRaw) ? dprRaw : 1;\n\n lastCanvasWidth = gridArea.canvasWidth;\n lastCanvasHeight = gridArea.canvasHeight;\n writeVsUniforms(gridArea.canvasWidth, gridArea.canvasHeight);\n lastScissor = computePlotScissorDevicePx(gridArea);\n\n const canvasCssWidth = gridArea.canvasWidth / dpr;\n const canvasCssHeight = gridArea.canvasHeight / dpr;\n if (!(canvasCssWidth > 0) || !(canvasCssHeight > 0)) {\n instanceCount = 0;\n return;\n }\n\n const plotWidthCss = canvasCssWidth - gridArea.left - gridArea.right;\n const plotHeightCss = canvasCssHeight - gridArea.top - gridArea.bottom;\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) {\n instanceCount = 0;\n return;\n }\n\n const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n if (!(maxRadiusCss > 0)) {\n instanceCount = 0;\n return;\n }\n\n // Center specified in plot-local CSS px (or %), then shifted by GridArea CSS margins.\n const centerPlotCss = resolveCenterPlotCss(seriesConfig.center, plotWidthCss, plotHeightCss);\n const centerCanvasCssX = gridArea.left + centerPlotCss.x;\n const centerCanvasCssY = gridArea.top + centerPlotCss.y;\n\n // Instance center is in clip space; VS transform is identity.\n const centerClipX = (centerCanvasCssX / canvasCssWidth) * 2 - 1;\n const centerClipY = 1 - (centerCanvasCssY / canvasCssHeight) * 2;\n if (!Number.isFinite(centerClipX) || !Number.isFinite(centerClipY)) {\n instanceCount = 0;\n return;\n }\n\n // Radii specified in CSS px (or % of max radius), converted to device px for the shader.\n const radiiCss = resolveRadiiCss(seriesConfig.radius, maxRadiusCss);\n const innerCss = Math.max(0, Math.min(radiiCss.inner, radiiCss.outer));\n const outerCss = Math.max(innerCss, radiiCss.outer);\n const innerPx = innerCss * dpr;\n const outerPx = outerCss * dpr;\n if (!(outerPx > 0)) {\n instanceCount = 0;\n return;\n }\n\n // Total positive value for angle allocation (exclude hidden slices).\n let total = 0;\n let validCount = 0;\n for (let i = 0; i < seriesConfig.data.length; i++) {\n const item = seriesConfig.data[i];\n const v = item?.value;\n if (typeof v === 'number' && Number.isFinite(v) && v > 0 && item.visible !== false) {\n total += v;\n validCount++;\n }\n }\n if (!(total > 0) || validCount === 0) {\n instanceCount = 0;\n return;\n }\n\n ensureCpuInstanceCapacityFloats(validCount * INSTANCE_STRIDE_FLOATS);\n const f32 = cpuInstanceStagingF32;\n\n // IMPORTANT: shader assumes start/end are already wrapped to [0, 2π) (it only adds TAU once).\n const startDeg =\n typeof seriesConfig.startAngle === 'number' && Number.isFinite(seriesConfig.startAngle) ? seriesConfig.startAngle : 90;\n let current = wrapToTau((startDeg * Math.PI) / 180);\n\n // Make the last slice close the circle (reduces float drift).\n let accumulated = 0;\n let outFloats = 0;\n let emitted = 0;\n\n for (let i = 0; i < seriesConfig.data.length; i++) {\n const item = seriesConfig.data[i];\n const v = item?.value;\n if (typeof v !== 'number' || !Number.isFinite(v) || v <= 0) continue;\n // Skip hidden slices\n if (item.visible === false) continue;\n\n emitted++;\n const isLast = emitted === validCount;\n\n const frac = v / total;\n let span = frac * TAU;\n if (isLast) {\n span = Math.max(0, TAU - accumulated);\n } else {\n // Keep accumulated stable and avoid pathological spans from weird inputs.\n span = Math.max(0, Math.min(TAU, span));\n }\n accumulated += span;\n if (!(span > 0)) continue;\n\n const startRad = current;\n // When there's only one visible slice, it should span the full circle (0 to TAU).\n // Don't wrap the end angle in this case, as wrapping (start + TAU) gives start again.\n const endRad = validCount === 1 ? current + TAU : wrapToTau(current + span);\n current = wrapToTau(current + span);\n\n const [r, g, b, a] = parseColor(item.color, seriesConfig.color);\n\n f32[outFloats + 0] = centerClipX;\n f32[outFloats + 1] = centerClipY;\n f32[outFloats + 2] = startRad;\n f32[outFloats + 3] = endRad;\n f32[outFloats + 4] = innerPx;\n f32[outFloats + 5] = outerPx;\n f32[outFloats + 6] = r;\n f32[outFloats + 7] = g;\n f32[outFloats + 8] = b;\n f32[outFloats + 9] = a;\n outFloats += INSTANCE_STRIDE_FLOATS;\n }\n\n instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = device.createBuffer({\n label: 'pieRenderer/instanceBuffer',\n size: grownBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n if (instanceBuffer && instanceCount > 0) {\n device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n }\n };\n\n const render: PieRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!instanceBuffer || instanceCount === 0) return;\n\n // Clip to plot area (scissor is in device pixels).\n if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n }\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, instanceBuffer);\n passEncoder.draw(6, instanceCount);\n\n // Reset scissor to full canvas to avoid impacting later renderers.\n if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n }\n };\n\n const dispose: PieRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = null;\n instanceCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n\n lastCanvasWidth = 0;\n lastCanvasHeight = 0;\n lastScissor = null;\n };\n\n return { prepare, render, dispose };\n}\n\n","export default \"// candlestick.wgsl\\n// Instanced candlestick shader (bodies + wicks):\\n// - Per-instance vertex input:\\n// - xClip, openClip, closeClip, lowClip, highClip, bodyWidthClip (6 floats)\\n// - bodyColor rgba (4 floats)\\n// - Draw call: draw(18, instanceCount) using triangle-list expansion in VS\\n// - vertices 0-5: body quad (2 triangles)\\n// - vertices 6-11: upper wick (2 triangles)\\n// - vertices 12-17: lower wick (2 triangles)\\n// - Uniforms:\\n// - @group(0) @binding(0): VSUniforms { transform, wickWidthClip }\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n wickWidthClip: f32,\\n _pad0: f32,\\n _pad1: f32,\\n _pad2: f32,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n @location(0) xClip: f32,\\n @location(1) openClip: f32,\\n @location(2) closeClip: f32,\\n @location(3) lowClip: f32,\\n @location(4) highClip: f32,\\n @location(5) bodyWidthClip: f32,\\n @location(6) bodyColor: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n @location(0) color: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n // Compute body bounds\\n let bodyTop = max(in.openClip, in.closeClip);\\n let bodyBottom = min(in.openClip, in.closeClip);\\n let bodyLeft = in.xClip - in.bodyWidthClip * 0.5;\\n let bodyRight = in.xClip + in.bodyWidthClip * 0.5;\\n\\n // Wick bounds\\n let wickLeft = in.xClip - vsUniforms.wickWidthClip * 0.5;\\n let wickRight = in.xClip + vsUniforms.wickWidthClip * 0.5;\\n\\n var pos: vec2<f32>;\\n\\n if (vertexIndex < 6u) {\\n // Body quad (vertices 0-5)\\n let corners = array<vec2<f32>, 6>(\\n vec2<f32>(0.0, 0.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(1.0, 1.0)\\n );\\n let corner = corners[vertexIndex];\\n let bodyMin = vec2<f32>(bodyLeft, bodyBottom);\\n let bodyMax = vec2<f32>(bodyRight, bodyTop);\\n pos = bodyMin + corner * (bodyMax - bodyMin);\\n } else if (vertexIndex < 12u) {\\n // Upper wick (vertices 6-11): from bodyTop to highClip\\n let idx = vertexIndex - 6u;\\n let corners = array<vec2<f32>, 6>(\\n vec2<f32>(0.0, 0.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(1.0, 1.0)\\n );\\n let corner = corners[idx];\\n let wickMin = vec2<f32>(wickLeft, bodyTop);\\n let wickMax = vec2<f32>(wickRight, in.highClip);\\n pos = wickMin + corner * (wickMax - wickMin);\\n } else {\\n // Lower wick (vertices 12-17): from lowClip to bodyBottom\\n let idx = vertexIndex - 12u;\\n let corners = array<vec2<f32>, 6>(\\n vec2<f32>(0.0, 0.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(0.0, 1.0),\\n vec2<f32>(1.0, 0.0),\\n vec2<f32>(1.0, 1.0)\\n );\\n let corner = corners[idx];\\n let wickMin = vec2<f32>(wickLeft, in.lowClip);\\n let wickMax = vec2<f32>(wickRight, bodyBottom);\\n pos = wickMin + corner * (wickMax - wickMin);\\n }\\n\\n var out: VSOut;\\n out.clipPosition = vsUniforms.transform * vec4<f32>(pos, 0.0, 1.0);\\n out.color = in.bodyColor;\\n return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n return in.color;\\n}\\n\"","import candlestickWgsl from '../shaders/candlestick.wgsl?raw';\nimport type { ResolvedCandlestickSeriesConfig } from '../config/OptionResolver';\nimport type { OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport type { GridArea } from './createGridRenderer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface CandlestickRenderer {\n prepare(\n series: ResolvedCandlestickSeriesConfig,\n data: ResolvedCandlestickSeriesConfig['data'],\n xScale: LinearScale,\n yScale: LinearScale,\n gridArea: GridArea,\n backgroundColor?: string\n ): void;\n render(passEncoder: GPURenderPassEncoder): void;\n dispose(): void;\n}\n\nexport interface CandlestickRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_WICK_WIDTH_CSS_PX = 1;\nconst INSTANCE_STRIDE_BYTES = 40; // 6 floats + vec4 color\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst nextPow2 = (v: number): number => {\n if (!Number.isFinite(v) || v <= 0) return 1;\n const n = Math.ceil(v);\n return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst parsePercent = (value: string): number | null => {\n const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n if (!m) return null;\n const p = Number(m[1]) / 100;\n return Number.isFinite(p) ? p : null;\n};\n\nconst isTupleDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getOHLC = (\n p: OHLCDataPoint\n): { readonly timestamp: number; readonly open: number; readonly close: number; readonly low: number; readonly high: number } => {\n if (isTupleDataPoint(p)) {\n return { timestamp: p[0], open: p[1], close: p[2], low: p[3], high: p[4] };\n }\n return { timestamp: p.timestamp, open: p.open, close: p.close, low: p.low, high: p.high };\n};\n\nconst computePlotSizeCssPx = (gridArea: GridArea): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n const dpr = gridArea.devicePixelRatio;\n if (!(dpr > 0)) return null;\n const canvasCssWidth = gridArea.canvasWidth / dpr;\n const canvasCssHeight = gridArea.canvasHeight / dpr;\n const plotWidthCss = canvasCssWidth - gridArea.left - gridArea.right;\n const plotHeightCss = canvasCssHeight - gridArea.top - gridArea.bottom;\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return null;\n return { plotWidthCss, plotHeightCss };\n};\n\nconst computePlotClipRect = (\n gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number; readonly width: number; readonly height: number } => {\n const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeft = left * devicePixelRatio;\n const plotRight = canvasWidth - right * devicePixelRatio;\n const plotTop = top * devicePixelRatio;\n const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n return {\n left: plotLeftClip,\n right: plotRightClip,\n top: plotTopClip,\n bottom: plotBottomClip,\n width: plotRightClip - plotLeftClip,\n height: plotTopClip - plotBottomClip,\n };\n};\n\nconst computePlotScissorDevicePx = (\n gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nconst computeCategoryStep = (data: ReadonlyArray<OHLCDataPoint>): number => {\n const timestamps: number[] = [];\n for (let i = 0; i < data.length; i++) {\n const { timestamp } = getOHLC(data[i]);\n if (Number.isFinite(timestamp)) timestamps.push(timestamp);\n }\n\n if (timestamps.length < 2) return 1;\n timestamps.sort((a, b) => a - b);\n\n let minStep = Number.POSITIVE_INFINITY;\n for (let i = 1; i < timestamps.length; i++) {\n const d = timestamps[i] - timestamps[i - 1];\n if (d > 0 && d < minStep) minStep = d;\n }\n return Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n};\n\nconst computeCategoryWidthClip = (\n xScale: LinearScale,\n categoryStep: number,\n plotClipRect: Readonly<{ width: number }>,\n fallbackCategoryCount: number\n): number => {\n if (Number.isFinite(categoryStep) && categoryStep > 0) {\n const x0 = 0;\n const p0 = xScale.scale(x0);\n const p1 = xScale.scale(x0 + categoryStep);\n const w = Math.abs(p1 - p0);\n if (Number.isFinite(w) && w > 0) return w;\n }\n\n const clipWidth = Math.abs(plotClipRect.width);\n if (!(clipWidth > 0)) return 0;\n const n = Math.max(1, Math.floor(fallbackCategoryCount));\n return clipWidth / n;\n};\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n // Column-major identity mat4x4\n const buffer = new ArrayBuffer(16 * 4);\n new Float32Array(buffer).set([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n ]);\n return buffer;\n};\n\nexport function createCandlestickRenderer(device: GPUDevice, options?: CandlestickRendererOptions): CandlestickRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n });\n\n // VSUniforms: mat4x4 (64 bytes) + wickWidthClip f32 (4 bytes) + pad (12 bytes) = 80 bytes\n const vsUniformBuffer = createUniformBuffer(device, 80, { label: 'candlestickRenderer/vsUniforms' });\n writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer()); // Default to identity\n\n const vsUniformScratchBuffer = new ArrayBuffer(80);\n const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'candlestickRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: candlestickWgsl,\n label: 'candlestick.wgsl',\n buffers: [\n {\n arrayStride: INSTANCE_STRIDE_BYTES,\n stepMode: 'instance',\n attributes: [\n { shaderLocation: 0, format: 'float32', offset: 0 },\n { shaderLocation: 1, format: 'float32', offset: 4 },\n { shaderLocation: 2, format: 'float32', offset: 8 },\n { shaderLocation: 3, format: 'float32', offset: 12 },\n { shaderLocation: 4, format: 'float32', offset: 16 },\n { shaderLocation: 5, format: 'float32', offset: 20 },\n { shaderLocation: 6, format: 'float32x4', offset: 24 },\n ],\n },\n ],\n },\n fragment: {\n code: candlestickWgsl,\n label: 'candlestick.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let instanceBuffer: GPUBuffer | null = null;\n let instanceCount = 0;\n let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n let lastCanvasWidth = 0;\n let lastCanvasHeight = 0;\n let lastScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n\n // Hollow mode state\n let hollowMode = false;\n let hollowInstanceBuffer: GPUBuffer | null = null;\n let hollowInstanceCount = 0;\n let cpuHollowStagingBuffer = new ArrayBuffer(0);\n let cpuHollowStagingF32 = new Float32Array(cpuHollowStagingBuffer);\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('CandlestickRenderer is disposed.');\n };\n\n const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n if (requiredFloats <= cpuInstanceStagingF32.length) return;\n const nextFloats = Math.max(8, nextPow2(requiredFloats));\n cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n };\n\n const ensureCpuHollowCapacityFloats = (requiredFloats: number): void => {\n if (requiredFloats <= cpuHollowStagingF32.length) return;\n const nextFloats = Math.max(8, nextPow2(requiredFloats));\n cpuHollowStagingBuffer = new ArrayBuffer(nextFloats * 4);\n cpuHollowStagingF32 = new Float32Array(cpuHollowStagingBuffer);\n };\n\n const prepare: CandlestickRenderer['prepare'] = (series, data, xScale, yScale, gridArea, backgroundColor) => {\n assertNotDisposed();\n\n if (data.length === 0) {\n instanceCount = 0;\n hollowInstanceCount = 0;\n return;\n }\n\n const plotSize = computePlotSizeCssPx(gridArea);\n if (!plotSize) {\n instanceCount = 0;\n hollowInstanceCount = 0;\n return;\n }\n\n const plotClipRect = computePlotClipRect(gridArea);\n const clipPerCssX = plotSize.plotWidthCss > 0 ? plotClipRect.width / plotSize.plotWidthCss : 0;\n\n lastCanvasWidth = gridArea.canvasWidth;\n lastCanvasHeight = gridArea.canvasHeight;\n lastScissor = computePlotScissorDevicePx(gridArea);\n\n // Compute category step and width\n const categoryStep = computeCategoryStep(data);\n const categoryWidthClip = computeCategoryWidthClip(xScale, categoryStep, plotClipRect, data.length);\n\n // Compute body width in clip space\n let bodyWidthClip = 0;\n const rawBarWidth = series.barWidth;\n if (typeof rawBarWidth === 'number') {\n bodyWidthClip = Math.max(0, rawBarWidth) * clipPerCssX;\n } else if (typeof rawBarWidth === 'string') {\n const p = parsePercent(rawBarWidth);\n bodyWidthClip = p == null ? 0 : categoryWidthClip * clamp01(p);\n }\n\n // Apply min/max width constraints (CSS pixels converted to clip space)\n const minWidthClip = series.barMinWidth * clipPerCssX;\n const maxWidthClip = series.barMaxWidth * clipPerCssX;\n bodyWidthClip = Math.min(Math.max(bodyWidthClip, minWidthClip), maxWidthClip);\n\n // Compute wick width in clip space (default 1px CSS)\n const wickWidthCssPx = series.itemStyle.borderWidth ?? DEFAULT_WICK_WIDTH_CSS_PX;\n const wickWidthClip = Math.max(0, wickWidthCssPx) * clipPerCssX;\n\n // Write VS uniforms (identity transform + wick width)\n vsUniformScratchF32.set([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n wickWidthClip,\n 0,\n 0,\n 0,\n ]);\n writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n\n // Parse colors\n const upColor = parseSeriesColorToRgba01(series.itemStyle.upColor);\n const downColor = parseSeriesColorToRgba01(series.itemStyle.downColor);\n const upBorderColor = parseSeriesColorToRgba01(series.itemStyle.upBorderColor);\n const downBorderColor = parseSeriesColorToRgba01(series.itemStyle.downBorderColor);\n const bgColor = backgroundColor ? parseSeriesColorToRgba01(backgroundColor) : ([0, 0, 0, 1] as const);\n\n hollowMode = series.style === 'hollow';\n\n ensureCpuInstanceCapacityFloats(data.length * INSTANCE_STRIDE_FLOATS);\n const f32 = cpuInstanceStagingF32;\n let outFloats = 0;\n\n if (hollowMode) {\n ensureCpuHollowCapacityFloats(data.length * INSTANCE_STRIDE_FLOATS);\n }\n const hollowF32 = cpuHollowStagingF32;\n let hollowOutFloats = 0;\n\n for (let i = 0; i < data.length; i++) {\n const { timestamp, open, close, low, high } = getOHLC(data[i]);\n if (!Number.isFinite(timestamp) || !Number.isFinite(open) || !Number.isFinite(close) || !Number.isFinite(low) || !Number.isFinite(high)) {\n continue;\n }\n\n const xClip = xScale.scale(timestamp);\n const openClip = yScale.scale(open);\n const closeClip = yScale.scale(close);\n const lowClip = yScale.scale(low);\n const highClip = yScale.scale(high);\n\n if (!Number.isFinite(xClip) || !Number.isFinite(openClip) || !Number.isFinite(closeClip) || !Number.isFinite(lowClip) || !Number.isFinite(highClip)) {\n continue;\n }\n\n const isUp = close > open;\n\n if (hollowMode) {\n // Pass 1: Draw all candles with border colors (body + wicks)\n const borderColor = isUp ? upBorderColor : downBorderColor;\n f32[outFloats + 0] = xClip;\n f32[outFloats + 1] = openClip;\n f32[outFloats + 2] = closeClip;\n f32[outFloats + 3] = lowClip;\n f32[outFloats + 4] = highClip;\n f32[outFloats + 5] = bodyWidthClip;\n f32[outFloats + 6] = borderColor[0];\n f32[outFloats + 7] = borderColor[1];\n f32[outFloats + 8] = borderColor[2];\n f32[outFloats + 9] = borderColor[3];\n outFloats += INSTANCE_STRIDE_FLOATS;\n\n // Pass 2: For UP candles only, draw body inset with background color to punch out interior\n if (isUp) {\n const borderWidthClip = series.itemStyle.borderWidth * clipPerCssX;\n const insetBodyWidthClip = Math.max(0, bodyWidthClip - 2 * borderWidthClip);\n\n hollowF32[hollowOutFloats + 0] = xClip;\n hollowF32[hollowOutFloats + 1] = openClip;\n hollowF32[hollowOutFloats + 2] = closeClip;\n hollowF32[hollowOutFloats + 3] = lowClip; // Not used for body-only draw, but keep for consistency\n hollowF32[hollowOutFloats + 4] = highClip; // Not used for body-only draw\n hollowF32[hollowOutFloats + 5] = insetBodyWidthClip;\n hollowF32[hollowOutFloats + 6] = bgColor[0];\n hollowF32[hollowOutFloats + 7] = bgColor[1];\n hollowF32[hollowOutFloats + 8] = bgColor[2];\n hollowF32[hollowOutFloats + 9] = bgColor[3];\n hollowOutFloats += INSTANCE_STRIDE_FLOATS;\n }\n } else {\n // Classic mode: draw candles with fill colors\n const fillColor = isUp ? upColor : downColor;\n f32[outFloats + 0] = xClip;\n f32[outFloats + 1] = openClip;\n f32[outFloats + 2] = closeClip;\n f32[outFloats + 3] = lowClip;\n f32[outFloats + 4] = highClip;\n f32[outFloats + 5] = bodyWidthClip;\n f32[outFloats + 6] = fillColor[0];\n f32[outFloats + 7] = fillColor[1];\n f32[outFloats + 8] = fillColor[2];\n f32[outFloats + 9] = fillColor[3];\n outFloats += INSTANCE_STRIDE_FLOATS;\n }\n }\n\n instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n hollowInstanceCount = hollowOutFloats / INSTANCE_STRIDE_FLOATS;\n\n // Upload primary instance buffer\n const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = device.createBuffer({\n label: 'candlestickRenderer/instanceBuffer',\n size: grownBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n if (instanceCount > 0) {\n device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n }\n\n // Upload hollow mode buffer (second pass)\n if (hollowMode && hollowInstanceCount > 0) {\n const hollowRequiredBytes = Math.max(4, hollowInstanceCount * INSTANCE_STRIDE_BYTES);\n if (!hollowInstanceBuffer || hollowInstanceBuffer.size < hollowRequiredBytes) {\n const grownBytes = Math.max(Math.max(4, nextPow2(hollowRequiredBytes)), hollowInstanceBuffer ? hollowInstanceBuffer.size : 0);\n if (hollowInstanceBuffer) {\n try {\n hollowInstanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n hollowInstanceBuffer = device.createBuffer({\n label: 'candlestickRenderer/hollowInstanceBuffer',\n size: grownBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n device.queue.writeBuffer(hollowInstanceBuffer, 0, cpuHollowStagingBuffer, 0, hollowInstanceCount * INSTANCE_STRIDE_BYTES);\n }\n };\n\n const render: CandlestickRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n\n if (!instanceBuffer || instanceCount === 0) return;\n\n // Apply scissor rect to clip to plot area\n if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n }\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n\n // Pass 1: Draw all candles (18 vertices per instance)\n passEncoder.setVertexBuffer(0, instanceBuffer);\n passEncoder.draw(18, instanceCount);\n\n // Pass 2: For hollow mode, draw body-only punch-out for UP candles\n if (hollowMode && hollowInstanceBuffer && hollowInstanceCount > 0) {\n passEncoder.setVertexBuffer(0, hollowInstanceBuffer);\n // Draw only body vertices (0-5) by drawing 6 vertices per instance\n passEncoder.draw(6, hollowInstanceCount);\n }\n\n // Reset scissor to full canvas\n if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n }\n };\n\n const dispose: CandlestickRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = null;\n instanceCount = 0;\n\n if (hollowInstanceBuffer) {\n try {\n hollowInstanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n hollowInstanceBuffer = null;\n hollowInstanceCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n\n lastCanvasWidth = 0;\n lastCanvasHeight = 0;\n lastScissor = null;\n };\n\n return { prepare, render, dispose };\n}\n","export default \"// crosshair.wgsl\\n// Minimal crosshair line shader:\\n// - Vertex input: vec2<f32> position in clip-space coordinates\\n// - VS uniform: transform mat4 (identity)\\n// - FS uniform: solid RGBA color\\n\\nstruct VSUniforms {\\n transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn) -> VSOut {\\n var out: VSOut;\\n out.clipPosition = vsUniforms.transform * vec4<f32>(in.position, 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n return fsUniforms.color;\\n}\\n\\n\"","export interface StreamBuffer {\n /**\n * Writes a new vertex payload into the streaming buffer.\n *\n * Notes:\n * - `data` is interpreted as interleaved `vec2<f32>` vertices: `[x0, y0, x1, y1, ...]`.\n * - Uses double buffering (alternates GPU buffers each write) to avoid writing into the same\n * buffer the GPU might still be reading from the prior frame.\n * - Uses a per-buffer CPU mirror (Uint32 bit patterns) to compute partial updates.\n */\n write(data: Float32Array): void;\n /** Returns the GPUBuffer that contains the most recently written data. */\n getBuffer(): GPUBuffer;\n /** Returns the vertex count for the most recently written data. */\n getVertexCount(): number;\n /** Destroys GPU resources (best-effort). Safe to call multiple times. */\n dispose(): void;\n}\n\nconst align4 = (n: number): number => (n + 3) & ~3;\n\n// Small payloads are cheaper to just full-write (avoid diff overhead).\nconst SMALL_FULL_WRITE_MAX_BYTES = 1024;\n\n// Heuristic guard against pathological alternating-word diffs which would produce many tiny ranges.\n// If exceeded, we do a single full-range write for the used bytes.\nconst MAX_DIFF_RANGES_BEFORE_FULL_WRITE = 128;\nconst MAX_CHANGED_WORDS_BEFORE_FULL_WRITE = 16_384;\n\nconst toU32View = (data: Float32Array): Uint32Array => {\n if ((data.byteOffset & 3) !== 0) {\n // This should never happen for Float32Array, but keep it explicit for correctness.\n throw new Error('createStreamBuffer.write: data.byteOffset must be 4-byte aligned.');\n }\n return new Uint32Array(data.buffer, data.byteOffset, data.byteLength >>> 2);\n};\n\nexport function createStreamBuffer(device: GPUDevice, maxSize: number): StreamBuffer {\n if (!Number.isFinite(maxSize) || maxSize <= 0) {\n throw new Error(`createStreamBuffer(maxSize): maxSize (bytes) must be a positive number. Received: ${String(maxSize)}`);\n }\n\n const clamped = Math.max(4, Math.floor(maxSize));\n const capacityBytes = align4(clamped);\n\n const limit = device.limits.maxBufferSize;\n if (capacityBytes > limit) {\n throw new Error(\n `createStreamBuffer(maxSize): requested size ${capacityBytes} bytes exceeds device.limits.maxBufferSize (${limit}).`\n );\n }\n\n const capacityWords = capacityBytes >>> 2;\n\n const createSlot = (label: string): { readonly buffer: GPUBuffer; readonly mirror: Uint32Array } => ({\n buffer: device.createBuffer({\n label,\n size: capacityBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n }),\n mirror: new Uint32Array(capacityWords),\n });\n\n const slots = [createSlot('streamBuffer/a'), createSlot('streamBuffer/b')] as const;\n\n let disposed = false;\n let currentIndex = 0; // getBuffer() returns slots[currentIndex]\n let vertexCount = 0;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('createStreamBuffer: StreamBuffer is disposed.');\n };\n\n const writeFull = (slotIndex: number, newWords: Uint32Array, usedWords: number): void => {\n const slot = slots[slotIndex];\n const mirror = slot.mirror;\n\n if (usedWords < 0 || usedWords > newWords.length) {\n throw new Error('createStreamBuffer.write: internal error (invalid usedWords).');\n }\n if (usedWords === 0) return;\n\n const usedBytes = usedWords << 2;\n device.queue.writeBuffer(slot.buffer, 0, newWords.buffer, newWords.byteOffset, usedBytes);\n mirror.set(newWords.subarray(0, usedWords), 0);\n };\n\n const writeRangesByDiff = (slotIndex: number, newWords: Uint32Array, usedWords: number): void => {\n const slot = slots[slotIndex];\n const mirror = slot.mirror;\n\n // Guard against programming errors.\n if (usedWords < 0 || usedWords > newWords.length) {\n throw new Error('createStreamBuffer.write: internal error (invalid usedWords).');\n }\n\n // Small-buffer fast path: diffing overhead dominates.\n const usedBytes = usedWords << 2;\n if (usedBytes > 0 && usedBytes <= SMALL_FULL_WRITE_MAX_BYTES) {\n writeFull(slotIndex, newWords, usedWords);\n return;\n }\n\n // First pass: collect ranges and decide whether we should fall back to a full write.\n const ranges: Array<[start: number, end: number]> = [];\n let rangeCount = 0;\n let changedWords = 0;\n\n let i = 0;\n while (i < usedWords) {\n // Find first differing word.\n while (i < usedWords && mirror[i] === newWords[i]) i++;\n if (i >= usedWords) break;\n\n const start = i;\n i++;\n // Extend to contiguous run of differing words.\n while (i < usedWords && mirror[i] !== newWords[i]) i++;\n const end = i;\n\n ranges.push([start, end]);\n rangeCount++;\n changedWords += end - start;\n\n // Pathological case guard: alternating changes can create many tiny ranges.\n if (rangeCount > MAX_DIFF_RANGES_BEFORE_FULL_WRITE || changedWords > MAX_CHANGED_WORDS_BEFORE_FULL_WRITE) {\n writeFull(slotIndex, newWords, usedWords);\n return;\n }\n }\n\n // Second pass: apply range writes.\n for (let r = 0; r < ranges.length; r++) {\n const [start, end] = ranges[r];\n const byteOffset = start << 2;\n const byteSize = (end - start) << 2;\n\n // WebGPU requires offsets/sizes to be multiples of 4 bytes (satisfied by word addressing).\n device.queue.writeBuffer(slot.buffer, byteOffset, newWords.buffer, newWords.byteOffset + byteOffset, byteSize);\n mirror.set(newWords.subarray(start, end), start);\n }\n };\n\n const write: StreamBuffer['write'] = (data) => {\n assertNotDisposed();\n\n if (data.length & 1) {\n throw new Error('createStreamBuffer.write: data length must be even (vec2<f32> vertices).');\n }\n\n const bytes = data.byteLength;\n if (bytes > capacityBytes) {\n throw new Error(\n `createStreamBuffer.write: data.byteLength (${bytes}) exceeds capacity (${capacityBytes}). Increase maxSize.`\n );\n }\n\n const nextVertexCount = data.length >>> 1;\n if (bytes === 0) {\n // Avoid swapping buffers for empty payloads.\n vertexCount = nextVertexCount;\n return;\n }\n\n const words = toU32View(data);\n const nextIndex = 1 - currentIndex;\n\n // Only swap after the write succeeds so we never expose a partially-updated \"current\" buffer.\n writeRangesByDiff(nextIndex, words, words.length);\n currentIndex = nextIndex;\n vertexCount = nextVertexCount;\n };\n\n const getBuffer: StreamBuffer['getBuffer'] = () => {\n assertNotDisposed();\n return slots[currentIndex].buffer;\n };\n\n const getVertexCount: StreamBuffer['getVertexCount'] = () => {\n assertNotDisposed();\n return vertexCount;\n };\n\n const dispose: StreamBuffer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n vertexCount = 0;\n\n for (const slot of slots) {\n try {\n slot.buffer.destroy();\n } catch {\n // best-effort\n }\n }\n };\n\n return { write, getBuffer, getVertexCount, dispose };\n}\n\n","import crosshairWgsl from '../shaders/crosshair.wgsl?raw';\nimport { createStreamBuffer } from '../data/createStreamBuffer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport type { GridArea } from './createGridRenderer';\n\nexport interface CrosshairRenderOptions {\n /** Whether to render the vertical crosshair line. */\n readonly showX: boolean;\n /** Whether to render the horizontal crosshair line. */\n readonly showY: boolean;\n /** CSS color string for the crosshair lines. */\n readonly color: string;\n /**\n * Desired line width in CSS pixels.\n *\n * Note: WebGPU wide lines are not reliably supported; the renderer emulates thickness by\n * drawing multiple 1px lines in device-pixel offsets (best-effort, deterministic).\n */\n readonly lineWidth: number;\n}\n\nexport interface CrosshairRenderer {\n /**\n * Positions the crosshair for rendering.\n *\n * Coordinate contract:\n * - `x`, `y` are CANVAS-LOCAL CSS pixels (e.g. eventManager payload x/y)\n * - `gridArea` margins are CSS pixels; `gridArea.canvasWidth/Height` are device pixels\n */\n prepare(x: number, y: number, gridArea: GridArea, options: CrosshairRenderOptions): void;\n /** Draws the crosshair (if visible) clipped to the plot rect. */\n render(passEncoder: GPURenderPassEncoder): void;\n /** Shows/hides the crosshair without destroying GPU resources. */\n setVisible(visible: boolean): void;\n /** Cleans up GPU resources (best-effort). */\n dispose(): void;\n}\n\nexport interface CrosshairRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_CROSSHAIR_RGBA: readonly [number, number, number, number] = [1, 1, 1, 0.8];\n\nconst MAX_THICKNESS_DEVICE_PX = 8;\nconst DASH_ON_DEVICE_PX = 6;\nconst DASH_OFF_DEVICE_PX = 4;\n\n// Hard cap to keep CPU-side dash segmentation inexpensive/deterministic.\nconst MAX_VERTICES = 8192; // vec2<f32> vertices, i.e. floats/2.\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n // Column-major identity mat4x4\n const buffer = new ArrayBuffer(16 * 4);\n new Float32Array(buffer).set([\n 1, 0, 0, 0, // col0\n 0, 1, 0, 0, // col1\n 0, 0, 1, 0, // col2\n 0, 0, 0, 1, // col3\n ]);\n return buffer;\n};\n\nconst isFiniteGridArea = (gridArea: GridArea): boolean =>\n Number.isFinite(gridArea.left) &&\n Number.isFinite(gridArea.right) &&\n Number.isFinite(gridArea.top) &&\n Number.isFinite(gridArea.bottom) &&\n Number.isFinite(gridArea.canvasWidth) &&\n Number.isFinite(gridArea.canvasHeight);\n\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst computeThicknessOffsetsDevicePx = (lineWidthCssPx: number, dpr: number): readonly number[] => {\n if (!Number.isFinite(lineWidthCssPx) || lineWidthCssPx < 0) {\n throw new Error('CrosshairRenderer.prepare: lineWidth must be a finite non-negative number.');\n }\n if (lineWidthCssPx === 0) return [];\n\n // Convert to device px, then clamp to a small deterministic maximum.\n const widthDevicePx = lineWidthCssPx * dpr;\n const thickness = Math.max(1, Math.min(MAX_THICKNESS_DEVICE_PX, Math.round(widthDevicePx)));\n\n // Symmetric offsets around center (even thickness yields ±0.5 style offsets).\n const mid = (thickness - 1) / 2;\n const out: number[] = [];\n for (let i = 0; i < thickness; i++) out.push(i - mid);\n return out;\n};\n\nconst devicePxToClipX = (xDevicePx: number, canvasWidthDevicePx: number): number =>\n (xDevicePx / canvasWidthDevicePx) * 2.0 - 1.0;\nconst devicePxToClipY = (yDevicePx: number, canvasHeightDevicePx: number): number =>\n 1.0 - (yDevicePx / canvasHeightDevicePx) * 2.0;\n\ntype Segment2D = readonly [x0: number, y0: number, x1: number, y1: number];\n\nconst appendSegmentVerticesClip = (out: number[], seg: Segment2D): void => {\n out.push(seg[0], seg[1], seg[2], seg[3]);\n};\n\nconst generateDashedSegmentsAxisAligned = (start: number, end: number): readonly [number, number][] => {\n // Returns a list of [a,b] segments in *device* space along a single axis.\n if (!Number.isFinite(start) || !Number.isFinite(end)) return [];\n\n const a0 = Math.min(start, end);\n const a1 = Math.max(start, end);\n if (a1 <= a0) return [];\n\n const on = DASH_ON_DEVICE_PX;\n const off = DASH_OFF_DEVICE_PX;\n const period = on + off;\n if (period <= 0 || !Number.isFinite(period)) return [];\n\n // Conservative cap: if this many segments would exceed MAX_VERTICES after thickness expansion,\n // the caller will fall back to a single solid segment.\n const approxSegments = Math.ceil((a1 - a0) / period);\n if (!Number.isFinite(approxSegments) || approxSegments <= 0) return [];\n\n const segments: Array<[number, number]> = [];\n let t = a0;\n while (t < a1) {\n const s0 = t;\n const s1 = Math.min(t + on, a1);\n if (s1 > s0) segments.push([s0, s1]);\n t += period;\n }\n return segments;\n};\n\nconst generateCrosshairVertices = (\n xCssPx: number,\n yCssPx: number,\n gridArea: GridArea,\n options: CrosshairRenderOptions\n): {\n readonly vertices: Float32Array;\n readonly scissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number };\n} => {\n if (!Number.isFinite(xCssPx) || !Number.isFinite(yCssPx)) {\n throw new Error('CrosshairRenderer.prepare: x and y must be finite numbers.');\n }\n if (!isFiniteGridArea(gridArea)) {\n throw new Error('CrosshairRenderer.prepare: gridArea dimensions must be finite numbers.');\n }\n if (gridArea.canvasWidth <= 0 || gridArea.canvasHeight <= 0) {\n throw new Error('CrosshairRenderer.prepare: canvas dimensions must be positive.');\n }\n if (gridArea.left < 0 || gridArea.right < 0 || gridArea.top < 0 || gridArea.bottom < 0) {\n throw new Error('CrosshairRenderer.prepare: gridArea margins must be non-negative.');\n }\n\n const { canvasWidth, canvasHeight } = gridArea;\n // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n const devicePixelRatio =\n Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n // Convert the requested position from CSS px (canvas-local) to device px.\n const xDevice = xCssPx * devicePixelRatio;\n const yDevice = yCssPx * devicePixelRatio;\n\n const thicknessOffsets = computeThicknessOffsetsDevicePx(options.lineWidth, devicePixelRatio);\n if (thicknessOffsets.length === 0 || (!options.showX && !options.showY)) {\n return {\n vertices: new Float32Array(0),\n scissor: { x: scissorX, y: scissorY, w: scissorW, h: scissorH },\n };\n }\n\n const floats: number[] = [];\n\n // Compute how many dashed segments we *might* generate and fall back to solid if too many.\n const dashSegmentsY = options.showX ? generateDashedSegmentsAxisAligned(plotTopDevice, plotBottomDevice) : [];\n const dashSegmentsX = options.showY ? generateDashedSegmentsAxisAligned(plotLeftDevice, plotRightDevice) : [];\n\n const segmentsPerThickness =\n (options.showX ? dashSegmentsY.length : 0) + (options.showY ? dashSegmentsX.length : 0);\n const projectedVertexCount = segmentsPerThickness * thicknessOffsets.length * 2; // 2 vertices per segment\n\n const useDashed = projectedVertexCount > 0 && projectedVertexCount <= MAX_VERTICES;\n\n const addVerticalSolid = (xDevicePx: number): void => {\n const xClip = devicePxToClipX(xDevicePx, canvasWidth);\n const y0 = devicePxToClipY(plotTopDevice, canvasHeight);\n const y1 = devicePxToClipY(plotBottomDevice, canvasHeight);\n appendSegmentVerticesClip(floats, [xClip, y0, xClip, y1]);\n };\n\n const addHorizontalSolid = (yDevicePx: number): void => {\n const yClip = devicePxToClipY(yDevicePx, canvasHeight);\n const x0 = devicePxToClipX(plotLeftDevice, canvasWidth);\n const x1 = devicePxToClipX(plotRightDevice, canvasWidth);\n appendSegmentVerticesClip(floats, [x0, yClip, x1, yClip]);\n };\n\n if (options.showX) {\n for (let i = 0; i < thicknessOffsets.length; i++) {\n const xd = xDevice + thicknessOffsets[i];\n if (!useDashed) {\n addVerticalSolid(xd);\n continue;\n }\n\n const xClip = devicePxToClipX(xd, canvasWidth);\n for (let s = 0; s < dashSegmentsY.length; s++) {\n const [ya, yb] = dashSegmentsY[s];\n const y0 = devicePxToClipY(ya, canvasHeight);\n const y1 = devicePxToClipY(yb, canvasHeight);\n appendSegmentVerticesClip(floats, [xClip, y0, xClip, y1]);\n }\n }\n }\n\n if (options.showY) {\n for (let i = 0; i < thicknessOffsets.length; i++) {\n const yd = yDevice + thicknessOffsets[i];\n if (!useDashed) {\n addHorizontalSolid(yd);\n continue;\n }\n\n const yClip = devicePxToClipY(yd, canvasHeight);\n for (let s = 0; s < dashSegmentsX.length; s++) {\n const [xa, xb] = dashSegmentsX[s];\n const x0 = devicePxToClipX(xa, canvasWidth);\n const x1 = devicePxToClipX(xb, canvasWidth);\n appendSegmentVerticesClip(floats, [x0, yClip, x1, yClip]);\n }\n }\n }\n\n const vertices = new Float32Array(floats);\n return { vertices, scissor: { x: scissorX, y: scissorY, w: scissorW, h: scissorH } };\n};\n\nexport function createCrosshairRenderer(device: GPUDevice, options?: CrosshairRendererOptions): CrosshairRenderer {\n let disposed = false;\n let visible = true;\n\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n ],\n });\n\n const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'crosshairRenderer/vsUniforms' });\n const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'crosshairRenderer/fsUniforms' });\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: vsUniformBuffer } },\n { binding: 1, resource: { buffer: fsUniformBuffer } },\n ],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'crosshairRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: crosshairWgsl,\n label: 'crosshair.wgsl',\n buffers: [\n {\n arrayStride: 8,\n stepMode: 'vertex',\n attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n },\n ],\n },\n fragment: {\n code: crosshairWgsl,\n label: 'crosshair.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'line-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n const stream = createStreamBuffer(device, MAX_VERTICES * 8);\n let vertexCount = 0;\n let lastCanvasWidth = 0;\n let lastCanvasHeight = 0;\n let lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('CrosshairRenderer is disposed.');\n };\n\n const prepare: CrosshairRenderer['prepare'] = (x, y, gridArea, renderOptions) => {\n assertNotDisposed();\n\n // Validate options up-front for deterministic behavior.\n if (typeof renderOptions.showX !== 'boolean' || typeof renderOptions.showY !== 'boolean') {\n throw new Error('CrosshairRenderer.prepare: showX/showY must be boolean.');\n }\n if (typeof renderOptions.color !== 'string') {\n throw new Error('CrosshairRenderer.prepare: color must be a string.');\n }\n if (!Number.isFinite(renderOptions.lineWidth) || renderOptions.lineWidth < 0) {\n throw new Error('CrosshairRenderer.prepare: lineWidth must be a finite non-negative number.');\n }\n\n const { vertices, scissor } = generateCrosshairVertices(x, y, gridArea, renderOptions);\n if (vertices.byteLength === 0) {\n vertexCount = 0;\n } else {\n stream.write(vertices);\n vertexCount = stream.getVertexCount();\n }\n\n // Identity transform (vertices are already in clip-space).\n writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer());\n\n // Color.\n const rgba = parseCssColorToRgba01(renderOptions.color) ?? DEFAULT_CROSSHAIR_RGBA;\n const colorBuffer = new ArrayBuffer(4 * 4);\n new Float32Array(colorBuffer).set([rgba[0], rgba[1], rgba[2], rgba[3]]);\n writeUniformBuffer(device, fsUniformBuffer, colorBuffer);\n\n lastCanvasWidth = gridArea.canvasWidth;\n lastCanvasHeight = gridArea.canvasHeight;\n lastScissor = scissor;\n };\n\n const render: CrosshairRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!visible) return;\n if (vertexCount === 0) return;\n if (lastCanvasWidth <= 0 || lastCanvasHeight <= 0) return;\n\n // Clip to plot area (device pixels).\n passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, stream.getBuffer());\n passEncoder.draw(vertexCount);\n\n // Reset scissor to full canvas (avoid affecting subsequent renderers).\n passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n };\n\n const setVisible: CrosshairRenderer['setVisible'] = (v) => {\n assertNotDisposed();\n visible = Boolean(v);\n };\n\n const dispose: CrosshairRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n try {\n fsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n stream.dispose();\n\n vertexCount = 0;\n lastCanvasWidth = 0;\n lastCanvasHeight = 0;\n lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n };\n\n return { prepare, render, setVisible, dispose };\n}\n\n","export default \"// highlight.wgsl\\n// Draws an anti-aliased ring highlight around a point.\\n//\\n// Contract:\\n// - `@builtin(position)` in the fragment stage is framebuffer-space pixels.\\n// - The renderer supplies `center` and ring sizes in *device pixels*.\\n\\nstruct Uniforms {\\n center: vec2<f32>,\\n radius: f32,\\n thickness: f32,\\n color: vec4<f32>,\\n outlineColor: vec4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> u: Uniforms;\\n\\nstruct VSOut {\\n @builtin(position) position: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(@builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n // Fullscreen triangle.\\n // Covers clip-space [-1,1] with 3 verts: (-1,-1), (3,-1), (-1,3)\\n let positions = array<vec2<f32>, 3>(\\n vec2<f32>(-1.0, -1.0),\\n vec2<f32>(3.0, -1.0),\\n vec2<f32>(-1.0, 3.0)\\n );\\n\\n var out: VSOut;\\n out.position = vec4<f32>(positions[vertexIndex], 0.0, 1.0);\\n return out;\\n}\\n\\nfn ringCoverage(distancePx: f32, radiusPx: f32, thicknessPx: f32) -> f32 {\\n let aa = 1.0; // ~1px antialias band (device pixels)\\n let halfT = max(0.5, thicknessPx * 0.5);\\n let a0 = smoothstep(radiusPx - halfT - aa, radiusPx - halfT + aa, distancePx);\\n let a1 = smoothstep(radiusPx + halfT - aa, radiusPx + halfT + aa, distancePx);\\n return clamp(a0 - a1, 0.0, 1.0);\\n}\\n\\n@fragment\\nfn fsMain(@builtin(position) fragPos: vec4<f32>) -> @location(0) vec4<f32> {\\n let d = distance(fragPos.xy, u.center);\\n\\n let ring = ringCoverage(d, u.radius, u.thickness);\\n let outline = ringCoverage(d, u.radius, u.thickness + 2.0);\\n\\n let cover = max(ring, outline);\\n if (cover <= 0.0) {\\n discard;\\n }\\n\\n // Blend between outline and ring color based on relative coverage,\\n // then apply total coverage as alpha.\\n let t = clamp(select(0.0, ring / cover, cover > 0.0), 0.0, 1.0);\\n let rgb = mix(u.outlineColor.rgb, u.color.rgb, t);\\n let a = mix(u.outlineColor.a, u.color.a, t) * cover;\\n return vec4<f32>(rgb, a);\\n}\\n\\n\"","import highlightWgsl from '../shaders/highlight.wgsl?raw';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport type HighlightPoint = Readonly<{\n /** Center in *device pixels* (same coordinate space as fragment `@builtin(position)`). */\n centerDeviceX: number;\n centerDeviceY: number;\n\n /** Device pixel ratio used for CSS→device conversion (worker-safe). */\n devicePixelRatio: number;\n\n /** Canvas dimensions in *device pixels* (used to reset scissor). */\n canvasWidth: number;\n canvasHeight: number;\n\n /** Plot scissor rect in *device pixels*. */\n scissor: Readonly<{ x: number; y: number; w: number; h: number }>;\n}>;\n\nexport interface HighlightRenderer {\n /**\n * Prepares the highlight ring.\n *\n * Coordinate contract:\n * - `point.centerDeviceX/Y` are device pixels in the same space as fragment `@builtin(position)`.\n * - `size` is specified in CSS pixels; the renderer will scale it by `point.devicePixelRatio`.\n */\n prepare(point: HighlightPoint, color: string, size: number): void;\n render(passEncoder: GPURenderPassEncoder): void;\n setVisible(visible: boolean): void;\n dispose(): void;\n}\n\nexport interface HighlightRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_RGBA: readonly [number, number, number, number] = [1, 1, 1, 1];\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst isFiniteScissor = (s: HighlightPoint['scissor']): boolean =>\n Number.isFinite(s.x) && Number.isFinite(s.y) && Number.isFinite(s.w) && Number.isFinite(s.h);\n\nconst brighten = (rgba: readonly [number, number, number, number], factor: number): readonly [number, number, number, number] => {\n const f = Number.isFinite(factor) ? factor : 1;\n return [clamp01(rgba[0] * f), clamp01(rgba[1] * f), clamp01(rgba[2] * f), clamp01(rgba[3])] as const;\n};\n\nconst luminance = (rgba: readonly [number, number, number, number]): number =>\n 0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2];\n\nexport function createHighlightRenderer(device: GPUDevice, options?: HighlightRendererOptions): HighlightRenderer {\n let disposed = false;\n let visible = true;\n\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } }],\n });\n\n // Uniform layout (WGSL):\n // center.xy, radius, thickness, color.rgba, outlineColor.rgba\n // = 12 floats = 48 bytes\n const uniformBuffer = createUniformBuffer(device, 48, { label: 'highlightRenderer/uniforms' });\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [{ binding: 0, resource: { buffer: uniformBuffer } }],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'highlightRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: { code: highlightWgsl, label: 'highlight.wgsl' },\n fragment: {\n code: highlightWgsl,\n label: 'highlight.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: 1 },\n });\n\n let lastCanvasWidth = 0;\n let lastCanvasHeight = 0;\n let lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n let hasPrepared = false;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('HighlightRenderer is disposed.');\n };\n\n const prepare: HighlightRenderer['prepare'] = (point, cssColor, sizeCssPx) => {\n assertNotDisposed();\n\n if (!Number.isFinite(point.centerDeviceX) || !Number.isFinite(point.centerDeviceY)) {\n throw new Error('HighlightRenderer.prepare: point center must be finite.');\n }\n if (!Number.isFinite(point.canvasWidth) || !Number.isFinite(point.canvasHeight) || point.canvasWidth <= 0 || point.canvasHeight <= 0) {\n throw new Error('HighlightRenderer.prepare: canvasWidth/canvasHeight must be positive finite numbers.');\n }\n if (!isFiniteScissor(point.scissor)) {\n throw new Error('HighlightRenderer.prepare: scissor must be finite.');\n }\n if (!Number.isFinite(sizeCssPx) || sizeCssPx < 0) {\n throw new Error('HighlightRenderer.prepare: size must be a finite non-negative number.');\n }\n\n const dprRaw = point.devicePixelRatio;\n const dpr = Number.isFinite(dprRaw) && dprRaw > 0 ? dprRaw : 1;\n const baseRadiusDevicePx = sizeCssPx * dpr;\n\n // Slightly larger than the implied \"normal\" point size.\n const radius = Math.max(1, baseRadiusDevicePx * 1.5);\n const thickness = Math.max(1, Math.round(Math.max(2, radius * 0.25)));\n\n const seriesRgba = parseCssColorToRgba01(cssColor) ?? DEFAULT_RGBA;\n const ringRgba = brighten(seriesRgba, 1.25);\n const useDarkOutline = luminance(seriesRgba) > 0.7;\n const outlineRgba: readonly [number, number, number, number] = useDarkOutline ? [0, 0, 0, 0.9] : [1, 1, 1, 0.9];\n\n const buf = new ArrayBuffer(12 * 4);\n new Float32Array(buf).set([\n point.centerDeviceX,\n point.centerDeviceY,\n radius,\n thickness,\n ringRgba[0],\n ringRgba[1],\n ringRgba[2],\n 1.0,\n outlineRgba[0],\n outlineRgba[1],\n outlineRgba[2],\n outlineRgba[3],\n ]);\n writeUniformBuffer(device, uniformBuffer, buf);\n\n lastCanvasWidth = point.canvasWidth;\n lastCanvasHeight = point.canvasHeight;\n\n // Clamp scissor to valid canvas bounds (defensive).\n const x0 = clampInt(Math.floor(point.scissor.x), 0, Math.max(0, point.canvasWidth));\n const y0 = clampInt(Math.floor(point.scissor.y), 0, Math.max(0, point.canvasHeight));\n const x1 = clampInt(Math.ceil(point.scissor.x + point.scissor.w), 0, Math.max(0, point.canvasWidth));\n const y1 = clampInt(Math.ceil(point.scissor.y + point.scissor.h), 0, Math.max(0, point.canvasHeight));\n lastScissor = { x: x0, y: y0, w: Math.max(0, x1 - x0), h: Math.max(0, y1 - y0) };\n\n hasPrepared = true;\n };\n\n const render: HighlightRenderer['render'] = (passEncoder) => {\n assertNotDisposed();\n if (!visible) return;\n if (!hasPrepared) return;\n if (lastCanvasWidth <= 0 || lastCanvasHeight <= 0) return;\n if (lastScissor.w === 0 || lastScissor.h === 0) return;\n\n passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.draw(3);\n passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n };\n\n const setVisible: HighlightRenderer['setVisible'] = (v) => {\n assertNotDisposed();\n visible = Boolean(v);\n };\n\n const dispose: HighlightRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n uniformBuffer.destroy();\n } catch {\n // best-effort\n }\n\n lastCanvasWidth = 0;\n lastCanvasHeight = 0;\n lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n hasPrepared = false;\n };\n\n return { prepare, render, setVisible, dispose };\n}\n\n","export default \"// Reference line renderer (axis-aligned, instanced quads).\\n//\\n// Coordinate conventions:\\n// - Instance position is provided in CANVAS-LOCAL CSS pixels (same coordinate space as pointer events).\\n// - Plot rect is provided in DEVICE pixels (computed from grid margins + DPR).\\n// - Line width and dash lengths are provided in CSS pixels and converted in-shader using DPR.\\n//\\n// Scissoring/clipping:\\n// - The render coordinator is expected to set a scissor rect for the plot area before drawing.\\n// - This shader simply draws full-height/full-width quads; clipping is handled by scissor.\\n//\\n// Dash semantics:\\n// - lineDash is a repeating on/off sequence in CSS pixels, starting with \\\"on\\\" at t=0.\\n// - Up to 8 dash entries are supported per line (truncated on CPU).\\n//\\n// Performance:\\n// - Vertex stage expands each instance into a quad (2 triangles, 6 vertices).\\n// - We intentionally avoid snapping to integer device pixels to prevent visible stepping/jiggle\\n// while zooming; edge AA is handled in the fragment stage.\\n\\nstruct VSUniforms {\\n canvasSize : vec2<f32>, // device pixels (canvas.width, canvas.height)\\n plotOrigin : vec2<f32>, // device pixels (plotLeft, plotTop)\\n plotSize : vec2<f32>, // device pixels (plotWidth, plotHeight)\\n devicePixelRatio : f32,\\n _pad0 : f32,\\n};\\n\\n@group(0) @binding(0) var<uniform> u : VSUniforms;\\n\\nstruct VSIn {\\n // axisPos.x = axis (0 = vertical, 1 = horizontal)\\n // axisPos.y = position in CANVAS-LOCAL CSS pixels (x for vertical, y for horizontal)\\n @location(0) axisPos : vec2<f32>,\\n\\n // widthDashCount.x = lineWidth in CSS px\\n // widthDashCount.y = dashCount (float, cast to u32)\\n @location(1) widthDashCount : vec2<f32>,\\n\\n // dashMeta.x = dashTotal (CSS px)\\n // dashMeta.y = reserved (unused)\\n @location(2) dashMeta : vec2<f32>,\\n\\n @location(3) dash0_3 : vec4<f32>,\\n @location(4) dash4_7 : vec4<f32>,\\n\\n // Premultiplied or straight alpha is fine; blending is handled by pipeline state.\\n @location(5) color : vec4<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) position : vec4<f32>,\\n\\n // Distance along the line in CSS pixels (0..plotLengthCss).\\n @location(0) alongCss : f32,\\n\\n // Packed dash metadata to avoid extra varyings.\\n // dashInfo.x = dashCount (float, cast to u32)\\n // dashInfo.y = dashTotal (CSS px)\\n @location(1) @interpolate(flat) dashInfo : vec2<f32>,\\n\\n @location(2) @interpolate(flat) dash0_3 : vec4<f32>,\\n @location(3) @interpolate(flat) dash4_7 : vec4<f32>,\\n @location(4) @interpolate(flat) color : vec4<f32>,\\n\\n // Axis-aligned quad anti-aliasing (device pixels).\\n // acrossDevice ranges [0..widthDevice] across the stroke thickness.\\n @location(5) acrossDevice : f32,\\n @location(6) @interpolate(flat) widthDevice : f32,\\n};\\n\\nfn quadUv(vid : u32) -> vec2<f32> {\\n // Two triangles covering [0,1]x[0,1].\\n // 0: (0,0) 1:(1,0) 2:(0,1) 3:(0,1) 4:(1,0) 5:(1,1)\\n switch (vid) {\\n case 0u: { return vec2<f32>(0.0, 0.0); }\\n case 1u: { return vec2<f32>(1.0, 0.0); }\\n case 2u: { return vec2<f32>(0.0, 1.0); }\\n case 3u: { return vec2<f32>(0.0, 1.0); }\\n case 4u: { return vec2<f32>(1.0, 0.0); }\\n default: { return vec2<f32>(1.0, 1.0); }\\n }\\n}\\n\\n@vertex\\nfn vsMain(in : VSIn, @builtin(vertex_index) vid : u32) -> VSOut {\\n let uv = quadUv(vid);\\n let dpr = max(1e-6, u.devicePixelRatio);\\n // IMPORTANT: Do NOT snap reference lines to integer device pixels.\\n // Snapping looks crisp at rest but causes visible \\\"jiggle\\\" / stepping while zooming because\\n // the line position is continuously changing (data-space → screen-space), and rounding\\n // quantizes that motion to adjacent pixels. We rely on analytic AA in the fragment stage\\n // to keep strokes stable and reasonably crisp across DPRs.\\n\\n let axis = in.axisPos.x;\\n let posCss = in.axisPos.y;\\n let widthCss = max(0.0, in.widthDashCount.x);\\n let widthDevice = max(1.0, widthCss * dpr);\\n\\n var xDevice : f32;\\n var yDevice : f32;\\n var alongCss : f32;\\n var acrossDevice : f32;\\n\\n if (axis < 0.5) {\\n // Vertical line at x = posCss (canvas-local CSS px), spanning plot height.\\n let centerX = posCss * dpr;\\n let startX = centerX - 0.5 * widthDevice;\\n xDevice = startX + uv.x * widthDevice;\\n yDevice = u.plotOrigin.y + uv.y * u.plotSize.y;\\n alongCss = (uv.y * u.plotSize.y) / dpr;\\n acrossDevice = uv.x * widthDevice;\\n } else {\\n // Horizontal line at y = posCss (canvas-local CSS px), spanning plot width.\\n let centerY = posCss * dpr;\\n let startY = centerY - 0.5 * widthDevice;\\n xDevice = u.plotOrigin.x + uv.x * u.plotSize.x;\\n yDevice = startY + uv.y * widthDevice;\\n alongCss = (uv.x * u.plotSize.x) / dpr;\\n acrossDevice = uv.y * widthDevice;\\n }\\n\\n let clipX = (xDevice / u.canvasSize.x) * 2.0 - 1.0;\\n let clipY = 1.0 - (yDevice / u.canvasSize.y) * 2.0;\\n\\n var out : VSOut;\\n out.position = vec4<f32>(clipX, clipY, 0.0, 1.0);\\n out.alongCss = alongCss;\\n out.dashInfo = vec2<f32>(in.widthDashCount.y, in.dashMeta.x);\\n out.dash0_3 = in.dash0_3;\\n out.dash4_7 = in.dash4_7;\\n out.color = in.color;\\n out.acrossDevice = acrossDevice;\\n out.widthDevice = widthDevice;\\n return out;\\n}\\n\\nfn dashValue(i : u32, d0 : vec4<f32>, d1 : vec4<f32>) -> f32 {\\n switch (i) {\\n case 0u: { return d0.x; }\\n case 1u: { return d0.y; }\\n case 2u: { return d0.z; }\\n case 3u: { return d0.w; }\\n case 4u: { return d1.x; }\\n case 5u: { return d1.y; }\\n case 6u: { return d1.z; }\\n default: { return d1.w; }\\n }\\n}\\n\\n@fragment\\nfn fsMain(in : VSOut) -> @location(0) vec4<f32> {\\n // Analytic edge anti-aliasing for axis-aligned quads (reduces shimmering during zoom).\\n // This is a lightweight alternative to full MSAA for thin strokes.\\n let edgeDist = min(in.acrossDevice, in.widthDevice - in.acrossDevice);\\n // Slightly widen AA to reduce temporal shimmer on moving 1-2px strokes.\\n // Keep conservative so lines remain reasonably crisp.\\n let aa = max(fwidth(in.acrossDevice), 1e-3) * 1.25;\\n let edgeCoverage = smoothstep(0.0, aa, edgeDist);\\n var color = in.color;\\n color.a = color.a * edgeCoverage;\\n\\n let dashCount = u32(round(in.dashInfo.x));\\n let dashTotal = in.dashInfo.y;\\n\\n // IMPORTANT: derivative ops (fwidth) must execute in uniform control flow.\\n // So compute the dash parameterization unconditionally (using a safe total) BEFORE any early-return.\\n let dashTotalSafe = max(dashTotal, 1.0);\\n let t = in.alongCss - floor(in.alongCss / dashTotalSafe) * dashTotalSafe;\\n // Anti-alias dash edges along the line axis (CSS pixels).\\n // This reduces shimmer during zoom for dashed reference lines without requiring MSAA.\\n let dashAa = max(fwidth(t), 1e-3);\\n\\n // Solid line (no dash pattern).\\n if (dashCount == 0u || dashTotal <= 0.0) {\\n return color;\\n }\\n\\n var acc = 0.0;\\n var on = true;\\n\\n for (var i : u32 = 0u; i < 8u; i = i + 1u) {\\n if (i >= dashCount) { break; }\\n let seg = dashValue(i, in.dash0_3, in.dash4_7);\\n if (seg <= 0.0) { continue; }\\n\\n if (t < acc + seg) {\\n // IMPORTANT: Avoid `discard` for off segments.\\n // Discard can cause temporal popping on moving dashed edges; prefer a smooth alpha mask.\\n //\\n // Fade in/out near dash boundaries for smooth edges. This produces coverage in [0..1]\\n // within the current segment, going to 0 at segment boundaries.\\n let inFromStart = smoothstep(0.0, dashAa, t - acc);\\n let inFromEnd = smoothstep(0.0, dashAa, (acc + seg) - t);\\n let segCoverage = min(inFromStart, inFromEnd);\\n\\n // On segments contribute alpha; off segments contribute 0 alpha (no discard).\\n let dashMask = select(0.0, segCoverage, on);\\n color.a = color.a * dashMask;\\n return color;\\n }\\n\\n acc = acc + seg;\\n on = !on;\\n }\\n\\n // Defensive fallback if the dash list is degenerate.\\n // If we didn't find a segment (shouldn't happen), default to transparent (safer than solid).\\n color.a = 0.0;\\n return color;\\n}\\n\"","import referenceLineWgsl from '../shaders/referenceLine.wgsl?raw';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport type { GridArea } from './createGridRenderer';\n\n/**\n * Maximum dash entries supported per line instance.\n *\n * WGSL requires fixed-size arrays/varyings; we cap and truncate for deterministic perf.\n * If you need more, increase this (and update the shader accordingly).\n */\nconst MAX_DASH_VALUES = 8;\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nexport type ReferenceLineAxis = 'vertical' | 'horizontal';\n\nexport interface ReferenceLineInstance {\n /**\n * Axis alignment.\n * - `'vertical'`: a line spanning the plot height at a fixed X position\n * - `'horizontal'`: a line spanning the plot width at a fixed Y position\n */\n readonly axis: ReferenceLineAxis;\n\n /**\n * Position in **CANVAS-LOCAL CSS pixels**.\n *\n * This is the same coordinate space as pointer event payloads:\n * - For vertical lines: canvas-local X in CSS px\n * - For horizontal lines: canvas-local Y in CSS px\n *\n * The shader converts CSS px → device px using DPR and relies on analytic AA for stable\n * strokes during zoom (no integer device-pixel snapping).\n */\n readonly positionCssPx: number;\n\n /**\n * Desired line width in **CSS pixels**.\n *\n * The renderer emulates thickness using a quad (two triangles) and converts CSS px to\n * device px using `gridArea.devicePixelRatio`.\n */\n readonly lineWidth: number;\n\n /**\n * Dash pattern in **CSS pixels**, matching the semantics of Canvas2D/SVG:\n * `[dash, gap, dash, gap, ...]`, repeating, starting with an \"on\" dash.\n *\n * - `undefined` / `[]` renders a solid line.\n * - Non-finite / non-positive entries are ignored.\n * - If the list length is odd, it is duplicated (CSS behavior) before truncation.\n * - The pattern is truncated to `MAX_DASH_VALUES`.\n */\n readonly lineDash?: ReadonlyArray<number>;\n\n /**\n * Line color as RGBA in 0..1.\n *\n * `rgba[3]` is the final opacity (i.e. you can pre-multiply any \"opacity\" control into alpha).\n */\n readonly rgba: readonly [number, number, number, number];\n}\n\nexport interface ReferenceLineRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n\n /**\n * Multisample count for the render pipeline.\n *\n * Must match the render pass color attachment sampleCount.\n * Defaults to 1 (no MSAA).\n */\n readonly sampleCount?: number;\n}\n\nexport interface ReferenceLineRenderer {\n /**\n * Prepares GPU buffers and uniforms for drawing.\n *\n * Coordinate contract:\n * - Line positions are CANVAS-LOCAL CSS pixels.\n * - `gridArea` margins are CSS pixels; `gridArea.canvasWidth/Height` are device pixels.\n */\n prepare(gridArea: GridArea, lines: ReadonlyArray<ReferenceLineInstance>): void;\n /**\n * Draws all prepared reference lines.\n *\n * Important: This renderer does NOT set scissor state. The render coordinator is expected\n * to set a scissor rect for the plot area before calling `render()`.\n */\n render(passEncoder: GPURenderPassEncoder, firstInstance?: number, instanceCount?: number): void;\n /** Cleans up GPU resources (best-effort). */\n dispose(): void;\n}\n\nconst isFiniteGridArea = (gridArea: GridArea): boolean =>\n Number.isFinite(gridArea.left) &&\n Number.isFinite(gridArea.right) &&\n Number.isFinite(gridArea.top) &&\n Number.isFinite(gridArea.bottom) &&\n Number.isFinite(gridArea.canvasWidth) &&\n Number.isFinite(gridArea.canvasHeight);\n\ntype PackedDash = {\n readonly dashCount: number;\n readonly dashTotal: number;\n readonly values: readonly number[]; // length MAX_DASH_VALUES\n};\n\nconst normalizeDash = (lineDash?: ReadonlyArray<number>): PackedDash => {\n if (!lineDash || lineDash.length === 0) {\n return { dashCount: 0, dashTotal: 0, values: new Array<number>(MAX_DASH_VALUES).fill(0) };\n }\n\n const cleaned: number[] = [];\n for (let i = 0; i < lineDash.length; i++) {\n const v = lineDash[i];\n if (typeof v === 'number' && Number.isFinite(v) && v > 0) cleaned.push(v);\n }\n\n if (cleaned.length === 0) {\n return { dashCount: 0, dashTotal: 0, values: new Array<number>(MAX_DASH_VALUES).fill(0) };\n }\n\n // CSS behavior: odd-length dash arrays are repeated to make even length.\n const normalized = cleaned.length % 2 === 1 ? cleaned.concat(cleaned) : cleaned;\n\n const dashCount = Math.min(MAX_DASH_VALUES, normalized.length);\n const values = new Array<number>(MAX_DASH_VALUES).fill(0);\n let dashTotal = 0;\n for (let i = 0; i < dashCount; i++) {\n values[i] = normalized[i];\n dashTotal += normalized[i];\n }\n\n if (!Number.isFinite(dashTotal) || dashTotal <= 0) {\n return { dashCount: 0, dashTotal: 0, values: new Array<number>(MAX_DASH_VALUES).fill(0) };\n }\n\n return { dashCount, dashTotal, values };\n};\n\nexport function createReferenceLineRenderer(device: GPUDevice, options?: ReferenceLineRendererOptions): ReferenceLineRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n // Be resilient: coerce invalid values to 1 (no MSAA).\n const sampleCountRaw = options?.sampleCount ?? 1;\n const sampleCount = Number.isFinite(sampleCountRaw) ? Math.max(1, Math.floor(sampleCountRaw)) : 1;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n });\n\n // VSUniforms:\n // - canvasSize (vec2f)\n // - plotOrigin (vec2f)\n // - plotSize (vec2f)\n // - devicePixelRatio (f32)\n // - pad (f32)\n const vsUniformBuffer = createUniformBuffer(device, 32, { label: 'referenceLineRenderer/vsUniforms' });\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n });\n\n const INSTANCE_STRIDE_BYTES = 72;\n const INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\n const pipeline = createRenderPipeline(device, {\n label: 'referenceLineRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: referenceLineWgsl,\n label: 'referenceLine.wgsl',\n buffers: [\n {\n arrayStride: INSTANCE_STRIDE_BYTES,\n stepMode: 'instance',\n attributes: [\n { shaderLocation: 0, format: 'float32x2', offset: 0 }, // axisPos\n { shaderLocation: 1, format: 'float32x2', offset: 8 }, // widthDashCount\n { shaderLocation: 2, format: 'float32x2', offset: 16 }, // dashMeta\n { shaderLocation: 3, format: 'float32x4', offset: 24 }, // dash0_3\n { shaderLocation: 4, format: 'float32x4', offset: 40 }, // dash4_7\n { shaderLocation: 5, format: 'float32x4', offset: 56 }, // color\n ],\n },\n ],\n },\n fragment: {\n code: referenceLineWgsl,\n label: 'referenceLine.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: sampleCount },\n });\n\n let instanceBuffer: GPUBuffer | null = null;\n let instanceCapacity = 0;\n let instanceCount = 0;\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('ReferenceLineRenderer is disposed.');\n };\n\n const prepare: ReferenceLineRenderer['prepare'] = (gridArea, lines) => {\n assertNotDisposed();\n\n if (!Array.isArray(lines)) {\n throw new Error('ReferenceLineRenderer.prepare: lines must be an array.');\n }\n if (!isFiniteGridArea(gridArea)) {\n throw new Error('ReferenceLineRenderer.prepare: gridArea dimensions must be finite numbers.');\n }\n if (gridArea.canvasWidth <= 0 || gridArea.canvasHeight <= 0) {\n throw new Error('ReferenceLineRenderer.prepare: canvas dimensions must be positive.');\n }\n if (gridArea.left < 0 || gridArea.right < 0 || gridArea.top < 0 || gridArea.bottom < 0) {\n throw new Error('ReferenceLineRenderer.prepare: gridArea margins must be non-negative.');\n }\n\n // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n const dpr =\n Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n const plotLeftDevice = gridArea.left * dpr;\n const plotTopDevice = gridArea.top * dpr;\n const plotRightDevice = gridArea.canvasWidth - gridArea.right * dpr;\n const plotBottomDevice = gridArea.canvasHeight - gridArea.bottom * dpr;\n const plotWidthDevice = plotRightDevice - plotLeftDevice;\n const plotHeightDevice = plotBottomDevice - plotTopDevice;\n\n if (!(plotWidthDevice > 0) || !(plotHeightDevice > 0)) {\n instanceCount = 0;\n return;\n }\n\n // Write uniforms.\n const uniforms = new Float32Array(8);\n uniforms[0] = gridArea.canvasWidth;\n uniforms[1] = gridArea.canvasHeight;\n uniforms[2] = plotLeftDevice;\n uniforms[3] = plotTopDevice;\n uniforms[4] = plotWidthDevice;\n uniforms[5] = plotHeightDevice;\n uniforms[6] = dpr;\n uniforms[7] = 0;\n writeUniformBuffer(device, vsUniformBuffer, uniforms);\n\n // Early out: no instances.\n if (lines.length === 0) {\n instanceCount = 0;\n return;\n }\n\n // Ensure instance buffer capacity.\n if (!instanceBuffer || instanceCapacity < lines.length) {\n const nextCapacity = Math.max(1, Math.ceil(lines.length * 1.5));\n const size = Math.max(4, nextCapacity * INSTANCE_STRIDE_BYTES);\n\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n\n instanceBuffer = device.createBuffer({\n label: 'referenceLineRenderer/instanceBuffer',\n size,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n instanceCapacity = nextCapacity;\n }\n\n const data = new Float32Array(lines.length * INSTANCE_STRIDE_FLOATS);\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const base = i * INSTANCE_STRIDE_FLOATS;\n\n if (line.axis !== 'vertical' && line.axis !== 'horizontal') {\n throw new Error(\"ReferenceLineRenderer.prepare: line.axis must be 'vertical' or 'horizontal'.\");\n }\n if (!Number.isFinite(line.positionCssPx)) {\n throw new Error('ReferenceLineRenderer.prepare: line.positionCssPx must be a finite number.');\n }\n if (!Number.isFinite(line.lineWidth) || line.lineWidth < 0) {\n throw new Error('ReferenceLineRenderer.prepare: line.lineWidth must be a finite non-negative number.');\n }\n\n const rgba = line.rgba;\n if (!Array.isArray(rgba) || rgba.length !== 4) {\n throw new Error('ReferenceLineRenderer.prepare: line.rgba must be a tuple [r,g,b,a].');\n }\n\n const dash = normalizeDash(line.lineDash);\n\n // axisPos\n data[base + 0] = line.axis === 'vertical' ? 0 : 1;\n data[base + 1] = line.positionCssPx;\n\n // widthDashCount\n data[base + 2] = line.lineWidth;\n data[base + 3] = dash.dashCount;\n\n // dashMeta\n data[base + 4] = dash.dashTotal;\n data[base + 5] = 0;\n\n // dash0_3 + dash4_7\n for (let d = 0; d < MAX_DASH_VALUES; d++) {\n data[base + 6 + d] = dash.values[d];\n }\n\n // color\n data[base + 14] = rgba[0];\n data[base + 15] = rgba[1];\n data[base + 16] = rgba[2];\n data[base + 17] = rgba[3];\n }\n\n device.queue.writeBuffer(instanceBuffer, 0, data.buffer, data.byteOffset, data.byteLength);\n instanceCount = lines.length;\n };\n\n const render: ReferenceLineRenderer['render'] = (passEncoder, firstInstance = 0, requestedCount) => {\n assertNotDisposed();\n if (instanceCount === 0 || !instanceBuffer) return;\n\n const first = Number.isFinite(firstInstance) ? Math.max(0, Math.floor(firstInstance)) : 0;\n const available = Math.max(0, instanceCount - first);\n const count =\n requestedCount == null\n ? available\n : Number.isFinite(requestedCount)\n ? Math.max(0, Math.min(available, Math.floor(requestedCount)))\n : available;\n if (count === 0) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, instanceBuffer);\n passEncoder.draw(6, count, 0, first);\n };\n\n const dispose: ReferenceLineRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n\n instanceBuffer = null;\n instanceCapacity = 0;\n instanceCount = 0;\n };\n\n return { prepare, render, dispose };\n}\n\n","export default \"// annotationMarker.wgsl\\n// Instanced annotation marker shader (circle SDF with optional stroke).\\n//\\n// Coordinate contract:\\n// - Instance center is CANVAS-LOCAL CSS pixels (xCssPx, yCssPx)\\n// - Instance size is diameter in CSS pixels (sizeCssPx)\\n// - Uniform provides render target size in *device* pixels and DPR for CSS→device conversion.\\n//\\n// Draw call: draw(6, instanceCount) using triangle-list quad expansion in VS.\\n\\nstruct VSUniforms {\\n viewportPx: vec2<f32>, // render target size in device pixels (width, height)\\n dpr: f32, // device pixel ratio (CSS px -> device px)\\n _pad0: f32,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n // Center in CANVAS-LOCAL CSS pixels.\\n @location(0) centerCssPx: vec2<f32>,\\n // Marker diameter in CSS pixels.\\n @location(1) sizeCssPx: f32,\\n // Stroke width in CSS pixels (0 disables stroke).\\n @location(2) strokeWidthCssPx: f32,\\n // Colors are straight-alpha RGBA in 0..1.\\n @location(3) fillRgba: vec4<f32>,\\n @location(4) strokeRgba: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n @builtin(position) clipPosition: vec4<f32>,\\n // Local quad coordinates in [-1, 1]^2 (used for circle SDF).\\n @location(0) local: vec2<f32>,\\n // Half-size in device pixels (radius in screen space).\\n @location(1) halfSizePx: f32,\\n @location(2) strokeWidthPx: f32,\\n @location(3) fillRgba: vec4<f32>,\\n @location(4) strokeRgba: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n // Fixed local corners for 2 triangles (triangle-list).\\n let localCorners = array<vec2<f32>, 6>(\\n vec2<f32>(-1.0, -1.0),\\n vec2<f32>( 1.0, -1.0),\\n vec2<f32>(-1.0, 1.0),\\n vec2<f32>(-1.0, 1.0),\\n vec2<f32>( 1.0, -1.0),\\n vec2<f32>( 1.0, 1.0)\\n );\\n\\n let corner = localCorners[vertexIndex];\\n\\n let dpr = select(1.0, vsUniforms.dpr, vsUniforms.dpr > 0.0);\\n let centerPx = in.centerCssPx * dpr;\\n let halfSizePx = 0.5 * max(0.0, in.sizeCssPx) * dpr;\\n let strokeWidthPx = max(0.0, in.strokeWidthCssPx) * dpr;\\n\\n let posPx = centerPx + corner * halfSizePx;\\n\\n // Convert device pixels to clip-space with origin at top-left:\\n // x: [0..w] -> [-1..1], y: [0..h] -> [1..-1]\\n let clipX = (posPx.x / vsUniforms.viewportPx.x) * 2.0 - 1.0;\\n let clipY = 1.0 - (posPx.y / vsUniforms.viewportPx.y) * 2.0;\\n\\n var out: VSOut;\\n out.clipPosition = vec4<f32>(clipX, clipY, 0.0, 1.0);\\n out.local = corner;\\n out.halfSizePx = halfSizePx;\\n out.strokeWidthPx = strokeWidthPx;\\n out.fillRgba = in.fillRgba;\\n out.strokeRgba = in.strokeRgba;\\n return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n if (in.halfSizePx <= 0.0) {\\n discard;\\n }\\n\\n // Circle SDF in normalized space: dist == 1 at the circle boundary.\\n let dist = length(in.local);\\n let aa = max(1e-6, fwidth(dist));\\n\\n // Coverage inside the circle.\\n let outerCoverage = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, dist);\\n if (outerCoverage <= 0.0) {\\n discard;\\n }\\n\\n // Optional stroke: compute inner radius in normalized units.\\n let strokeNorm = clamp(in.strokeWidthPx / max(1e-6, in.halfSizePx), 0.0, 1.0);\\n let inner = max(0.0, 1.0 - strokeNorm);\\n let innerCoverage = 1.0 - smoothstep(inner - aa, inner + aa, dist);\\n\\n let fillCoverage = clamp(innerCoverage, 0.0, 1.0);\\n let strokeCoverage = clamp(outerCoverage - innerCoverage, 0.0, 1.0);\\n\\n let fillA = clamp(in.fillRgba.a, 0.0, 1.0) * fillCoverage;\\n let strokeA = clamp(in.strokeRgba.a, 0.0, 1.0) * strokeCoverage;\\n let outA = fillA + strokeA;\\n if (outA <= 0.0) {\\n discard;\\n }\\n\\n // Straight-alpha output: compute a weighted average RGB for correct blending.\\n let rgb = (in.fillRgba.rgb * fillA + in.strokeRgba.rgb * strokeA) / outA;\\n return vec4<f32>(rgb, outA);\\n}\\n\\n\"","import annotationMarkerWgsl from '../shaders/annotationMarker.wgsl?raw';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport type AnnotationMarkerInstance = Readonly<{\n /**\n * Center in CANVAS-LOCAL CSS pixels.\n * (0,0) is the canvas top-left in CSS pixel coordinates.\n */\n xCssPx: number;\n yCssPx: number;\n\n /** Marker diameter in CSS pixels. */\n sizeCssPx: number;\n\n /** Fill color RGBA in 0..1 (straight alpha). */\n fillRgba: readonly [r: number, g: number, b: number, a: number];\n\n /** Optional stroke width in CSS pixels (0 disables stroke). */\n strokeWidthCssPx?: number;\n\n /** Optional stroke color RGBA in 0..1 (straight alpha). */\n strokeRgba?: readonly [r: number, g: number, b: number, a: number];\n}>;\n\nexport interface AnnotationMarkerRenderer {\n /**\n * Uploads marker instances and prepares uniforms for rendering.\n *\n * Coordinate contract:\n * - `instances[*].xCssPx/yCssPx` are CANVAS-LOCAL CSS pixels.\n * - `canvasWidth/canvasHeight` are in *device pixels* (same as render target size).\n * - `devicePixelRatio` is used to convert CSS px to device px inside the shader.\n *\n * Scissor contract:\n * - This renderer intentionally does NOT set or reset scissor state.\n * The caller must set scissor for plot clipping before invoking `render()`.\n */\n prepare(params: Readonly<{\n canvasWidth: number;\n canvasHeight: number;\n devicePixelRatio: number;\n instances: readonly AnnotationMarkerInstance[];\n }>): void;\n\n /** Draws all prepared instances (if any). */\n render(passEncoder: GPURenderPassEncoder, firstInstance?: number, instanceCount?: number): void;\n\n /** Cleans up GPU resources (best-effort). */\n dispose(): void;\n}\n\nexport interface AnnotationMarkerRendererOptions {\n /**\n * Must match the canvas context format used for the render pass color attachment.\n * Usually this is `gpuContext.preferredFormat`.\n *\n * Defaults to `'bgra8unorm'` for backward compatibility.\n */\n readonly targetFormat?: GPUTextureFormat;\n\n /**\n * Multisample count for the render pipeline.\n *\n * Must match the render pass color attachment sampleCount.\n * Defaults to 1 (no MSAA).\n */\n readonly sampleCount?: number;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\n// Instance layout (WGSL VSIn):\n// centerCssPx.xy, sizeCssPx, strokeWidthCssPx, fillRgba.rgba, strokeRgba.rgba\nconst INSTANCE_STRIDE_FLOATS = 12;\nconst INSTANCE_STRIDE_BYTES = INSTANCE_STRIDE_FLOATS * 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\nconst nextPow2 = (v: number): number => {\n if (!Number.isFinite(v) || v <= 0) return 1;\n const n = Math.ceil(v);\n return 2 ** Math.ceil(Math.log2(n));\n};\n\nexport function createAnnotationMarkerRenderer(device: GPUDevice, options?: AnnotationMarkerRendererOptions): AnnotationMarkerRenderer {\n let disposed = false;\n const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n // Be resilient: coerce invalid values to 1 (no MSAA).\n const sampleCountRaw = options?.sampleCount ?? 1;\n const sampleCount = Number.isFinite(sampleCountRaw) ? Math.max(1, Math.floor(sampleCountRaw)) : 1;\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n });\n\n // VSUniforms (WGSL):\n // viewportPx vec2 + dpr f32 + pad f32 = 16 bytes\n const vsUniformBuffer = createUniformBuffer(device, 16, { label: 'annotationMarkerRenderer/vsUniforms' });\n const vsUniformScratchF32 = new Float32Array(4);\n\n const bindGroup = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n });\n\n const pipeline = createRenderPipeline(device, {\n label: 'annotationMarkerRenderer/pipeline',\n bindGroupLayouts: [bindGroupLayout],\n vertex: {\n code: annotationMarkerWgsl,\n label: 'annotationMarker.wgsl',\n buffers: [\n {\n arrayStride: INSTANCE_STRIDE_BYTES,\n stepMode: 'instance',\n attributes: [\n { shaderLocation: 0, format: 'float32x2', offset: 0 }, // centerCssPx\n { shaderLocation: 1, format: 'float32', offset: 8 }, // sizeCssPx\n { shaderLocation: 2, format: 'float32', offset: 12 }, // strokeWidthCssPx\n { shaderLocation: 3, format: 'float32x4', offset: 16 }, // fillRgba\n { shaderLocation: 4, format: 'float32x4', offset: 32 }, // strokeRgba\n ],\n },\n ],\n },\n fragment: {\n code: annotationMarkerWgsl,\n label: 'annotationMarker.wgsl',\n formats: targetFormat,\n blend: {\n color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n },\n },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: sampleCount },\n });\n\n let instanceBuffer: GPUBuffer | null = null;\n let instanceCount = 0;\n let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('AnnotationMarkerRenderer is disposed.');\n };\n\n const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n if (requiredFloats <= cpuInstanceStagingF32.length) return;\n const nextFloats = Math.max(32, nextPow2(requiredFloats));\n cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n };\n\n const writeVsUniforms = (canvasWidthDevicePx: number, canvasHeightDevicePx: number, devicePixelRatio: number): void => {\n const w = Number.isFinite(canvasWidthDevicePx) && canvasWidthDevicePx > 0 ? canvasWidthDevicePx : 1;\n const h = Number.isFinite(canvasHeightDevicePx) && canvasHeightDevicePx > 0 ? canvasHeightDevicePx : 1;\n const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n\n vsUniformScratchF32[0] = w;\n vsUniformScratchF32[1] = h;\n vsUniformScratchF32[2] = dpr;\n vsUniformScratchF32[3] = 0;\n writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchF32);\n };\n\n const prepare: AnnotationMarkerRenderer['prepare'] = ({ canvasWidth, canvasHeight, devicePixelRatio, instances }) => {\n assertNotDisposed();\n\n if (!Number.isFinite(canvasWidth) || !Number.isFinite(canvasHeight) || canvasWidth <= 0 || canvasHeight <= 0) {\n throw new Error('AnnotationMarkerRenderer.prepare: canvasWidth/canvasHeight must be positive finite numbers.');\n }\n if (!Array.isArray(instances)) {\n throw new Error('AnnotationMarkerRenderer.prepare: instances must be an array.');\n }\n\n writeVsUniforms(canvasWidth, canvasHeight, devicePixelRatio);\n\n ensureCpuInstanceCapacityFloats(instances.length * INSTANCE_STRIDE_FLOATS);\n const f32 = cpuInstanceStagingF32;\n let outFloats = 0;\n\n for (let i = 0; i < instances.length; i++) {\n const m = instances[i];\n if (!Number.isFinite(m.xCssPx) || !Number.isFinite(m.yCssPx)) continue;\n if (!Number.isFinite(m.sizeCssPx) || m.sizeCssPx <= 0) continue;\n\n const strokeWidthCss = m.strokeWidthCssPx ?? 0;\n const strokeRgba = m.strokeRgba ?? ([0, 0, 0, 0] as const);\n\n // Clamp colors to [0,1] for deterministic output.\n const fr = clamp01(m.fillRgba[0]);\n const fg = clamp01(m.fillRgba[1]);\n const fb = clamp01(m.fillRgba[2]);\n const fa = clamp01(m.fillRgba[3]);\n\n const sr = clamp01(strokeRgba[0]);\n const sg = clamp01(strokeRgba[1]);\n const sb = clamp01(strokeRgba[2]);\n const sa = clamp01(strokeRgba[3]);\n\n f32[outFloats + 0] = m.xCssPx;\n f32[outFloats + 1] = m.yCssPx;\n f32[outFloats + 2] = m.sizeCssPx;\n f32[outFloats + 3] = Number.isFinite(strokeWidthCss) ? Math.max(0, strokeWidthCss) : 0;\n\n f32[outFloats + 4] = fr;\n f32[outFloats + 5] = fg;\n f32[outFloats + 6] = fb;\n f32[outFloats + 7] = fa;\n\n f32[outFloats + 8] = sr;\n f32[outFloats + 9] = sg;\n f32[outFloats + 10] = sb;\n f32[outFloats + 11] = sa;\n\n outFloats += INSTANCE_STRIDE_FLOATS;\n }\n\n instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n\n // PERFORMANCE: Early exit if no valid instances (skip buffer allocation/write)\n if (instanceCount === 0) {\n return;\n }\n\n const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = device.createBuffer({\n label: 'annotationMarkerRenderer/instanceBuffer',\n size: grownBytes,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n }\n\n // PERFORMANCE: Only write buffer when we have instances (instanceCount > 0 already checked above)\n device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n };\n\n const render: AnnotationMarkerRenderer['render'] = (passEncoder, firstInstance = 0, requestedCount) => {\n assertNotDisposed();\n if (!instanceBuffer || instanceCount === 0) return;\n\n const first = Number.isFinite(firstInstance) ? Math.max(0, Math.floor(firstInstance)) : 0;\n const available = Math.max(0, instanceCount - first);\n const count =\n requestedCount == null\n ? available\n : Number.isFinite(requestedCount)\n ? Math.max(0, Math.min(available, Math.floor(requestedCount)))\n : available;\n if (count === 0) return;\n\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, bindGroup);\n passEncoder.setVertexBuffer(0, instanceBuffer);\n passEncoder.draw(6, count, 0, first);\n };\n\n const dispose: AnnotationMarkerRenderer['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n if (instanceBuffer) {\n try {\n instanceBuffer.destroy();\n } catch {\n // best-effort\n }\n }\n instanceBuffer = null;\n instanceCount = 0;\n\n try {\n vsUniformBuffer.destroy();\n } catch {\n // best-effort\n }\n };\n\n return { prepare, render, dispose };\n}\n\n","import type { GridArea } from '../renderers/createGridRenderer';\n\nexport type ChartGPUEventName = 'mousemove' | 'click' | 'mouseleave';\n\nexport type ChartGPUEventPayload = {\n readonly x: number;\n readonly y: number;\n readonly gridX: number;\n readonly gridY: number;\n /** Plot (grid) width in CSS pixels. */\n readonly plotWidthCss: number;\n /** Plot (grid) height in CSS pixels. */\n readonly plotHeightCss: number;\n readonly isInGrid: boolean;\n readonly originalEvent: PointerEvent;\n};\n\nexport type ChartGPUEventCallback = (payload: ChartGPUEventPayload) => void;\n\nexport interface EventManager {\n readonly canvas: HTMLCanvasElement;\n on(event: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n off(event: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n updateGridArea(gridArea: GridArea): void;\n dispose(): void;\n}\n\ntype ListenerRegistry = Readonly<Record<ChartGPUEventName, Set<ChartGPUEventCallback>>>;\n\ntype TapCandidate = {\n readonly pointerId: number;\n readonly startClientX: number;\n readonly startClientY: number;\n readonly startTimeMs: number;\n};\n\nconst DEFAULT_TAP_MAX_DISTANCE_CSS_PX = 6;\nconst DEFAULT_TAP_MAX_TIME_MS = 500;\n\nexport function createEventManager(canvas: HTMLCanvasElement, initialGridArea: GridArea): EventManager {\n let disposed = false;\n let gridArea = initialGridArea;\n\n const listeners: ListenerRegistry = {\n mousemove: new Set<ChartGPUEventCallback>(),\n click: new Set<ChartGPUEventCallback>(),\n mouseleave: new Set<ChartGPUEventCallback>(),\n };\n\n let tapCandidate: TapCandidate | null = null;\n let suppressNextLostPointerCaptureId: number | null = null;\n\n const toPayload = (e: PointerEvent): ChartGPUEventPayload | null => {\n const rect = canvas.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return null;\n\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n const plotLeftCss = gridArea.left;\n const plotTopCss = gridArea.top;\n const plotWidthCss = rect.width - gridArea.left - gridArea.right;\n const plotHeightCss = rect.height - gridArea.top - gridArea.bottom;\n\n const gridX = x - plotLeftCss;\n const gridY = y - plotTopCss;\n\n const isInGrid =\n gridX >= 0 &&\n gridX <= plotWidthCss &&\n gridY >= 0 &&\n gridY <= plotHeightCss;\n\n return { x, y, gridX, gridY, plotWidthCss, plotHeightCss, isInGrid, originalEvent: e };\n };\n\n const emit = (eventName: ChartGPUEventName, e: PointerEvent): void => {\n const payload = toPayload(e);\n if (!payload) return;\n\n for (const cb of listeners[eventName]) cb(payload);\n };\n\n const clearTapCandidateIfMatches = (e: PointerEvent): void => {\n if (!tapCandidate) return;\n if (!e.isPrimary) return;\n if (e.pointerId !== tapCandidate.pointerId) return;\n tapCandidate = null;\n };\n\n const onPointerMove = (e: PointerEvent): void => {\n if (disposed) return;\n emit('mousemove', e);\n };\n\n const onPointerLeave = (e: PointerEvent): void => {\n if (disposed) return;\n clearTapCandidateIfMatches(e);\n emit('mouseleave', e);\n };\n\n const onPointerCancel = (e: PointerEvent): void => {\n if (disposed) return;\n clearTapCandidateIfMatches(e);\n emit('mouseleave', e);\n };\n\n const onLostPointerCapture = (e: PointerEvent): void => {\n if (disposed) return;\n if (suppressNextLostPointerCaptureId === e.pointerId) {\n suppressNextLostPointerCaptureId = null;\n return;\n }\n clearTapCandidateIfMatches(e);\n emit('mouseleave', e);\n };\n\n const onPointerDown = (e: PointerEvent): void => {\n if (disposed) return;\n if (!e.isPrimary) return;\n\n // For mouse, only allow left button.\n if (e.pointerType === 'mouse' && e.button !== 0) return;\n\n // If canvas has no size, treat as non-interactive (and avoid tap tracking).\n const rect = canvas.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return;\n\n tapCandidate = {\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n startTimeMs: e.timeStamp,\n };\n\n // Optional pointer capture improves reliability for touch/pen.\n try {\n canvas.setPointerCapture(e.pointerId);\n } catch {\n // best-effort\n }\n };\n\n const onPointerUp = (e: PointerEvent): void => {\n if (disposed) return;\n if (!e.isPrimary) return;\n if (!tapCandidate || e.pointerId !== tapCandidate.pointerId) return;\n\n const dt = e.timeStamp - tapCandidate.startTimeMs;\n const dx = e.clientX - tapCandidate.startClientX;\n const dy = e.clientY - tapCandidate.startClientY;\n const distSq = dx * dx + dy * dy;\n\n tapCandidate = null;\n\n // Release capture if we have it; suppress the resulting lostpointercapture.\n try {\n if (canvas.hasPointerCapture(e.pointerId)) {\n suppressNextLostPointerCaptureId = e.pointerId;\n canvas.releasePointerCapture(e.pointerId);\n }\n } catch {\n // best-effort\n }\n\n const maxDist = DEFAULT_TAP_MAX_DISTANCE_CSS_PX;\n const isTap =\n dt <= DEFAULT_TAP_MAX_TIME_MS && distSq <= maxDist * maxDist;\n\n if (isTap) emit('click', e);\n };\n\n canvas.addEventListener('pointermove', onPointerMove, { passive: true });\n canvas.addEventListener('pointerleave', onPointerLeave, { passive: true });\n canvas.addEventListener('pointercancel', onPointerCancel, { passive: true });\n canvas.addEventListener('lostpointercapture', onLostPointerCapture, { passive: true });\n canvas.addEventListener('pointerdown', onPointerDown, { passive: true });\n canvas.addEventListener('pointerup', onPointerUp, { passive: true });\n\n const on: EventManager['on'] = (event, callback) => {\n if (disposed) return;\n listeners[event].add(callback);\n };\n\n const off: EventManager['off'] = (event, callback) => {\n listeners[event].delete(callback);\n };\n\n const updateGridArea: EventManager['updateGridArea'] = (nextGridArea) => {\n gridArea = nextGridArea;\n };\n\n const dispose: EventManager['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n tapCandidate = null;\n suppressNextLostPointerCaptureId = null;\n\n canvas.removeEventListener('pointermove', onPointerMove);\n canvas.removeEventListener('pointerleave', onPointerLeave);\n canvas.removeEventListener('pointercancel', onPointerCancel);\n canvas.removeEventListener('lostpointercapture', onLostPointerCapture);\n canvas.removeEventListener('pointerdown', onPointerDown);\n canvas.removeEventListener('pointerup', onPointerUp);\n\n listeners.mousemove.clear();\n listeners.click.clear();\n listeners.mouseleave.clear();\n };\n\n return { canvas, on, off, updateGridArea, dispose };\n}\n","import type { EventManager, ChartGPUEventPayload } from './createEventManager';\nimport type { ZoomState } from './createZoomState';\n\nexport type InsideZoom = Readonly<{\n enable(): void;\n disable(): void;\n dispose(): void;\n}>;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\n\nconst normalizeWheelDelta = (e: WheelEvent, basisCssPx: number): number => {\n const raw = e.deltaY;\n if (!Number.isFinite(raw) || raw === 0) return 0;\n\n // Normalize to CSS pixels-ish so sensitivity is stable across deltaMode.\n switch (e.deltaMode) {\n case WheelEvent.DOM_DELTA_PIXEL:\n return raw;\n case WheelEvent.DOM_DELTA_LINE:\n return raw * 16;\n case WheelEvent.DOM_DELTA_PAGE:\n return raw * (Number.isFinite(basisCssPx) && basisCssPx > 0 ? basisCssPx : 800);\n default:\n return raw;\n }\n};\n\nconst normalizeWheelDeltaX = (e: WheelEvent, basisCssPx: number): number => {\n const raw = e.deltaX;\n if (!Number.isFinite(raw) || raw === 0) return 0;\n\n // Normalize to CSS pixels-ish so sensitivity is stable across deltaMode.\n switch (e.deltaMode) {\n case WheelEvent.DOM_DELTA_PIXEL:\n return raw;\n case WheelEvent.DOM_DELTA_LINE:\n return raw * 16;\n case WheelEvent.DOM_DELTA_PAGE:\n return raw * (Number.isFinite(basisCssPx) && basisCssPx > 0 ? basisCssPx : 800);\n default:\n return raw;\n }\n};\n\nconst wheelDeltaToZoomFactor = (deltaCssPx: number): number => {\n // Positive delta = scroll down = zoom out; negative = zoom in.\n const abs = Math.abs(deltaCssPx);\n if (!Number.isFinite(abs) || abs === 0) return 1;\n\n // Cap extreme deltas (some devices can emit huge values).\n const capped = Math.min(abs, 200);\n const sensitivity = 0.002;\n return Math.exp(capped * sensitivity);\n};\n\nconst isMiddleButtonDrag = (e: PointerEvent): boolean =>\n e.pointerType === 'mouse' && (e.buttons & 4) !== 0;\n\nconst isShiftLeftDrag = (e: PointerEvent): boolean =>\n e.pointerType === 'mouse' && e.shiftKey && (e.buttons & 1) !== 0;\n\n/**\n * Internal “inside” zoom interaction:\n * - wheel zoom centered at cursor-x (only when inside grid)\n * - shift+left drag OR middle-mouse drag pans left/right (only when inside grid)\n */\nexport function createInsideZoom(eventManager: EventManager, zoomState: ZoomState): InsideZoom {\n let disposed = false;\n let enabled = false;\n\n let lastPointer: ChartGPUEventPayload | null = null;\n let isPanning = false;\n let lastPanGridX = 0;\n\n const clearPan = (): void => {\n isPanning = false;\n lastPanGridX = 0;\n };\n\n const onMouseMove = (payload: ChartGPUEventPayload): void => {\n lastPointer = payload;\n if (!enabled) return;\n\n // Pan only for mouse drags, only when inside grid.\n const e = payload.originalEvent;\n const shouldPan = payload.isInGrid && (isShiftLeftDrag(e) || isMiddleButtonDrag(e));\n\n if (!shouldPan) {\n clearPan();\n return;\n }\n\n const plotWidthCss = payload.plotWidthCss;\n if (!(plotWidthCss > 0) || !Number.isFinite(plotWidthCss)) {\n clearPan();\n return;\n }\n\n if (!isPanning) {\n isPanning = true;\n lastPanGridX = payload.gridX;\n return;\n }\n\n const dxCss = payload.gridX - lastPanGridX;\n lastPanGridX = payload.gridX;\n if (!Number.isFinite(dxCss) || dxCss === 0) return;\n\n const { start, end } = zoomState.getRange();\n const span = end - start;\n if (!Number.isFinite(span) || span === 0) return;\n\n // Convert grid-local px to percent points *within the current window*.\n // “Grab to pan” behavior: dragging right should move the window left (show earlier data).\n const deltaPct = -(dxCss / plotWidthCss) * span;\n if (!Number.isFinite(deltaPct) || deltaPct === 0) return;\n zoomState.pan(deltaPct);\n };\n\n const onMouseLeave = (_payload: ChartGPUEventPayload): void => {\n lastPointer = null;\n clearPan();\n };\n\n const onWheel = (e: WheelEvent): void => {\n if (!enabled || disposed) return;\n\n const p = lastPointer;\n if (!p || !p.isInGrid) return;\n\n const plotWidthCss = p.plotWidthCss;\n const plotHeightCss = p.plotHeightCss;\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return;\n\n const deltaYCss = normalizeWheelDelta(e, plotHeightCss);\n const deltaXCss = normalizeWheelDeltaX(e, plotWidthCss);\n\n // Check if horizontal scroll is dominant (pan operation).\n if (Math.abs(deltaXCss) > Math.abs(deltaYCss) && deltaXCss !== 0) {\n const { start, end } = zoomState.getRange();\n const span = end - start;\n if (!Number.isFinite(span) || span === 0) return;\n\n // Convert horizontal scroll delta to percent pan.\n // Positive deltaX = scroll right = pan right (show earlier data).\n const deltaPct = (deltaXCss / plotWidthCss) * span;\n if (!Number.isFinite(deltaPct) || deltaPct === 0) return;\n\n e.preventDefault();\n zoomState.pan(deltaPct);\n return;\n }\n\n // Otherwise, proceed with vertical scroll zoom logic.\n if (deltaYCss === 0) return;\n\n const factor = wheelDeltaToZoomFactor(deltaYCss);\n if (!(factor > 1)) return;\n\n const { start, end } = zoomState.getRange();\n const span = end - start;\n if (!Number.isFinite(span) || span === 0) return;\n const r = clamp(p.gridX / plotWidthCss, 0, 1);\n const centerPct = clamp(start + r * span, 0, 100);\n\n // Only prevent default when we are actually consuming the wheel to zoom.\n e.preventDefault();\n\n if (deltaYCss < 0) zoomState.zoomIn(centerPct, factor);\n else zoomState.zoomOut(centerPct, factor);\n };\n\n const enable: InsideZoom['enable'] = () => {\n if (disposed || enabled) return;\n enabled = true;\n eventManager.on('mousemove', onMouseMove);\n eventManager.on('mouseleave', onMouseLeave);\n eventManager.canvas.addEventListener('wheel', onWheel, { passive: false });\n };\n\n const disable: InsideZoom['disable'] = () => {\n if (disposed || !enabled) return;\n enabled = false;\n eventManager.off('mousemove', onMouseMove);\n eventManager.off('mouseleave', onMouseLeave);\n eventManager.canvas.removeEventListener('wheel', onWheel);\n lastPointer = null;\n clearPan();\n };\n\n const dispose: InsideZoom['dispose'] = () => {\n if (disposed) return;\n disable();\n disposed = true;\n };\n\n return { enable, disable, dispose };\n}\n\n","export type ZoomRange = Readonly<{ start: number; end: number }>;\n\nexport type ZoomRangeChangeCallback = (range: ZoomRange) => void;\n\nexport interface ZoomState {\n /**\n * Returns the current zoom window in percent space, clamped to [0, 100].\n */\n getRange(): ZoomRange;\n /**\n * Sets the zoom window in percent space.\n */\n setRange(start: number, end: number): void;\n /**\n * Zooms in around `center` by shrinking the span by `factor`.\n *\n * `factor <= 1` is treated as a no-op.\n */\n zoomIn(center: number, factor: number): void;\n /**\n * Zooms out around `center` by growing the span by `factor`.\n *\n * `factor <= 1` is treated as a no-op.\n */\n zoomOut(center: number, factor: number): void;\n /**\n * Pans the zoom window by `delta` percent points (preserving span).\n */\n pan(delta: number): void;\n /**\n * Subscribes to changes. Returns an unsubscribe function.\n */\n onChange(callback: ZoomRangeChangeCallback): () => void;\n}\n\nexport type ZoomSpanConstraints = Readonly<{\n /**\n * Minimum allowed span (percent points in [0, 100]).\n */\n readonly minSpan?: number;\n /**\n * Maximum allowed span (percent points in [0, 100]).\n */\n readonly maxSpan?: number;\n}>;\n\nexport type ZoomRangeAnchor =\n | 'start'\n | 'end'\n | 'center'\n | Readonly<{ center: number; ratio: number }>;\n\nexport interface ZoomStateWithConstraints extends ZoomState {\n /**\n * Updates span constraints at runtime (used by coordinator on setOption/appendData).\n *\n * Passing `undefined` leaves that constraint unchanged.\n */\n setSpanConstraints(minSpan?: number, maxSpan?: number): void;\n /**\n * Sets a range with an explicit anchor for clamping (used by slider handles).\n */\n setRangeAnchored(start: number, end: number, anchor: ZoomRangeAnchor): void;\n}\n\n// Minimum span of 0.5% prevents zooming beyond what can be reasonably visualized\n// and prevents the slider UI from becoming unusably collapsed.\n// At 0.5% span, a 500px track shows a 2.5px window, which with 10px handles\n// is still somewhat distinguishable. Below 0.5% the UI becomes meaningless.\nconst DEFAULT_MIN_SPAN = 0.5;\nconst DEFAULT_MAX_SPAN = 100;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\nconst clamp01 = (v: number): number => clamp(v, 0, 1);\n\nconst normalizeZero = (v: number): number => (Object.is(v, -0) ? 0 : v);\n\nconst copyRange = (r: ZoomRange): ZoomRange => ({ start: r.start, end: r.end });\n\nexport function createZoomState(\n initialStart: number,\n initialEnd: number,\n constraints?: ZoomSpanConstraints,\n): ZoomStateWithConstraints {\n let start = 0;\n let end = 100;\n let lastEmitted: ZoomRange | null = null;\n\n const listeners = new Set<ZoomRangeChangeCallback>();\n\n let minSpan = (() => {\n const v = Number.isFinite(constraints?.minSpan) ? (constraints!.minSpan as number) : DEFAULT_MIN_SPAN;\n return clamp(Number.isFinite(v) ? v : 0, 0, 100);\n })();\n\n let maxSpan = (() => {\n const v = Number.isFinite(constraints?.maxSpan) ? (constraints!.maxSpan as number) : DEFAULT_MAX_SPAN;\n return clamp(Number.isFinite(v) ? v : 100, 0, 100);\n })();\n\n let normalizedMinSpan = Math.min(minSpan, maxSpan);\n let normalizedMaxSpan = Math.max(minSpan, maxSpan);\n\n const emit = (): void => {\n const next: ZoomRange = { start, end };\n if (\n lastEmitted !== null &&\n lastEmitted.start === next.start &&\n lastEmitted.end === next.end\n ) {\n return;\n }\n\n lastEmitted = copyRange(next);\n\n // Emit to a snapshot so additions/removals during emit don't affect this flush.\n const snapshot = Array.from(listeners);\n for (const cb of snapshot) cb({ start, end });\n };\n\n const toAnchor = (nextStart: number, nextEnd: number, spec?: ZoomRangeAnchor): { readonly center: number; readonly ratio: number } | undefined => {\n if (!spec) return undefined;\n if (typeof spec === 'string') {\n switch (spec) {\n case 'start':\n return { center: nextStart, ratio: 0 };\n case 'end':\n return { center: nextEnd, ratio: 1 };\n case 'center':\n return { center: (nextStart + nextEnd) * 0.5, ratio: 0.5 };\n }\n }\n if (spec && Number.isFinite(spec.center) && Number.isFinite(spec.ratio)) {\n return { center: spec.center, ratio: spec.ratio };\n }\n return undefined;\n };\n\n const applyNextRange = (\n nextStart: number,\n nextEnd: number,\n options?: { readonly emit?: boolean; readonly anchor?: { readonly center: number; readonly ratio: number } },\n ): void => {\n if (!Number.isFinite(nextStart) || !Number.isFinite(nextEnd)) return;\n\n let s = nextStart;\n let e = nextEnd;\n\n if (s > e) {\n const t = s;\n s = e;\n e = t;\n }\n\n // Enforce span constraints by resizing around the proposed midpoint.\n let span = e - s;\n if (!Number.isFinite(span) || span < 0) return;\n\n const targetSpan = clamp(span, normalizedMinSpan, normalizedMaxSpan);\n if (targetSpan !== span) {\n const anchorCenter =\n options?.anchor && Number.isFinite(options.anchor.center)\n ? clamp(options.anchor.center, 0, 100)\n : (s + e) * 0.5;\n const anchorRatio =\n options?.anchor && Number.isFinite(options.anchor.ratio)\n ? clamp01(options.anchor.ratio)\n : 0.5;\n\n // Resize around the anchor so zoom operations preserve the cursor location.\n s = anchorCenter - anchorRatio * targetSpan;\n e = s + targetSpan;\n span = targetSpan;\n }\n\n // If span exceeds bounds (shouldn't happen with normalizedMaxSpan <= 100), clamp to full extent.\n if (span > 100) {\n s = 0;\n e = 100;\n span = 100;\n }\n\n // Shift into bounds without changing span.\n if (s < 0) {\n const shift = -s;\n s += shift;\n e += shift;\n }\n if (e > 100) {\n const shift = e - 100;\n s -= shift;\n e -= shift;\n }\n\n // Final clamp for tiny floating point drift.\n s = clamp(s, 0, 100);\n e = clamp(e, 0, 100);\n\n s = normalizeZero(s);\n e = normalizeZero(e);\n\n if (s === start && e === end) return;\n start = s;\n end = e;\n\n if (options?.emit === false) return;\n emit();\n };\n\n // Initialize state (no emit by default).\n applyNextRange(initialStart, initialEnd, { emit: false });\n\n const getRange: ZoomState['getRange'] = () => ({ start, end });\n\n const setRange: ZoomState['setRange'] = (nextStart, nextEnd) => {\n applyNextRange(nextStart, nextEnd);\n };\n\n const setRangeAnchored: ZoomStateWithConstraints['setRangeAnchored'] = (nextStart, nextEnd, anchor) => {\n applyNextRange(nextStart, nextEnd, { anchor: toAnchor(nextStart, nextEnd, anchor) });\n };\n\n const setSpanConstraints: ZoomStateWithConstraints['setSpanConstraints'] = (nextMinSpan, nextMaxSpan) => {\n // Undefined => leave unchanged (lets coordinator reapply dynamically computed values explicitly).\n const nextMin =\n typeof nextMinSpan === 'number' && Number.isFinite(nextMinSpan) ? clamp(nextMinSpan, 0, 100) : minSpan;\n const nextMax =\n typeof nextMaxSpan === 'number' && Number.isFinite(nextMaxSpan) ? clamp(nextMaxSpan, 0, 100) : maxSpan;\n\n if (nextMin === minSpan && nextMax === maxSpan) return;\n\n minSpan = nextMin;\n maxSpan = nextMax;\n normalizedMinSpan = Math.min(minSpan, maxSpan);\n normalizedMaxSpan = Math.max(minSpan, maxSpan);\n\n // If the current range violates the new constraints, clamp it.\n // Heuristic anchors keep \"pinned to start/end\" views stable (auto-scroll and common UX).\n const s = start;\n const e = end;\n const eps = 1e-6;\n const anchor: ZoomRangeAnchor =\n e >= 100 - eps ? 'end' : s <= 0 + eps ? 'start' : 'center';\n applyNextRange(s, e, { anchor: toAnchor(s, e, anchor) });\n };\n\n const zoomIn: ZoomState['zoomIn'] = (center, factor) => {\n if (!Number.isFinite(center) || !Number.isFinite(factor)) return;\n if (factor <= 1) return;\n\n const c = clamp(center, 0, 100);\n const span = end - start;\n const r = span === 0 ? 0.5 : clamp01((c - start) / span);\n const nextSpan = span / factor;\n const nextStart = c - r * nextSpan;\n const nextEnd = nextStart + nextSpan;\n applyNextRange(nextStart, nextEnd, { anchor: { center: c, ratio: r } });\n };\n\n const zoomOut: ZoomState['zoomOut'] = (center, factor) => {\n if (!Number.isFinite(center) || !Number.isFinite(factor)) return;\n if (factor <= 1) return;\n\n const c = clamp(center, 0, 100);\n const span = end - start;\n const r = span === 0 ? 0.5 : clamp01((c - start) / span);\n const nextSpan = span * factor;\n const nextStart = c - r * nextSpan;\n const nextEnd = nextStart + nextSpan;\n applyNextRange(nextStart, nextEnd, { anchor: { center: c, ratio: r } });\n };\n\n const pan: ZoomState['pan'] = (delta) => {\n if (!Number.isFinite(delta)) return;\n applyNextRange(start + delta, end + delta);\n };\n\n const onChange: ZoomState['onChange'] = (callback) => {\n listeners.add(callback);\n return () => {\n listeners.delete(callback);\n };\n };\n\n return { getRange, setRange, setRangeAnchored, setSpanConstraints, zoomIn, zoomOut, pan, onChange };\n}\n\n","import type { DataPoint, CartesianSeriesData } from '../config/types';\nimport type { ResolvedBarSeriesConfig, ResolvedSeriesConfig } from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { computeBarLayoutPx } from './findNearestPoint';\nimport { getPointCount, getX, getY, getSize } from '../data/cartesianData';\n\nexport type PointsAtXMatch = Readonly<{\n seriesIndex: number;\n dataIndex: number;\n point: DataPoint;\n}>;\n\nconst hasNaNXCache = new WeakMap<object, boolean>();\n\nconst seriesHasNaNX = (data: CartesianSeriesData): boolean => {\n // Use data object as cache key (works for arrays, typed arrays, and XYArraysData)\n const cacheKey = typeof data === 'object' && data !== null ? data : null;\n if (cacheKey && hasNaNXCache.has(cacheKey)) {\n return hasNaNXCache.get(cacheKey)!;\n }\n\n let hasNaN = false;\n const n = getPointCount(data);\n\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n if (Number.isNaN(x)) {\n hasNaN = true;\n break;\n }\n }\n\n if (cacheKey) hasNaNXCache.set(cacheKey, hasNaN);\n return hasNaN;\n};\n\ntype BarHitTestLayout = Readonly<{\n /** bar width in xScale range units (grid-local CSS px) */\n barWidth: number;\n /** gap between cluster slots, in xScale range units */\n gap: number;\n /** total cluster width (all bar slots), in xScale range units */\n clusterWidth: number;\n /** maps global series index -> cluster slot index */\n clusterIndexByGlobalSeriesIndex: ReadonlyMap<number, number>;\n}>;\n\nconst computeBarHitTestLayout = (\n series: ReadonlyArray<ResolvedSeriesConfig>,\n xScale: LinearScale\n): BarHitTestLayout | null => {\n // Mirror the bar renderer's shared layout math via `computeBarLayoutPx(...)`, but in xScale range units.\n // IMPORTANT: Bar layout depends on all bar series (stacking + grouped slots), not per-series.\n const barSeries: { readonly globalSeriesIndex: number; readonly s: ResolvedBarSeriesConfig }[] = [];\n for (let i = 0; i < series.length; i++) {\n const s = series[i];\n if (s?.type === 'bar') barSeries.push({ globalSeriesIndex: i, s });\n }\n if (barSeries.length === 0) return null;\n\n const layout = computeBarLayoutPx(\n barSeries.map((b) => b.s),\n xScale\n );\n\n const barWidthRange = layout.barWidthPx;\n const gap = layout.gapPx;\n const clusterWidth = layout.clusterWidthPx;\n if (!Number.isFinite(barWidthRange) || !(barWidthRange > 0)) return null;\n\n const clusterIndexByGlobalSeriesIndex = new Map<number, number>();\n for (let i = 0; i < barSeries.length; i++) {\n const globalSeriesIndex = barSeries[i].globalSeriesIndex;\n const clusterIndex = layout.clusterSlots.clusterIndexBySeries[i] ?? 0;\n clusterIndexByGlobalSeriesIndex.set(globalSeriesIndex, clusterIndex);\n }\n\n return {\n barWidth: barWidthRange,\n gap,\n clusterWidth,\n clusterIndexByGlobalSeriesIndex,\n };\n};\n\nconst lowerBoundX = (data: CartesianSeriesData, xTarget: number): number => {\n let lo = 0;\n let hi = getPointCount(data);\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = getX(data, mid);\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\n/**\n * Finds (at most) one nearest point per series at a given x position.\n *\n * Coordinate system contract (mirrors `findNearestPoint`):\n * - `xValue` and optional `tolerance` MUST be in the same units as `xScale` **range**.\n * (Example: if your `xScale.range()` is in grid-local CSS pixels, pass `payload.gridX` from `createEventManager`.)\n * Note: ChartGPU's internal renderer scales are currently in clip space (NDC, typically \\[-1, 1\\]); in that case\n * convert your pointer x into clip space before calling this helper.\n *\n * Behavior:\n * - Assumes each series is sorted by increasing x in domain space.\n * - Uses a lower-bound binary search in domain-x, then expands outward while x-distance alone can still improve.\n * - Skips points with non-finite domain x or non-finite scaled x. If a series contains any NaN x values, this helper\n * falls back to an O(n) scan for correctness (NaN breaks total ordering for binary search).\n * - Stable tie-breaking: for equal distance, chooses the smaller `dataIndex`.\n *\n * If `tolerance` is provided, it is interpreted in **xScale range units**. Matches beyond tolerance are omitted.\n * If `tolerance` is omitted (or non-finite), the nearest point per series is returned when possible.\n *\n * Bar series special-case:\n * - Bars occupy x-intervals \\([left, right)\\) in **xScale range units** (grid-local CSS px for interaction scales),\n * using the same shared layout math as the bar renderer (grouping + stacking slots).\n * - If `tolerance` is finite, a bar match is only returned when `xValue` falls inside the bar interval expanded by\n * `tolerance` on both sides: \\([left - tolerance, right + tolerance)\\).\n * - If `tolerance` is omitted / non-finite, we first attempt an exact interval hit (no expansion) and otherwise fall\n * back to the existing nearest-x behavior (so axis-trigger tooltips still work away from bars).\n */\nexport function findPointsAtX(\n series: ReadonlyArray<ResolvedSeriesConfig>,\n xValue: number,\n xScale: LinearScale,\n tolerance?: number,\n): ReadonlyArray<PointsAtXMatch> {\n if (!Number.isFinite(xValue)) return [];\n\n const maxDx =\n tolerance === undefined || !Number.isFinite(tolerance) ? Number.POSITIVE_INFINITY : Math.max(0, tolerance);\n const maxDxSq = maxDx * maxDx;\n\n const xTarget = xScale.invert(xValue);\n if (!Number.isFinite(xTarget)) return [];\n\n const matches: PointsAtXMatch[] = [];\n const barLayout = computeBarHitTestLayout(series, xScale);\n\n for (let s = 0; s < series.length; s++) {\n const seriesConfig = series[s];\n // Pie and candlestick are non-cartesian (or not yet implemented); they can't match an x position.\n if (seriesConfig.type === 'pie' || seriesConfig.type === 'candlestick') continue;\n\n // Skip invisible series.\n if (seriesConfig.visible === false) continue;\n\n const data = seriesConfig.data as CartesianSeriesData;\n const n = getPointCount(data);\n if (n === 0) continue;\n\n // Bar series: return the correct bar dataIndex for xValue when inside the bar interval.\n // When tolerance is finite: require an (expanded) interval hit.\n // When tolerance is non-finite: attempt exact hit, otherwise fall back to nearest-x behavior below.\n if (seriesConfig.type === 'bar' && barLayout) {\n const clusterIndex = barLayout.clusterIndexByGlobalSeriesIndex.get(s);\n if (clusterIndex !== undefined) {\n const { barWidth, gap, clusterWidth } = barLayout;\n const offsetLeftFromCategoryCenter = -clusterWidth / 2 + clusterIndex * (barWidth + gap);\n\n const hitTol =\n tolerance === undefined || !Number.isFinite(tolerance) ? 0 : Math.max(0, tolerance);\n\n // If we can't safely compute an interval hit, don't guess when tolerance is finite.\n if (Number.isFinite(barWidth) && barWidth > 0 && Number.isFinite(offsetLeftFromCategoryCenter)) {\n let hitIndex = -1;\n\n const isHit = (xCenterRange: number): boolean => {\n if (!Number.isFinite(xCenterRange)) return false;\n const left = xCenterRange + offsetLeftFromCategoryCenter;\n const right = left + barWidth;\n // Expanded interval: [left - tol, right + tol)\n return xValue >= left - hitTol && xValue < right + hitTol;\n };\n\n if (seriesHasNaNX(data)) {\n // NaN breaks ordering; linear scan for correctness.\n for (let i = 0; i < n; i++) {\n const px = getX(data, i);\n if (!Number.isFinite(px)) continue;\n const xCenter = xScale.scale(px);\n if (isHit(xCenter)) {\n hitIndex = hitIndex < 0 ? i : Math.min(hitIndex, i);\n }\n }\n } else {\n // Use a lower-bound search around the adjusted x (accounts for cluster offset).\n const xTargetAdjusted = xScale.invert(xValue - offsetLeftFromCategoryCenter);\n if (Number.isFinite(xTargetAdjusted)) {\n const insertionIndex = lowerBoundX(data, xTargetAdjusted);\n\n const getXCenterAt = (idx: number): number | null => {\n if (idx < 0 || idx >= n) return null;\n const px = getX(data, idx);\n if (!Number.isFinite(px)) return null;\n const xCenter = xScale.scale(px);\n return Number.isFinite(xCenter) ? xCenter : null;\n };\n\n // Scan left while intervals could still contain xValue.\n for (let i = insertionIndex - 1; i >= 0; i--) {\n const xCenter = getXCenterAt(i);\n if (xCenter === null) continue;\n const left = xCenter + offsetLeftFromCategoryCenter;\n const right = left + barWidth;\n if (right + hitTol <= xValue) break;\n if (xValue >= left - hitTol && xValue < right + hitTol) {\n hitIndex = hitIndex < 0 ? i : Math.min(hitIndex, i);\n }\n }\n\n // Scan right until intervals start strictly after xValue.\n for (let i = insertionIndex; i < n; i++) {\n const xCenter = getXCenterAt(i);\n if (xCenter === null) continue;\n const left = xCenter + offsetLeftFromCategoryCenter;\n if (left - hitTol > xValue) break;\n const right = left + barWidth;\n if (xValue < right + hitTol) {\n hitIndex = hitIndex < 0 ? i : Math.min(hitIndex, i);\n }\n }\n }\n }\n\n if (hitIndex >= 0) {\n const x = getX(data, hitIndex);\n const y = getY(data, hitIndex);\n const size = getSize(data, hitIndex);\n const point: DataPoint = size !== undefined ? [x, y, size] : [x, y];\n matches.push({ seriesIndex: s, dataIndex: hitIndex, point });\n continue;\n }\n\n // If tolerance is finite, require a hit (no nearest-x fallback).\n if (tolerance !== undefined && Number.isFinite(tolerance)) {\n continue;\n }\n // Else: fall through to nearest-x behavior (existing logic) for axis-trigger tooltips.\n } else if (tolerance !== undefined && Number.isFinite(tolerance)) {\n continue;\n }\n }\n }\n\n let bestDataIndex = -1;\n let bestPoint: DataPoint | null = null;\n let bestDxSq = maxDxSq;\n\n const tryUpdate = (idx: number, dxSq: number) => {\n if (!Number.isFinite(dxSq)) return;\n const isBetter =\n dxSq < bestDxSq || (dxSq === bestDxSq && (bestDataIndex < 0 || idx < bestDataIndex));\n if (!isBetter) return;\n bestDxSq = dxSq;\n bestDataIndex = idx;\n // Construct DataPoint for return\n const x = getX(data, idx);\n const y = getY(data, idx);\n const size = getSize(data, idx);\n bestPoint = size !== undefined ? [x, y, size] : [x, y];\n };\n\n // If the series contains NaN x values, binary search cannot be trusted (NaN breaks ordering).\n // Fall back to a linear scan for correctness. Cached per data array for performance.\n if (seriesHasNaNX(data)) {\n for (let i = 0; i < n; i++) {\n const px = getX(data, i);\n if (!Number.isFinite(px)) continue;\n const sx = xScale.scale(px);\n if (!Number.isFinite(sx)) continue;\n const dx = sx - xValue;\n tryUpdate(i, dx * dx);\n }\n } else {\n const insertionIndex = lowerBoundX(data, xTarget);\n\n let left = insertionIndex - 1;\n let right = insertionIndex;\n\n const dxSqAt = (idx: number): number | null => {\n const px = getX(data, idx);\n if (!Number.isFinite(px)) return null;\n const sx = xScale.scale(px);\n if (!Number.isFinite(sx)) return null;\n const dx = sx - xValue;\n return dx * dx;\n };\n\n while (left >= 0 || right < n) {\n while (left >= 0 && dxSqAt(left) === null) left--;\n while (right < n && dxSqAt(right) === null) right++;\n if (left < 0 && right >= n) break;\n\n const dxSqLeft = left >= 0 ? (dxSqAt(left) ?? Number.POSITIVE_INFINITY) : Number.POSITIVE_INFINITY;\n const dxSqRight = right < n ? (dxSqAt(right) ?? Number.POSITIVE_INFINITY) : Number.POSITIVE_INFINITY;\n\n if (dxSqLeft > bestDxSq && dxSqRight > bestDxSq) break;\n\n // If both sides are equally close in x, evaluate left first (smaller index) for stable ties.\n if (dxSqLeft <= dxSqRight) {\n if (left >= 0 && dxSqLeft <= bestDxSq) tryUpdate(left, dxSqLeft);\n left--;\n if (right < n && dxSqRight <= bestDxSq && dxSqRight === dxSqLeft) {\n tryUpdate(right, dxSqRight);\n right++;\n }\n } else {\n if (right < n && dxSqRight <= bestDxSq) tryUpdate(right, dxSqRight);\n right++;\n }\n }\n }\n\n if (bestPoint !== null) matches.push({ seriesIndex: s, dataIndex: bestDataIndex, point: bestPoint });\n }\n\n return matches;\n}\n\n","import type { ResolvedCandlestickSeriesConfig } from '../config/OptionResolver';\nimport type { OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\n\nexport interface CandlestickMatch {\n seriesIndex: number;\n dataIndex: number;\n point: OHLCDataPoint;\n}\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\nconst parsePercent = (value: string): number | null => {\n const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n if (!m) return null;\n const p = Number(m[1]) / 100;\n return Number.isFinite(p) ? p : null;\n};\n\nconst isTupleDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getTimestamp = (p: OHLCDataPoint): number => (isTupleDataPoint(p) ? p[0] : p.timestamp);\nconst getOpen = (p: OHLCDataPoint): number => (isTupleDataPoint(p) ? p[1] : p.open);\nconst getClose = (p: OHLCDataPoint): number => (isTupleDataPoint(p) ? p[2] : p.close);\n\nconst categoryStepCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, number>();\n\nconst computeCategoryStep = (data: ReadonlyArray<OHLCDataPoint>): number => {\n const cached = categoryStepCache.get(data);\n if (cached !== undefined) return cached;\n\n const timestamps: number[] = [];\n for (let i = 0; i < data.length; i++) {\n const t = getTimestamp(data[i]);\n if (Number.isFinite(t)) timestamps.push(t);\n }\n\n if (timestamps.length < 2) return 1;\n timestamps.sort((a, b) => a - b);\n\n let minStep = Number.POSITIVE_INFINITY;\n for (let i = 1; i < timestamps.length; i++) {\n const d = timestamps[i] - timestamps[i - 1];\n if (d > 0 && d < minStep) minStep = d;\n }\n const step = Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n categoryStepCache.set(data, step);\n return step;\n};\n\n/**\n * Computes the candlestick body width in xScale **range-space** units.\n *\n * Notes:\n * - This mirrors `createCandlestickRenderer.ts` bar width semantics, but stays in range units\n * (CSS pixels in ChartGPU interaction usage).\n * - No DPR conversions are applied here.\n */\nexport function computeCandlestickBodyWidthRange(\n series: ResolvedCandlestickSeriesConfig,\n data: ReadonlyArray<OHLCDataPoint>,\n xScale: LinearScale,\n plotWidthFallback?: number,\n): number {\n if (data.length === 0) return 0;\n\n const categoryStep = computeCategoryStep(data);\n\n // Prefer deriving category width from a domain step via xScale.scale(t0 + step) - xScale.scale(t0).\n let categoryWidthRange = 0;\n if (Number.isFinite(categoryStep) && categoryStep > 0) {\n let t0: number | null = null;\n for (let i = 0; i < data.length; i++) {\n const t = getTimestamp(data[i]);\n if (Number.isFinite(t)) {\n t0 = t;\n break;\n }\n }\n\n if (t0 != null) {\n const p0 = xScale.scale(t0);\n const p1 = xScale.scale(t0 + categoryStep);\n const w = Math.abs(p1 - p0);\n if (Number.isFinite(w) && w > 0) categoryWidthRange = w;\n }\n }\n\n // Fallback: approximate based on plot width and data length.\n if (!(categoryWidthRange > 0) || !Number.isFinite(categoryWidthRange)) {\n const plotW = Number.isFinite(plotWidthFallback ?? Number.NaN) ? (plotWidthFallback as number) : 0;\n categoryWidthRange = plotW / Math.max(1, data.length);\n }\n\n // barWidth semantics:\n // - number: width in range units\n // - percent string: percent of category width in range units\n let width = 0;\n const rawBarWidth = series.barWidth;\n if (typeof rawBarWidth === 'number') {\n width = Number.isFinite(rawBarWidth) ? Math.max(0, rawBarWidth) : 0;\n } else if (typeof rawBarWidth === 'string') {\n const p = parsePercent(rawBarWidth);\n width = p == null ? 0 : categoryWidthRange * clamp01(p);\n }\n\n // Clamp by min/max width (in CSS px; our range-space is CSS px in interaction usage).\n const minW = Number.isFinite(series.barMinWidth) ? Math.max(0, series.barMinWidth) : 0;\n const maxWCandidate = Number.isFinite(series.barMaxWidth) ? Math.max(0, series.barMaxWidth) : Number.POSITIVE_INFINITY;\n const maxW = Math.max(minW, maxWCandidate);\n width = Math.min(Math.max(width, minW), maxW);\n\n return Number.isFinite(width) ? width : 0;\n}\n\nconst monotonicTimestampCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, boolean>();\n\nconst isMonotonicNonDecreasingFiniteTimestamps = (data: ReadonlyArray<OHLCDataPoint>): boolean => {\n const cached = monotonicTimestampCache.get(data);\n if (cached !== undefined) return cached;\n\n let prev = Number.NEGATIVE_INFINITY;\n for (let i = 0; i < data.length; i++) {\n const t = getTimestamp(data[i]);\n if (!Number.isFinite(t)) {\n monotonicTimestampCache.set(data, false);\n return false;\n }\n if (t < prev) {\n monotonicTimestampCache.set(data, false);\n return false;\n }\n prev = t;\n }\n monotonicTimestampCache.set(data, true);\n return true;\n};\n\nconst lowerBoundByTimestamp = (data: ReadonlyArray<OHLCDataPoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const t = getTimestamp(data[mid]);\n if (t < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\n/**\n * Finds the candlestick body under the given cursor position.\n *\n * Coordinate system contract:\n * - `x`/`y` MUST be in the same units as `xScale`/`yScale` **range-space**\n * (ChartGPU interaction uses grid-local CSS pixels).\n *\n * Hit-test semantics:\n * - Body-only hit-testing (wicks ignored).\n * - A candle hits if:\n * - `abs(x - xCenter) <= barWidth / 2`, AND\n * - `y` is between the scaled `open` and `close` (inclusive).\n *\n * Performance:\n * - Per-series lower-bound binary search on timestamp, then scans left/right while x-distance alone can still hit.\n * - If timestamps are not monotonic non-decreasing finite numbers, falls back to an O(n) scan for correctness.\n *\n * Edge cases:\n * - Skips non-finite timestamps/open/close.\n * - If `barWidthClip` is non-finite or <= 0, returns null.\n * - Returns the closest in x (min abs dx) among hits; ties broken by smaller `dataIndex` (then smaller `seriesIndex`).\n */\nexport function findCandlestick(\n series: ReadonlyArray<ResolvedCandlestickSeriesConfig>,\n x: number,\n y: number,\n xScale: LinearScale,\n yScale: LinearScale,\n barWidthClip: number,\n): CandlestickMatch | null {\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n if (!Number.isFinite(barWidthClip) || !(barWidthClip > 0)) return null;\n\n const xTarget = xScale.invert(x);\n if (!Number.isFinite(xTarget)) return null;\n\n const halfW = barWidthClip / 2;\n\n let best: CandlestickMatch | null = null;\n let bestDx = Number.POSITIVE_INFINITY;\n\n const tryUpdate = (\n seriesIndex: number,\n dataIndex: number,\n point: OHLCDataPoint,\n dx: number,\n ): void => {\n if (!Number.isFinite(dx)) return;\n if (dx < bestDx) {\n bestDx = dx;\n best = { seriesIndex, dataIndex, point };\n return;\n }\n if (dx === bestDx && best) {\n if (dataIndex < best.dataIndex) {\n best = { seriesIndex, dataIndex, point };\n } else if (dataIndex === best.dataIndex && seriesIndex < best.seriesIndex) {\n best = { seriesIndex, dataIndex, point };\n }\n }\n };\n\n const isBodyHitAt = (p: OHLCDataPoint): boolean => {\n const open = getOpen(p);\n const close = getClose(p);\n if (!Number.isFinite(open) || !Number.isFinite(close)) return false;\n\n const yOpen = yScale.scale(open);\n const yClose = yScale.scale(close);\n if (!Number.isFinite(yOpen) || !Number.isFinite(yClose)) return false;\n\n const yMin = Math.min(yOpen, yClose);\n const yMax = Math.max(yOpen, yClose);\n return y >= yMin && y <= yMax;\n };\n\n for (let s = 0; s < series.length; s++) {\n const cfg = series[s];\n const data = cfg.data;\n const n = data.length;\n if (n === 0) continue;\n\n const monotonic = isMonotonicNonDecreasingFiniteTimestamps(data);\n\n if (!monotonic) {\n // Fallback O(n) scan for correctness.\n for (let i = 0; i < n; i++) {\n const p = data[i];\n const t = getTimestamp(p);\n if (!Number.isFinite(t)) continue;\n const xCenter = xScale.scale(t);\n if (!Number.isFinite(xCenter)) continue;\n\n const dx = Math.abs(x - xCenter);\n if (dx > halfW) continue;\n if (!isBodyHitAt(p)) continue;\n\n tryUpdate(s, i, p, dx);\n }\n continue;\n }\n\n const insertionIndex = lowerBoundByTimestamp(data, xTarget);\n\n // Scan left while xCenter can still be within [x - halfW, x + halfW].\n for (let i = insertionIndex - 1; i >= 0; i--) {\n const p = data[i];\n const t = getTimestamp(p);\n const xCenter = xScale.scale(t);\n if (!Number.isFinite(xCenter)) continue;\n if (xCenter < x - halfW) break;\n\n const dx = Math.abs(x - xCenter);\n if (dx > halfW) continue;\n if (!isBodyHitAt(p)) continue;\n\n tryUpdate(s, i, p, dx);\n }\n\n // Scan right while xCenter can still be within [x - halfW, x + halfW].\n for (let i = insertionIndex; i < n; i++) {\n const p = data[i];\n const t = getTimestamp(p);\n const xCenter = xScale.scale(t);\n if (!Number.isFinite(xCenter)) continue;\n if (xCenter > x + halfW) break;\n\n const dx = Math.abs(x - xCenter);\n if (dx > halfW) continue;\n if (!isBodyHitAt(p)) continue;\n\n tryUpdate(s, i, p, dx);\n }\n }\n\n return best;\n}\n\n","import type { ResolvedPieSeriesConfig } from '../config/OptionResolver';\n\nconst TAU = Math.PI * 2;\n\nconst wrapToTau = (thetaRad: number): number => {\n if (!Number.isFinite(thetaRad)) return 0;\n const t = thetaRad % TAU;\n return t < 0 ? t + TAU : t;\n};\n\nexport type PieSliceMatch = Readonly<{\n seriesIndex: number;\n dataIndex: number;\n slice: ResolvedPieSeriesConfig['data'][number];\n}>;\n\nexport type PieHitTestConfig = Readonly<{\n seriesIndex: number;\n series: ResolvedPieSeriesConfig;\n}>;\n\nexport type PieCenterCssPx = Readonly<{ x: number; y: number }>;\nexport type PieRadiusCssPx = Readonly<{ inner: number; outer: number }>;\n\n/**\n * Finds the pie slice under a given pointer position.\n *\n * Coordinate contract:\n * - `x`/`y` are plot/grid-local CSS pixels (origin at plot top-left, +y down).\n * - `center` is plot-local CSS pixels.\n * - `radius` is CSS pixels (inner/outer). Points within the donut hole are not hoverable.\n *\n * Angle conventions:\n * - Uses +y up for polar angle (to match `pie.wgsl` atan2(p.y, p.x)).\n * - Wraps angles to [0, 2π).\n * - Matches `createPieRenderer.ts` start angle default (90°).\n *\n * Value conventions:\n * - Ignores non-finite and non-positive slice values (mirrors renderer).\n */\nexport function findPieSlice(\n x: number,\n y: number,\n pieConfig: PieHitTestConfig,\n center: PieCenterCssPx,\n radius: PieRadiusCssPx\n): PieSliceMatch | null {\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n if (!Number.isFinite(center.x) || !Number.isFinite(center.y)) return null;\n\n const inner = Number.isFinite(radius.inner) ? Math.max(0, radius.inner) : 0;\n const outer = Number.isFinite(radius.outer) ? Math.max(0, radius.outer) : 0;\n if (!(outer > 0)) return null;\n\n // Polar coordinates:\n // - Pointer `y` is down in CSS px, but shader uses +y up (atan2(p.y, p.x)).\n const dx = x - center.x;\n const dyUp = center.y - y;\n const r = Math.hypot(dx, dyUp);\n if (!Number.isFinite(r)) return null;\n\n // Donut hole is non-hoverable; outer bound must be inside.\n if (r <= inner) return null;\n if (r > outer) return null;\n\n const angle = wrapToTau(Math.atan2(dyUp, dx));\n\n const series = pieConfig.series;\n const data = series.data;\n\n // Total positive value for angle allocation (mirrors renderer, exclude hidden slices).\n let total = 0;\n let validCount = 0;\n for (let i = 0; i < data.length; i++) {\n const item = data[i];\n const v = item?.value;\n if (typeof v === 'number' && Number.isFinite(v) && v > 0 && item.visible !== false) {\n total += v;\n validCount++;\n }\n }\n if (!(total > 0) || validCount === 0) return null;\n\n const startDeg =\n typeof series.startAngle === 'number' && Number.isFinite(series.startAngle) ? series.startAngle : 90;\n let current = wrapToTau((startDeg * Math.PI) / 180);\n\n // Mirror renderer float-drift mitigation: force last slice to close the circle.\n let accumulated = 0;\n let emitted = 0;\n\n for (let i = 0; i < data.length; i++) {\n const slice = data[i];\n const v = slice?.value;\n if (typeof v !== 'number' || !Number.isFinite(v) || v <= 0) continue;\n // Skip hidden slices\n if (slice?.visible === false) continue;\n\n emitted++;\n const isLast = emitted === validCount;\n\n const frac = v / total;\n let span = frac * TAU;\n if (isLast) {\n span = Math.max(0, TAU - accumulated);\n } else {\n span = Math.max(0, Math.min(TAU, span));\n }\n accumulated += span;\n if (!(span > 0)) continue;\n\n const start = current;\n // When there's only one visible slice, it should span the full circle (0 to TAU).\n // Don't wrap the end angle in this case, as wrapping (start + TAU) gives start again.\n const end = validCount === 1 ? current + TAU : wrapToTau(current + span);\n current = wrapToTau(current + span);\n\n // Match `pie.wgsl` wedge test (span and rel in [0, TAU) with wrap).\n let wedgeSpan = end - start;\n if (wedgeSpan < 0) wedgeSpan += TAU;\n\n let rel = angle - start;\n if (rel < 0) rel += TAU;\n\n if (rel <= wedgeSpan) {\n return { seriesIndex: pieConfig.seriesIndex, dataIndex: i, slice };\n }\n }\n\n return null;\n}\n\n","export interface LinearScale {\n /**\n * Sets the scale domain (data range). Returns self for chaining.\n */\n domain(min: number, max: number): LinearScale;\n\n /**\n * Sets the scale range (pixel range). Returns self for chaining.\n */\n range(min: number, max: number): LinearScale;\n\n /**\n * Maps a domain value to a range value.\n *\n * Notes:\n * - No clamping (will extrapolate outside the domain).\n * - If the domain span is 0 (min === max), returns the midpoint of the range.\n */\n scale(value: number): number;\n\n /**\n * Maps a range value (pixel) back to a domain value.\n *\n * Notes:\n * - No clamping (will extrapolate outside the range).\n * - If the domain span is 0 (min === max), returns domain min for any input.\n */\n invert(pixel: number): number;\n}\n\nexport interface CategoryScale {\n /**\n * Sets the category domain (ordered list of unique category names).\n * Returns self for chaining.\n *\n * Throws if duplicates exist (ambiguous mapping).\n */\n domain(categories: string[]): CategoryScale;\n\n /**\n * Sets the scale range (pixel range). Returns self for chaining.\n */\n range(min: number, max: number): CategoryScale;\n\n /**\n * Returns the center x-position for a category.\n *\n * Edge cases:\n * - Unknown category: returns NaN\n * - Empty domain: returns midpoint of range\n */\n scale(category: string): number;\n\n /**\n * Width allocated per category (always non-negative).\n *\n * Edge cases:\n * - Empty domain: returns 0\n * - Reversed ranges allowed\n */\n bandwidth(): number;\n\n /**\n * Returns the index of a category in the current domain.\n *\n * Edge cases:\n * - Unknown category: returns -1\n */\n categoryIndex(category: string): number;\n}\n\nconst assertFinite = (label: string, value: number): void => {\n if (!Number.isFinite(value)) {\n throw new Error(`${label} must be a finite number. Received: ${String(value)}`);\n }\n};\n\n/**\n * Creates a linear scale for mapping a numeric domain to a numeric range.\n *\n * Defaults to an identity mapping:\n * domain [0, 1] -> range [0, 1]\n */\nexport function createLinearScale(): LinearScale {\n let domainMin = 0;\n let domainMax = 1;\n let rangeMin = 0;\n let rangeMax = 1;\n\n const self: LinearScale = {\n domain(min: number, max: number) {\n assertFinite('domain min', min);\n assertFinite('domain max', max);\n domainMin = min;\n domainMax = max;\n return self;\n },\n\n range(min: number, max: number) {\n assertFinite('range min', min);\n assertFinite('range max', max);\n rangeMin = min;\n rangeMax = max;\n return self;\n },\n\n scale(value: number) {\n if (!Number.isFinite(value)) return Number.NaN;\n\n if (domainMin === domainMax) {\n return (rangeMin + rangeMax) / 2;\n }\n\n const t = (value - domainMin) / (domainMax - domainMin);\n return rangeMin + t * (rangeMax - rangeMin);\n },\n\n invert(pixel: number) {\n if (!Number.isFinite(pixel)) return Number.NaN;\n\n if (domainMin === domainMax) {\n return domainMin;\n }\n\n if (rangeMin === rangeMax) {\n return (domainMin + domainMax) / 2;\n }\n\n const t = (pixel - rangeMin) / (rangeMax - rangeMin);\n return domainMin + t * (domainMax - domainMin);\n },\n };\n\n return self;\n}\n\n/**\n * Creates a category scale for mapping string categories to evenly spaced\n * x-positions across a numeric range.\n *\n * Defaults:\n * - domain: []\n * - range: [0, 1]\n */\nexport function createCategoryScale(): CategoryScale {\n let categories: readonly string[] = [];\n let indexByCategory = new Map<string, number>();\n let rangeMin = 0;\n let rangeMax = 1;\n\n const rebuildIndex = (nextCategories: readonly string[]) => {\n const nextIndex = new Map<string, number>();\n for (let i = 0; i < nextCategories.length; i++) {\n const c = nextCategories[i];\n // Enforce uniqueness to avoid ambiguous mapping\n if (nextIndex.has(c)) {\n throw new Error(`Category domain must not contain duplicates. Duplicate: ${JSON.stringify(c)}`);\n }\n nextIndex.set(c, i);\n }\n indexByCategory = nextIndex;\n };\n\n const self: CategoryScale = {\n domain(nextCategories: string[]) {\n categories = [...nextCategories];\n rebuildIndex(categories);\n return self;\n },\n\n range(min: number, max: number) {\n assertFinite('range min', min);\n assertFinite('range max', max);\n rangeMin = min;\n rangeMax = max;\n return self;\n },\n\n categoryIndex(category: string) {\n const idx = indexByCategory.get(category);\n return idx === undefined ? -1 : idx;\n },\n\n bandwidth() {\n const n = categories.length;\n if (n === 0) return 0;\n return Math.abs((rangeMax - rangeMin) / n);\n },\n\n scale(category: string) {\n const n = categories.length;\n if (n === 0) {\n return (rangeMin + rangeMax) / 2;\n }\n\n const i = self.categoryIndex(category);\n if (i < 0) return Number.NaN;\n\n const step = (rangeMax - rangeMin) / n; // can be negative (reversed range)\n return rangeMin + (i + 0.5) * step;\n },\n };\n\n return self;\n}\n","export type TextOverlayAnchor = 'start' | 'middle' | 'end';\n\nexport interface TextOverlayLabelOptions {\n readonly fontSize?: number;\n readonly color?: string;\n readonly anchor?: TextOverlayAnchor;\n /**\n * Rotation in degrees (CSS `rotate(<deg>deg)`).\n */\n readonly rotation?: number;\n}\n\nexport interface TextOverlay {\n clear(): void;\n addLabel(\n text: string,\n x: number,\n y: number,\n options?: TextOverlayLabelOptions\n ): HTMLSpanElement;\n dispose(): void;\n}\n\nconst getAnchorTransform = (\n anchor: TextOverlayAnchor\n): Readonly<{ translateX: string; originX: string }> => {\n switch (anchor) {\n case 'start':\n return { translateX: '0%', originX: '0%' };\n case 'middle':\n return { translateX: '-50%', originX: '50%' };\n case 'end':\n return { translateX: '-100%', originX: '100%' };\n }\n};\n\nexport function createTextOverlay(container: HTMLElement): TextOverlay {\n const computedStyle = getComputedStyle(container);\n const computedPosition = computedStyle.position;\n const computedOverflow = computedStyle.overflow;\n\n const didSetRelative = computedPosition === 'static';\n const didSetOverflowVisible = computedOverflow === 'hidden' || computedOverflow === 'scroll' || computedOverflow === 'auto';\n\n const previousInlinePosition = didSetRelative ? container.style.position : null;\n const previousInlineOverflow = didSetOverflowVisible ? container.style.overflow : null;\n\n if (didSetRelative) {\n container.style.position = 'relative';\n }\n\n if (didSetOverflowVisible) {\n container.style.overflow = 'visible';\n }\n\n const overlay = document.createElement('div');\n overlay.style.position = 'absolute';\n overlay.style.inset = '0';\n overlay.style.pointerEvents = 'none';\n overlay.style.overflow = 'visible';\n overlay.style.zIndex = '10'; // Above zoom slider (z-index: 4) and other overlays\n container.appendChild(overlay);\n\n let disposed = false;\n\n const clear = (): void => {\n if (disposed) return;\n overlay.replaceChildren();\n };\n\n const addLabel: TextOverlay['addLabel'] = (text, x, y, options) => {\n if (disposed) {\n // Keep it non-throwing so callsites don't need try/catch in teardown paths.\n return document.createElement('span');\n }\n\n const span = document.createElement('span');\n span.textContent = text;\n span.style.position = 'absolute';\n span.style.left = `${x}px`;\n span.style.top = `${y}px`;\n span.style.pointerEvents = 'none';\n span.style.userSelect = 'none';\n span.style.whiteSpace = 'nowrap';\n span.style.lineHeight = '1';\n\n if (options?.fontSize != null) span.style.fontSize = `${options.fontSize}px`;\n if (options?.color != null) span.style.color = options.color;\n\n const rotation = options?.rotation ?? 0;\n const anchor = options?.anchor ?? 'start';\n const { translateX, originX } = getAnchorTransform(anchor);\n\n span.style.transformOrigin = `${originX} 50%`;\n span.style.transform = `translateX(${translateX}) translateY(-50%) rotate(${rotation}deg)`;\n\n overlay.appendChild(span);\n return span;\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n\n try {\n overlay.remove();\n } finally {\n if (previousInlinePosition !== null) {\n container.style.position = previousInlinePosition;\n }\n if (previousInlineOverflow !== null) {\n container.style.overflow = previousInlineOverflow;\n }\n }\n };\n\n return { clear, addLabel, dispose };\n}\n\n ","import type { SeriesConfig } from '../config/types';\nimport type { ThemeConfig } from '../themes/types';\n\nexport type LegendPosition = 'top' | 'bottom' | 'left' | 'right';\n\nexport interface Legend {\n update(series: ReadonlyArray<SeriesConfig>, theme: ThemeConfig): void;\n dispose(): void;\n}\n\nconst getSeriesName = (series: SeriesConfig, index: number): string => {\n const candidate = series.name?.trim();\n return candidate ? candidate : `Series ${index + 1}`;\n};\n\nconst getSeriesColor = (\n series: SeriesConfig,\n index: number,\n theme: ThemeConfig\n): string => {\n const explicit = series.color?.trim();\n if (explicit) return explicit;\n\n const palette = theme.colorPalette;\n if (palette.length > 0) return palette[index % palette.length] ?? '#000000';\n return '#000000';\n};\n\nconst getPieSliceLabel = (sliceName: string | undefined, sliceIndex: number): string => {\n const candidate = sliceName?.trim();\n return candidate ? candidate : `Slice ${sliceIndex + 1}`;\n};\n\nconst getPieSliceColor = (\n sliceColor: string | undefined,\n seriesIndex: number,\n sliceIndex: number,\n theme: ThemeConfig\n): string => {\n const explicit = sliceColor?.trim();\n if (explicit) return explicit;\n\n const palette = theme.colorPalette;\n const len = palette.length;\n if (len > 0) return palette[(seriesIndex + sliceIndex) % len] ?? '#000000';\n return '#000000';\n};\n\nexport function createLegend(\n container: HTMLElement,\n position: LegendPosition = 'right',\n onSeriesToggle?: (seriesIndex: number, sliceIndex?: number) => void\n): Legend {\n const computedPosition = getComputedStyle(container).position;\n const didSetRelative = computedPosition === 'static';\n const previousInlinePosition = didSetRelative ? container.style.position : null;\n\n if (didSetRelative) {\n container.style.position = 'relative';\n }\n\n const root = document.createElement('div');\n root.style.position = 'absolute';\n root.style.pointerEvents = 'auto';\n root.style.userSelect = 'none';\n root.style.boxSizing = 'border-box';\n\n // Theme-driven styling (set/update in update()).\n root.style.padding = '8px';\n root.style.borderRadius = '8px';\n root.style.borderStyle = 'solid';\n root.style.borderWidth = '1px';\n root.style.maxHeight = 'calc(100% - 16px)';\n root.style.overflow = 'auto';\n\n const list = document.createElement('div');\n list.style.display = 'flex';\n list.style.gap = '8px';\n root.appendChild(list);\n\n // Event delegation for series toggle (fixes memory leak and improves performance)\n if (onSeriesToggle) {\n list.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const item = target.closest('[data-series-index]') as HTMLElement;\n if (item) {\n const seriesIndex = parseInt(item.dataset.seriesIndex!, 10);\n if (!isNaN(seriesIndex)) {\n // Check if this is a pie slice item\n const sliceIndexStr = item.dataset.sliceIndex;\n if (sliceIndexStr !== undefined) {\n const sliceIndex = parseInt(sliceIndexStr, 10);\n if (!isNaN(sliceIndex)) {\n onSeriesToggle(seriesIndex, sliceIndex);\n return;\n }\n }\n // Regular series toggle\n onSeriesToggle(seriesIndex);\n }\n }\n });\n\n // Keyboard navigation support for accessibility\n list.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n const target = e.target as HTMLElement;\n const item = target.closest('[data-series-index]') as HTMLElement;\n if (item) {\n e.preventDefault();\n const seriesIndex = parseInt(item.dataset.seriesIndex!, 10);\n if (!isNaN(seriesIndex)) {\n // Check if this is a pie slice item\n const sliceIndexStr = item.dataset.sliceIndex;\n if (sliceIndexStr !== undefined) {\n const sliceIndex = parseInt(sliceIndexStr, 10);\n if (!isNaN(sliceIndex)) {\n onSeriesToggle(seriesIndex, sliceIndex);\n return;\n }\n }\n // Regular series toggle\n onSeriesToggle(seriesIndex);\n }\n }\n }\n });\n }\n\n const applyPositionStyles = (p: LegendPosition): void => {\n // Clear positional styles first so changing position is safe/idempotent.\n root.style.top = '';\n root.style.right = '';\n root.style.bottom = '';\n root.style.left = '';\n root.style.maxWidth = '';\n\n list.style.flexDirection = '';\n list.style.flexWrap = '';\n list.style.alignItems = '';\n\n switch (p) {\n case 'right': {\n root.style.top = '8px';\n root.style.right = '8px';\n root.style.maxWidth = '40%';\n\n list.style.flexDirection = 'column';\n list.style.flexWrap = 'nowrap';\n list.style.alignItems = 'flex-start';\n return;\n }\n case 'left': {\n root.style.top = '8px';\n root.style.left = '8px';\n root.style.maxWidth = '40%';\n\n list.style.flexDirection = 'column';\n list.style.flexWrap = 'nowrap';\n list.style.alignItems = 'flex-start';\n return;\n }\n case 'top': {\n root.style.top = '8px';\n root.style.left = '8px';\n root.style.right = '8px';\n\n list.style.flexDirection = 'row';\n list.style.flexWrap = 'wrap';\n list.style.alignItems = 'center';\n return;\n }\n case 'bottom': {\n root.style.bottom = '8px';\n root.style.left = '8px';\n root.style.right = '8px';\n\n list.style.flexDirection = 'row';\n list.style.flexWrap = 'wrap';\n list.style.alignItems = 'center';\n return;\n }\n }\n };\n\n applyPositionStyles(position);\n container.appendChild(root);\n\n let disposed = false;\n\n const update: Legend['update'] = (series, theme) => {\n if (disposed) return;\n\n root.style.color = theme.textColor;\n root.style.background = theme.backgroundColor;\n root.style.borderColor = theme.axisLineColor;\n root.style.fontFamily = theme.fontFamily;\n root.style.fontSize = `${theme.fontSize}px`;\n\n const items: HTMLElement[] = [];\n for (let seriesIndex = 0; seriesIndex < series.length; seriesIndex++) {\n const s = series[seriesIndex];\n\n if (s.type === 'pie') {\n for (let sliceIndex = 0; sliceIndex < s.data.length; sliceIndex++) {\n const slice = s.data[sliceIndex];\n const isVisible = slice?.visible !== false;\n\n const item = document.createElement('div');\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '6px';\n item.style.lineHeight = '1.1';\n item.style.whiteSpace = 'nowrap';\n item.style.cursor = onSeriesToggle ? 'pointer' : 'default';\n item.style.opacity = isVisible ? '1' : '0.5';\n item.style.transition = 'opacity 0.2s';\n\n // Add accessibility attributes and data attributes for event delegation\n if (onSeriesToggle) {\n item.setAttribute('role', 'button');\n item.setAttribute('aria-pressed', String(isVisible));\n item.setAttribute('aria-label', `Toggle ${getPieSliceLabel(slice?.name, sliceIndex)} visibility`);\n item.tabIndex = 0;\n item.dataset.seriesIndex = String(seriesIndex);\n item.dataset.sliceIndex = String(sliceIndex);\n }\n\n const swatch = document.createElement('div');\n swatch.style.width = '10px';\n swatch.style.height = '10px';\n swatch.style.borderRadius = '2px';\n swatch.style.flex = '0 0 auto';\n swatch.style.background = getPieSliceColor(slice?.color, seriesIndex, sliceIndex, theme);\n swatch.style.border = `1px solid ${theme.axisLineColor}`;\n\n const label = document.createElement('span');\n label.textContent = getPieSliceLabel(slice?.name, sliceIndex);\n label.style.textDecoration = isVisible ? 'none' : 'line-through';\n\n item.appendChild(swatch);\n item.appendChild(label);\n items.push(item);\n }\n } else {\n const isVisible = s.visible !== false;\n\n const item = document.createElement('div');\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '6px';\n item.style.lineHeight = '1.1';\n item.style.whiteSpace = 'nowrap';\n item.style.cursor = onSeriesToggle ? 'pointer' : 'default';\n item.style.opacity = isVisible ? '1' : '0.5';\n item.style.transition = 'opacity 0.2s';\n\n // Add accessibility attributes and data attribute for event delegation\n if (onSeriesToggle) {\n item.setAttribute('role', 'button');\n item.setAttribute('aria-pressed', String(isVisible));\n item.setAttribute('aria-label', `Toggle ${getSeriesName(s, seriesIndex)} visibility`);\n item.tabIndex = 0;\n item.dataset.seriesIndex = String(seriesIndex);\n }\n\n const swatch = document.createElement('div');\n swatch.style.width = '10px';\n swatch.style.height = '10px';\n swatch.style.borderRadius = '2px';\n swatch.style.flex = '0 0 auto';\n swatch.style.background = getSeriesColor(s, seriesIndex, theme);\n swatch.style.border = `1px solid ${theme.axisLineColor}`;\n\n const label = document.createElement('span');\n label.textContent = getSeriesName(s, seriesIndex);\n label.style.textDecoration = isVisible ? 'none' : 'line-through';\n\n item.appendChild(swatch);\n item.appendChild(label);\n items.push(item);\n }\n }\n\n list.replaceChildren(...items);\n };\n\n const dispose: Legend['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n root.remove();\n } finally {\n if (previousInlinePosition !== null) {\n container.style.position = previousInlinePosition;\n }\n }\n };\n\n return { update, dispose };\n}\n\n","export interface Tooltip {\n /**\n * Show tooltip at container-local CSS pixel coordinates.\n *\n * `content` is treated as HTML (assigned via `innerHTML`).\n */\n show(x: number, y: number, content: string): void;\n hide(): void;\n dispose(): void;\n}\n\nconst clamp = (value: number, min: number, max: number): number => {\n if (max < min) return min;\n if (value < min) return min;\n if (value > max) return max;\n return value;\n};\n\nexport function createTooltip(container: HTMLElement): Tooltip {\n const computedPosition = getComputedStyle(container).position;\n const didSetRelative = computedPosition === 'static';\n const previousInlinePosition = didSetRelative ? container.style.position : null;\n\n if (didSetRelative) {\n container.style.position = 'relative';\n }\n\n const root = document.createElement('div');\n root.style.position = 'absolute';\n root.style.left = '0';\n root.style.top = '0';\n root.style.pointerEvents = 'none';\n root.style.userSelect = 'none';\n root.style.boxSizing = 'border-box';\n\n // Theme-friendly default visuals with CSS variable override points.\n root.style.zIndex = 'var(--chartgpu-tooltip-z, 10)';\n root.style.padding = 'var(--chartgpu-tooltip-padding, 6px 8px)';\n root.style.borderRadius = 'var(--chartgpu-tooltip-radius, 8px)';\n root.style.borderStyle = 'solid';\n root.style.borderWidth = 'var(--chartgpu-tooltip-border-width, 1px)';\n root.style.borderColor =\n 'var(--chartgpu-tooltip-border, rgba(224,224,224,0.35))';\n root.style.boxShadow =\n 'var(--chartgpu-tooltip-shadow, 0 6px 18px rgba(0,0,0,0.35))';\n root.style.maxWidth = 'var(--chartgpu-tooltip-max-width, min(320px, 100%))';\n root.style.overflow = 'hidden';\n root.style.fontFamily =\n 'var(--chartgpu-tooltip-font-family, system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\")';\n root.style.fontSize = 'var(--chartgpu-tooltip-font-size, 12px)';\n root.style.lineHeight = 'var(--chartgpu-tooltip-line-height, 1.2)';\n root.style.color = 'var(--chartgpu-tooltip-color, #e0e0e0)';\n root.style.background = 'var(--chartgpu-tooltip-bg, rgba(26,26,46,0.95))';\n root.style.whiteSpace = 'normal';\n\n // Transition-ready baseline; keep fade-out visible until completion.\n root.style.opacity = '0';\n root.style.transitionProperty = 'opacity';\n const fadeMs = 140;\n root.style.transitionDuration = `${fadeMs}ms`;\n root.style.transitionTimingFunction = 'ease';\n root.style.willChange = 'opacity';\n\n // Keep it out of layout/paint when hidden.\n root.style.display = 'none';\n root.style.visibility = 'hidden';\n\n root.setAttribute('role', 'tooltip');\n container.appendChild(root);\n\n let disposed = false;\n let transitionToken = 0;\n let hideTimeoutId: number | null = null;\n let rafId: number | null = null;\n\n const clearPendingTransitions = (): void => {\n if (hideTimeoutId != null) {\n window.clearTimeout(hideTimeoutId);\n hideTimeoutId = null;\n }\n if (rafId != null) {\n window.cancelAnimationFrame(rafId);\n rafId = null;\n }\n };\n\n const isCurrentlyHidden = (): boolean =>\n root.style.display === 'none' || root.style.visibility === 'hidden';\n\n const measureSize = (): Readonly<{ width: number; height: number }> => {\n // Measure without touching opacity to avoid restarting fades.\n // If the tooltip is currently visible, this temporarily hides it from paint\n // within the same call (no flicker between frames).\n const prevVisibility = root.style.visibility;\n root.style.visibility = 'hidden';\n\n // offsetWidth/offsetHeight are rounded but stable for layout decisions here.\n const width = root.offsetWidth;\n const height = root.offsetHeight;\n\n root.style.visibility = prevVisibility;\n return { width, height };\n };\n\n const show: Tooltip['show'] = (x, y, content) => {\n if (disposed) return;\n\n transitionToken += 1;\n clearPendingTransitions();\n\n const wasHidden = isCurrentlyHidden();\n\n root.innerHTML = content;\n\n const dx = 12;\n const dy = 12;\n const pad = 8;\n\n // Ensure it participates in layout for measurement & positioning.\n // Keep it hidden from paint until we finish placing it.\n root.style.display = 'block';\n root.style.visibility = 'hidden';\n\n const { width: w, height: h } = measureSize();\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n\n let left = x + dx;\n let top = y + dy;\n\n if (left + w > containerW - pad) left = x - dx - w;\n if (top + h > containerH - pad) top = y - dy - h;\n\n left = clamp(left, pad, containerW - pad - w);\n top = clamp(top, pad, containerH - pad - h);\n\n root.style.left = `${left}px`;\n root.style.top = `${top}px`;\n\n root.style.visibility = 'visible';\n\n if (wasHidden) {\n // Only fade in on hidden -> visible transition.\n root.style.opacity = '0';\n const myToken = transitionToken;\n rafId = window.requestAnimationFrame(() => {\n rafId = null;\n if (disposed) return;\n if (myToken !== transitionToken) return;\n root.style.opacity = '1';\n });\n } else {\n // Frequent updates while visible should not restart the fade.\n // Also cancels an in-progress hide fade-out by restoring opacity.\n root.style.opacity = '1';\n }\n };\n\n const hide: Tooltip['hide'] = () => {\n if (disposed) return;\n\n transitionToken += 1;\n clearPendingTransitions();\n\n // If it's already hidden, keep idempotent and avoid extra work.\n if (root.style.display === 'none' || root.style.visibility === 'hidden') {\n root.style.opacity = '0';\n root.style.visibility = 'hidden';\n root.style.display = 'none';\n return;\n }\n\n root.style.opacity = '0';\n\n const myToken = transitionToken;\n hideTimeoutId = window.setTimeout(() => {\n hideTimeoutId = null;\n if (disposed) return;\n if (myToken !== transitionToken) return;\n root.style.visibility = 'hidden';\n root.style.display = 'none';\n }, fadeMs + 50);\n };\n\n const dispose: Tooltip['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n try {\n clearPendingTransitions();\n root.remove();\n } finally {\n if (previousInlinePosition !== null) {\n container.style.position = previousInlinePosition;\n }\n }\n };\n\n return { show, hide, dispose };\n}\n\n","import type { TooltipParams } from '../config/types';\n\nconst EM_DASH = '\\u2014';\n\nfunction escapeHtml(text: string): string {\n // Escapes text for safe insertion into HTML text/attribute contexts.\n // (We only use it for text nodes here, but keeping it generic is fine.)\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction formatNumber(value: number): string {\n if (!Number.isFinite(value)) return EM_DASH;\n\n // Normalize -0 to 0 for display stability.\n const normalized = Object.is(value, -0) ? 0 : value;\n\n // Maximum 2 decimal places, trim trailing zeros.\n const fixed = normalized.toFixed(2);\n const trimmed = fixed.replace(/\\.?0+$/, '');\n return trimmed === '-0' ? '0' : trimmed;\n}\n\nfunction resolveSeriesName(params: TooltipParams): string {\n const trimmed = params.seriesName.trim();\n return trimmed.length > 0 ? trimmed : `Series ${params.seriesIndex + 1}`;\n}\n\nfunction sanitizeCssColor(value: string): string {\n // Tooltip content is assigned via innerHTML, so treat color as untrusted.\n // Allow only common safe color syntaxes; otherwise fall back.\n const s = value.trim();\n if (s.length === 0) return '#888';\n\n // Hex: #RGB, #RRGGBB, #RRGGBBAA\n if (/^#[0-9a-fA-F]{3}$/.test(s)) return s;\n if (/^#[0-9a-fA-F]{6}$/.test(s)) return s;\n if (/^#[0-9a-fA-F]{8}$/.test(s)) return s;\n\n // rgb()/rgba() numeric forms (commas or space-separated with optional slash alpha)\n if (\n /^rgba?\\(\\s*\\d{1,3}\\s*(?:,\\s*|\\s+)\\d{1,3}\\s*(?:,\\s*|\\s+)\\d{1,3}(?:\\s*(?:,\\s*|\\/\\s*)(?:0|1|0?\\.\\d+))?\\s*\\)$/.test(\n s,\n )\n ) {\n return s;\n }\n\n // Named colors: basic CSS ident (letters only) to avoid weird tokens.\n if (/^[a-zA-Z]+$/.test(s)) return s;\n\n return '#888';\n}\n\nfunction isCandlestickValue(\n value: readonly [number, number] | readonly [number, number, number, number, number],\n): value is readonly [number, number, number, number, number] {\n return value.length === 5;\n}\n\nfunction formatPercentChange(open: number, close: number): string {\n if (!Number.isFinite(open) || !Number.isFinite(close)) return EM_DASH;\n if (open === 0) return EM_DASH; // Avoid division by zero\n\n const change = ((close - open) / open) * 100;\n if (!Number.isFinite(change)) return EM_DASH;\n\n const sign = change > 0 ? '+' : '';\n return `${sign}${change.toFixed(2)}%`;\n}\n\nfunction formatRowHtml(params: TooltipParams, valueText: string): string {\n const safeName = escapeHtml(resolveSeriesName(params));\n const safeValue = escapeHtml(valueText);\n const safeColor = escapeHtml(sanitizeCssColor(params.color));\n\n return [\n '<div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;\">',\n '<span style=\"display:flex;align-items:center;gap:8px;min-width:0;\">',\n `<span style=\"width:8px;height:8px;border-radius:999px;flex:0 0 auto;background-color:${safeColor};\"></span>`,\n `<span style=\"overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\">${safeName}</span>`,\n '</span>',\n `<span style=\"font-variant-numeric:tabular-nums;white-space:nowrap;\">${safeValue}</span>`,\n '</div>',\n ].join('');\n}\n\nfunction formatCandlestickRowHtml(params: TooltipParams): string {\n const [, open, close, low, high] = params.value as readonly [number, number, number, number, number];\n \n const safeName = escapeHtml(resolveSeriesName(params));\n const safeColor = escapeHtml(sanitizeCssColor(params.color));\n\n // Format OHLC values\n const openStr = formatNumber(open);\n const highStr = formatNumber(high);\n const lowStr = formatNumber(low);\n const closeStr = formatNumber(close);\n \n // Determine direction and arrow\n const isUp = close > open;\n const arrow = isUp ? '\\u25B2' : '\\u25BC'; // ▲ or ▼\n const arrowColor = isUp ? '#22c55e' : '#ef4444';\n const percentChange = formatPercentChange(open, close);\n\n const ohlcText = `O: ${openStr} H: ${highStr} L: ${lowStr} C: ${closeStr}`;\n const safeOHLC = escapeHtml(ohlcText);\n const safeArrow = escapeHtml(arrow);\n const safePercent = escapeHtml(percentChange);\n const safeArrowColor = escapeHtml(arrowColor);\n\n return [\n '<div style=\"display:flex;flex-direction:column;gap:4px;\">',\n // Series name row\n '<div style=\"display:flex;align-items:center;gap:8px;\">',\n `<span style=\"width:8px;height:8px;border-radius:999px;flex:0 0 auto;background-color:${safeColor};\"></span>`,\n `<span style=\"overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600;\">${safeName}</span>`,\n '</div>',\n // OHLC values row\n `<div style=\"font-variant-numeric:tabular-nums;white-space:nowrap;font-size:0.9em;\">${safeOHLC}</div>`,\n // Change row with arrow\n '<div style=\"display:flex;align-items:center;gap:6px;font-variant-numeric:tabular-nums;\">',\n `<span style=\"color:${safeArrowColor};font-weight:700;\">${safeArrow}</span>`,\n `<span style=\"color:${safeArrowColor};font-weight:600;\">${safePercent}</span>`,\n '</div>',\n '</div>',\n ].join('');\n}\n\n/**\n * Default tooltip formatter for candlestick series in item mode.\n * Renders O/H/L/C values with colored arrow and percentage change.\n */\nexport function formatCandlestickTooltip(params: TooltipParams): string {\n return formatCandlestickRowHtml(params);\n}\n\n/**\n * Default tooltip formatter for item mode.\n * Returns a compact single-row HTML snippet: dot + series name + y value.\n * For candlestick series, returns O/H/L/C with arrow and percentage change.\n */\nexport function formatTooltipItem(params: TooltipParams): string {\n if (isCandlestickValue(params.value)) {\n return formatCandlestickTooltip(params);\n }\n return formatRowHtml(params, formatNumber(params.value[1]));\n}\n\n/**\n * Default tooltip formatter for axis mode.\n * Renders an x header line then one row per series with the y value.\n * Candlestick series show O/H/L/C values with arrow and percentage change.\n */\nexport function formatTooltipAxis(params: TooltipParams[]): string {\n if (params.length === 0) return '';\n\n const xText = `x: ${formatNumber(params[0].value[0])}`;\n const header = `<div style=\"margin:0 0 6px 0;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap;\">${escapeHtml(\n xText,\n )}</div>`;\n\n const rows = params\n .map((p) => {\n if (isCandlestickValue(p.value)) {\n return formatCandlestickRowHtml(p);\n }\n return formatRowHtml(p, formatNumber(p.value[1]));\n })\n .join('<div style=\"height:4px;\"></div>');\n\n return `${header}${rows}`;\n}\n\n","import type { EasingFunction } from '../utils/easing';\n\nexport type AnimationId = symbol;\n\nexport interface AnimationController {\n animate(\n from: number,\n to: number,\n duration: number,\n easing: EasingFunction,\n onUpdate: (value: number) => void,\n onComplete?: () => void,\n ): AnimationId;\n animate(\n from: ReadonlyArray<number>,\n to: ReadonlyArray<number>,\n duration: number,\n easing: EasingFunction,\n onUpdate: (value: ReadonlyArray<number>) => void,\n onComplete?: () => void,\n ): AnimationId;\n\n cancel(animationId: AnimationId): void;\n cancelAll(): void;\n\n /**\n * Progresses all active animations to `timestamp` (ms).\n * Intended to be called once per frame by the caller (e.g. a render loop).\n */\n update(timestamp: number): void;\n}\n\ntype ScalarAnimation = Readonly<{\n kind: 'scalar';\n from: number;\n to: number;\n duration: number;\n easing: EasingFunction;\n onUpdate: (value: number) => void;\n onComplete?: () => void;\n startTime: number | null;\n}>;\n\ntype ArrayAnimation = Readonly<{\n kind: 'array';\n from: ReadonlyArray<number>;\n to: ReadonlyArray<number>;\n duration: number;\n easing: EasingFunction;\n onUpdate: (value: ReadonlyArray<number>) => void;\n onComplete?: () => void;\n startTime: number | null;\n out: number[];\n}>;\n\ntype AnimationInternal = ScalarAnimation | ArrayAnimation;\n\nconst normalizeDurationMs = (duration: number): number =>\n Number.isFinite(duration) ? duration : 0;\n\nconst normalizeTimestampMs = (timestamp: number): number | null =>\n Number.isFinite(timestamp) ? timestamp : null;\n\nexport function createAnimationController(): AnimationController {\n const animations = new Map<AnimationId, AnimationInternal>();\n\n function animate(\n from: number | ReadonlyArray<number>,\n to: number | ReadonlyArray<number>,\n duration: number,\n easing: EasingFunction,\n onUpdate: ((value: number) => void) | ((value: ReadonlyArray<number>) => void),\n onComplete?: () => void,\n ): AnimationId {\n const id: AnimationId = Symbol('Animation');\n\n if (Array.isArray(from) || Array.isArray(to)) {\n if (!Array.isArray(from) || !Array.isArray(to)) {\n throw new Error('Array animation requires both \"from\" and \"to\" to be arrays');\n }\n if (from.length !== to.length) {\n throw new Error(\n `Array animation length mismatch: from.length=${from.length}, to.length=${to.length}`,\n );\n }\n\n const out = new Array<number>(from.length);\n animations.set(id, {\n kind: 'array',\n from,\n to,\n duration,\n easing,\n onUpdate: onUpdate as (value: ReadonlyArray<number>) => void,\n onComplete,\n startTime: null,\n out,\n });\n return id;\n }\n\n animations.set(id, {\n kind: 'scalar',\n from: from as number,\n to: to as number,\n duration,\n easing,\n onUpdate: onUpdate as (value: number) => void,\n onComplete,\n startTime: null,\n });\n return id;\n }\n\n function cancel(animationId: AnimationId): void {\n animations.delete(animationId);\n }\n\n function cancelAll(): void {\n animations.clear();\n }\n\n function update(timestamp: number): void {\n const ts = normalizeTimestampMs(timestamp);\n if (ts === null) return;\n\n // Snapshot IDs to tolerate cancellation during callbacks and to ensure\n // animations started during callbacks don't run until next tick.\n const ids = Array.from(animations.keys());\n for (const id of ids) {\n const anim = animations.get(id);\n if (!anim) continue; // cancelled\n\n const startTime = anim.startTime ?? ts;\n if (anim.startTime === null) {\n // Mutate by replacement to keep internal entries immutable-by-type.\n animations.set(id, { ...anim, startTime });\n }\n\n const durationMs = normalizeDurationMs(anim.duration);\n const elapsed = Math.max(0, ts - startTime);\n\n const shouldComplete = durationMs <= 0 || elapsed >= durationMs;\n const rawT = durationMs <= 0 ? 1 : elapsed / durationMs;\n const t = shouldComplete ? 1 : anim.easing(rawT);\n\n if (anim.kind === 'scalar') {\n const value = anim.from + (anim.to - anim.from) * t;\n anim.onUpdate(value);\n\n // Cancellation during callback should prevent onComplete.\n if (!animations.has(id)) continue;\n } else {\n const n = anim.out.length;\n for (let i = 0; i < n; i++) {\n const a = anim.from[i] ?? 0;\n const b = anim.to[i] ?? 0;\n anim.out[i] = a + (b - a) * t;\n }\n anim.onUpdate(anim.out);\n\n // Cancellation during callback should prevent onComplete.\n if (!animations.has(id)) continue;\n }\n\n if (shouldComplete) {\n anim.onComplete?.();\n // If it was cancelled inside onComplete, deletion is harmless.\n animations.delete(id);\n }\n }\n }\n\n return {\n animate: animate as AnimationController['animate'],\n cancel,\n cancelAll,\n update,\n };\n}\n","export type EasingFunction = (t: number) => number;\n\nimport type { AnimationConfig } from '../config/types';\n\nexport type EasingName = NonNullable<AnimationConfig['easing']>;\n\nconst clamp01 = (t: number): number => {\n if (Number.isNaN(t)) return 0;\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n return t;\n};\n\nexport function easeLinear(t: number): number {\n return clamp01(t);\n}\n\nexport function easeCubicOut(t: number): number {\n const x = clamp01(t);\n const inv = 1 - x;\n return 1 - inv * inv * inv;\n}\n\nexport function easeCubicInOut(t: number): number {\n const x = clamp01(t);\n // Standard easeInOutCubic:\n // - accelerating cubic for the first half\n // - decelerating cubic for the second half\n if (x < 0.5) return 4 * x * x * x;\n const y = -2 * x + 2;\n return 1 - (y * y * y) / 2;\n}\n\nexport function easeBounceOut(t: number): number {\n const x = clamp01(t);\n // Standard easeOutBounce (Robert Penner) piecewise approximation.\n const n1 = 7.5625;\n const d1 = 2.75;\n\n if (x < 1 / d1) {\n return n1 * x * x;\n }\n if (x < 2 / d1) {\n const a = x - 1.5 / d1;\n return n1 * a * a + 0.75;\n }\n if (x < 2.5 / d1) {\n const a = x - 2.25 / d1;\n return n1 * a * a + 0.9375;\n }\n\n const a = x - 2.625 / d1;\n return n1 * a * a + 0.984375;\n}\n\nexport function getEasing(\n name: AnimationConfig['easing'] | null | undefined,\n): EasingFunction {\n switch (name) {\n case 'linear':\n return easeLinear;\n case 'cubicOut':\n return easeCubicOut;\n case 'cubicInOut':\n return easeCubicInOut;\n case 'bounceOut':\n return easeBounceOut;\n default:\n return easeLinear;\n }\n}\n","import type {\n ResolvedBarSeriesConfig,\n ResolvedCandlestickSeriesConfig,\n ResolvedChartGPUOptions,\n ResolvedPieSeriesConfig,\n} from '../config/OptionResolver';\nimport type {\n AnimationConfig,\n AnnotationConfig,\n DataPoint,\n DataPointTuple,\n OHLCDataPoint,\n PieCenter,\n PieRadius,\n} from '../config/types';\nimport { GPUContext, isHTMLCanvasElement as isHTMLCanvasElementGPU } from './GPUContext';\nimport { createDataStore } from '../data/createDataStore';\nimport { sampleSeriesDataPoints } from '../data/sampleSeries';\nimport { ohlcSample } from '../data/ohlcSample';\nimport {\n sliceVisibleRangeByX,\n sliceVisibleRangeByOHLC,\n isTupleOHLCDataPoint as isTupleOHLCDataPointImported,\n} from './renderCoordinator/data/computeVisibleSlice';\nimport { \n getPointCount, \n getX, \n getY, \n computeRawBoundsFromCartesianData \n} from '../data/cartesianData';\nimport type { CartesianSeriesData } from '../config/types';\nimport { renderAxisLabels } from './renderCoordinator/render/renderAxisLabels';\nimport { renderAnnotationLabels } from './renderCoordinator/render/renderAnnotationLabels';\nimport { prepareOverlays } from './renderCoordinator/render/renderOverlays';\nimport { processAnnotations } from './renderCoordinator/annotations/processAnnotations';\nimport {\n prepareSeries,\n encodeScatterDensityCompute,\n renderSeries as renderSeriesPass,\n renderAboveSeriesAnnotations,\n} from './renderCoordinator/render/renderSeries';\nimport { createAxisRenderer } from '../renderers/createAxisRenderer';\nimport { createGridRenderer } from '../renderers/createGridRenderer';\nimport type { GridArea } from '../renderers/createGridRenderer';\nimport { createAreaRenderer } from '../renderers/createAreaRenderer';\nimport { createLineRenderer } from '../renderers/createLineRenderer';\nimport { createBarRenderer } from '../renderers/createBarRenderer';\nimport { createScatterRenderer } from '../renderers/createScatterRenderer';\nimport { createScatterDensityRenderer } from '../renderers/createScatterDensityRenderer';\nimport { createPieRenderer } from '../renderers/createPieRenderer';\nimport { createCandlestickRenderer } from '../renderers/createCandlestickRenderer';\nimport { createCrosshairRenderer } from '../renderers/createCrosshairRenderer';\nimport { createHighlightRenderer } from '../renderers/createHighlightRenderer';\nimport { createRenderPipeline } from '../renderers/rendererUtils';\nimport { createReferenceLineRenderer } from '../renderers/createReferenceLineRenderer';\nimport type { ReferenceLineInstance } from '../renderers/createReferenceLineRenderer';\nimport { createAnnotationMarkerRenderer } from '../renderers/createAnnotationMarkerRenderer';\nimport type { AnnotationMarkerInstance } from '../renderers/createAnnotationMarkerRenderer';\nimport { createEventManager } from '../interaction/createEventManager';\nimport type { ChartGPUEventPayload } from '../interaction/createEventManager';\nimport { createInsideZoom } from '../interaction/createInsideZoom';\nimport { createZoomState } from '../interaction/createZoomState';\nimport type { ZoomRange, ZoomState } from '../interaction/createZoomState';\nimport { findNearestPoint } from '../interaction/findNearestPoint';\nimport { findPointsAtX } from '../interaction/findPointsAtX';\nimport { computeCandlestickBodyWidthRange, findCandlestick } from '../interaction/findCandlestick';\nimport { findPieSlice } from '../interaction/findPieSlice';\nimport { createLinearScale } from '../utils/scales';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToGPUColor, parseCssColorToRgba01 } from '../utils/colors';\nimport { createTextOverlay } from '../components/createTextOverlay';\nimport type { TextOverlay, TextOverlayAnchor } from '../components/createTextOverlay';\nimport { createLegend } from '../components/createLegend';\nimport type { Legend } from '../components/createLegend';\nimport { createTooltip } from '../components/createTooltip';\nimport type { Tooltip } from '../components/createTooltip';\nimport type { TooltipParams } from '../config/types';\nimport { formatTooltipAxis, formatTooltipItem } from '../components/formatTooltip';\nimport { createAnimationController } from './createAnimationController';\nimport type { AnimationId } from './createAnimationController';\nimport { getEasing } from '../utils/easing';\nimport type { EasingFunction } from '../utils/easing';\n\nexport interface GPUContextLike {\n readonly device: GPUDevice | null;\n readonly canvas: HTMLCanvasElement | null;\n readonly canvasContext: GPUCanvasContext | null;\n readonly preferredFormat: GPUTextureFormat | null;\n readonly initialized: boolean;\n readonly devicePixelRatio?: number;\n}\n\n/** Type guard to check if canvas is HTMLCanvasElement (has DOM-specific properties). */\nconst isHTMLCanvasElement = isHTMLCanvasElementGPU;\n\n/** Gets canvas CSS width - clientWidth for HTMLCanvasElement */\nfunction getCanvasCssWidth(canvas: HTMLCanvasElement | null): number {\n if (!canvas) {\n return 0;\n }\n\n return canvas.clientWidth;\n}\n\n/**\n * Gets canvas CSS size derived strictly from device-pixel dimensions and DPR.\n *\n * This is intentionally different from `getCanvasCssWidth/Height(...)`:\n * - HTMLCanvasElement: `clientWidth/clientHeight` reflect DOM layout and can diverge (rounding, zoom, async resize)\n * from the WebGPU render target size (`canvas.width/height` in device pixels).\n * - For GPU overlays that round-trip CSS↔device pixels in-shader, we must derive CSS size from\n * `canvas.width/height` + DPR to keep transforms consistent with the render target.\n *\n * NOTE: Use this for GPU overlay coordinate conversion only (reference lines, markers).\n * Keep DOM overlays (labels/tooltips) using `clientWidth/clientHeight` for layout correctness.\n */\nfunction getCanvasCssSizeFromDevicePixels(\n canvas: HTMLCanvasElement | null,\n): Readonly<{ width: number; height: number }> {\n if (!canvas) return { width: 0, height: 0 };\n const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n // HTMLCanvasElement exposes `.width/.height` in device pixels.\n return { width: canvas.width / dpr, height: canvas.height / dpr };\n}\n\nexport interface RenderCoordinator {\n setOptions(resolvedOptions: ResolvedChartGPUOptions): void;\n /**\n * Appends new points to a cartesian series’ runtime data without requiring a full `setOptions(...)`\n * resolver pass.\n *\n * Appends are coalesced and flushed once per render frame.\n */\n appendData(seriesIndex: number, newPoints: ReadonlyArray<DataPoint> | ReadonlyArray<OHLCDataPoint>): void;\n /**\n * Gets the current “interaction x” in domain units (or `null` when inactive).\n *\n * This is derived from pointer movement inside the plot grid and can also be driven\n * externally via `setInteractionX(...)` (e.g. chart sync).\n */\n getInteractionX(): number | null;\n /**\n * Drives the chart’s crosshair + tooltip from a domain-space x value.\n *\n * Passing `null` clears the interaction (hides crosshair/tooltip).\n */\n setInteractionX(x: number | null, source?: unknown): void;\n /**\n * Subscribes to interaction x changes (domain units).\n *\n * Returns an unsubscribe function.\n */\n onInteractionXChange(callback: (x: number | null, source?: unknown) => void): () => void;\n /**\n * Returns the current percent-space zoom window (or `null` when zoom is disabled).\n */\n getZoomRange(): Readonly<{ start: number; end: number }> | null;\n /**\n * Sets the percent-space zoom window.\n *\n * No-op when zoom is disabled.\n */\n setZoomRange(start: number, end: number): void;\n /**\n * Subscribes to zoom window changes (percent space).\n *\n * Returns an unsubscribe function.\n */\n onZoomRangeChange(cb: (range: Readonly<{ start: number; end: number }>) => void): () => void;\n render(): void;\n dispose(): void;\n}\n\nexport type RenderCoordinatorCallbacks = Readonly<{\n /**\n * Optional hook for render-on-demand systems (like `ChartGPU`) to re-render when\n * interaction state changes (e.g. crosshair on pointer move).\n */\n readonly onRequestRender?: () => void;\n /**\n * Called when GPU device is lost.\n */\n readonly onDeviceLost?: (reason: string) => void;\n}>;\n\ntype Bounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_TICK_COUNT: number = 5;\n\n// Story 6: time-axis label tiers + adaptive tick count (x-axis only).\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n// Approximate month/year thresholds (requirements are ms-range based, not calendar-aware).\nconst MS_PER_MONTH_APPROX = 30 * MS_PER_DAY;\nconst MS_PER_YEAR_APPROX = 365 * MS_PER_DAY;\n\nconst MAX_TIME_X_TICK_COUNT = 9;\nconst MIN_TIME_X_TICK_COUNT = 1;\nconst MIN_X_LABEL_GAP_CSS_PX = 6;\n\nconst finiteOrNull = (v: number | null | undefined): number | null =>\n typeof v === 'number' && Number.isFinite(v) ? v : null;\n\nconst finiteOrUndefined = (v: number | undefined): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n\n// Story 5.17: CPU-side update interpolation can be expensive for very large series.\n// We still animate domains for large series, but skip per-point y interpolation past this cap.\nconst MAX_ANIMATED_POINTS_PER_SERIES = 20_000;\n\nconst assertUnreachable = (value: never): never => {\n // Intentionally minimal message: this is used for compile-time exhaustiveness.\n throw new Error(`RenderCoordinator: unreachable value: ${String(value)}`);\n};\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n return { x: p.x, y: p.y };\n};\n\n/**\n * Helper: Convert CartesianSeriesData to mutable DataPoint[] array.\n * Used for runtime storage that supports streaming appends.\n */\nconst cartesianDataToDataPointArray = (data: CartesianSeriesData): DataPoint[] => {\n // If already a DataPoint array, clone it\n if (Array.isArray(data)) {\n return data.length === 0 ? [] : data.slice();\n }\n\n // Convert XYArraysData or InterleavedXYData to DataPoint[]\n const n = getPointCount(data);\n const out: DataPoint[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n const y = getY(data, i);\n out[i] = [x, y];\n }\n return out;\n};\n\nconst extendBoundsWithDataPoints = (bounds: Bounds | null, points: ReadonlyArray<DataPoint>): Bounds | null => {\n if (points.length === 0) return bounds;\n\n let b = bounds;\n if (!b) {\n // Try to seed from the appended points.\n const seeded = computeRawBoundsFromCartesianData(points);\n if (!seeded) return bounds;\n b = seeded;\n }\n\n let xMin = b.xMin;\n let xMax = b.xMax;\n let yMin = b.yMin;\n let yMax = b.yMax;\n\n for (let i = 0; i < points.length; i++) {\n const { x, y } = getPointXY(points[i]!);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n\n // Keep bounds usable for downstream scale derivation.\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst extendBoundsWithOHLCDataPoints = (bounds: Bounds | null, points: ReadonlyArray<OHLCDataPoint>): Bounds | null => {\n if (points.length === 0) return bounds;\n\n let xMin = bounds?.xMin ?? Number.POSITIVE_INFINITY;\n let xMax = bounds?.xMax ?? Number.NEGATIVE_INFINITY;\n let yMin = bounds?.yMin ?? Number.POSITIVE_INFINITY;\n let yMax = bounds?.yMax ?? Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < points.length; i++) {\n const p = points[i]!;\n const timestamp = isTupleOHLCDataPoint(p) ? p[0] : p.timestamp;\n const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n\n if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n if (timestamp < xMin) xMin = timestamp;\n if (timestamp > xMax) xMax = timestamp;\n if (low < yMin) yMin = low;\n if (high > yMax) yMax = high;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return bounds;\n }\n\n // Keep bounds usable for downstream scale derivation.\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst computeGlobalBounds = (\n series: ResolvedChartGPUOptions['series'],\n runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null\n): Bounds => {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let s = 0; s < series.length; s++) {\n const seriesConfig = series[s];\n // Pie series are non-cartesian; they don't participate in x/y bounds.\n if (seriesConfig.type === 'pie') continue;\n\n const runtimeBoundsCandidate = runtimeRawBoundsByIndex?.[s] ?? null;\n if (runtimeBoundsCandidate) {\n const b = runtimeBoundsCandidate;\n if (\n Number.isFinite(b.xMin) &&\n Number.isFinite(b.xMax) &&\n Number.isFinite(b.yMin) &&\n Number.isFinite(b.yMax)\n ) {\n if (b.xMin < xMin) xMin = b.xMin;\n if (b.xMax > xMax) xMax = b.xMax;\n if (b.yMin < yMin) yMin = b.yMin;\n if (b.yMax > yMax) yMax = b.yMax;\n continue;\n }\n }\n\n // Prefer precomputed bounds from the original (unsampled) data when available.\n // This ensures sampling cannot affect axis auto-bounds and avoids per-render O(n) scans.\n const rawBoundsCandidate = seriesConfig.rawBounds;\n if (rawBoundsCandidate) {\n const b = rawBoundsCandidate;\n if (\n Number.isFinite(b.xMin) &&\n Number.isFinite(b.xMax) &&\n Number.isFinite(b.yMin) &&\n Number.isFinite(b.yMax)\n ) {\n if (b.xMin < xMin) xMin = b.xMin;\n if (b.xMax > xMax) xMax = b.xMax;\n if (b.yMin < yMin) yMin = b.yMin;\n if (b.yMax > yMax) yMax = b.yMax;\n continue;\n }\n }\n\n // Candlestick series: bounds should be precomputed in OptionResolver from timestamp/low/high.\n // If we reach here, `rawBounds` was undefined; fall back to a raw OHLC scan so axes don't break.\n if (seriesConfig.type === 'candlestick') {\n const rawOHLC = (seriesConfig.rawData ?? seriesConfig.data) as ReadonlyArray<OHLCDataPoint>;\n for (let i = 0; i < rawOHLC.length; i++) {\n const p = rawOHLC[i]!;\n if (isTupleOHLCDataPoint(p)) {\n const timestamp = p[0];\n const low = p[3];\n const high = p[4];\n if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n const yLow = Math.min(low, high);\n const yHigh = Math.max(low, high);\n\n if (timestamp < xMin) xMin = timestamp;\n if (timestamp > xMax) xMax = timestamp;\n if (yLow < yMin) yMin = yLow;\n if (yHigh > yMax) yMax = yHigh;\n } else {\n const timestamp = p.timestamp;\n const low = p.low;\n const high = p.high;\n if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n const yLow = Math.min(low, high);\n const yHigh = Math.max(low, high);\n\n if (timestamp < xMin) xMin = timestamp;\n if (timestamp > xMax) xMax = timestamp;\n if (yLow < yMin) yMin = yLow;\n if (yHigh > yMax) yMax = yHigh;\n }\n }\n continue;\n }\n\n // Cartesian series (line, area, bar, scatter): use CartesianSeriesData accessors\n const data = seriesConfig.data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const x = getX(data, i);\n const y = getY(data, i);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n }\n\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n}; \n\nconst normalizeDomain = (\n minCandidate: number,\n maxCandidate: number\n): { readonly min: number; readonly max: number } => {\n let min = minCandidate;\n let max = maxCandidate;\n\n if (!Number.isFinite(min) || !Number.isFinite(max)) {\n min = 0;\n max = 1;\n }\n\n if (min === max) {\n max = min + 1;\n } else if (min > max) {\n const t = min;\n min = max;\n max = t;\n }\n\n return { min, max };\n};\n\nconst computeGridArea = (gpuContext: GPUContextLike, options: ResolvedChartGPUOptions): GridArea => {\n const canvas = gpuContext.canvas;\n if (!canvas) throw new Error('RenderCoordinator: gpuContext.canvas is required.');\n\n // GridArea uses:\n // - Margins (left, right, top, bottom) in CSS pixels\n // - Canvas dimensions (canvasWidth, canvasHeight) in DEVICE pixels\n // - devicePixelRatio for CSS-to-device conversion (worker-compatible)\n // This allows renderers to multiply margins by DPR and subtract from canvas dimensions\n\n const dpr = gpuContext.devicePixelRatio ?? 1;\n const devicePixelRatio = (Number.isFinite(dpr) && dpr > 0) ? dpr : 1;\n\n // Validate and sanitize canvas dimensions (device pixels)\n // Canvas dimensions should be set by GPUContext initialization/resize, but guard against edge cases:\n // - Race conditions during initialization\n // - Canvas not yet sized (0 dimensions)\n const rawCanvasWidth = canvas.width;\n const rawCanvasHeight = canvas.height;\n \n if (!Number.isFinite(rawCanvasWidth) || !Number.isFinite(rawCanvasHeight)) {\n throw new Error(\n `RenderCoordinator: Invalid canvas dimensions: width=${rawCanvasWidth}, height=${rawCanvasHeight}. ` +\n `Canvas must be initialized with finite dimensions before rendering.`\n );\n }\n \n // Be resilient: charts may be mounted into 0-sized containers (e.g. display:none during init).\n // Renderers guard internally; clamping avoids hard crashes and allows future resize to recover.\n const canvasWidth = Math.max(1, Math.floor(rawCanvasWidth));\n const canvasHeight = Math.max(1, Math.floor(rawCanvasHeight));\n\n // Validate and sanitize grid margins (CSS pixels)\n // Grid margins come from resolved options and should be finite, but guard against edge cases\n const left = Number.isFinite(options.grid.left) ? options.grid.left : 0;\n const right = Number.isFinite(options.grid.right) ? options.grid.right : 0;\n const top = Number.isFinite(options.grid.top) ? options.grid.top : 0;\n const bottom = Number.isFinite(options.grid.bottom) ? options.grid.bottom : 0;\n\n // Ensure margins are non-negative (negative margins could cause rendering issues)\n const sanitizedLeft = Math.max(0, left);\n const sanitizedRight = Math.max(0, right);\n const sanitizedTop = Math.max(0, top);\n const sanitizedBottom = Math.max(0, bottom);\n\n return {\n left: sanitizedLeft,\n right: sanitizedRight,\n top: sanitizedTop,\n bottom: sanitizedBottom,\n canvasWidth, // Device pixels (clamped above)\n canvasHeight, // Device pixels (clamped above)\n devicePixelRatio, // Explicit DPR for worker compatibility (validated above)\n };\n};\n\nconst rgba01ToCssRgba = (rgba: readonly [number, number, number, number]): string => {\n const r = Math.max(0, Math.min(255, Math.round(rgba[0] * 255)));\n const g = Math.max(0, Math.min(255, Math.round(rgba[1] * 255)));\n const b = Math.max(0, Math.min(255, Math.round(rgba[2] * 255)));\n const a = Math.max(0, Math.min(1, rgba[3]));\n return `rgba(${r},${g},${b},${a})`;\n};\n\nconst withAlpha = (cssColor: string, alphaMultiplier: number): string => {\n const parsed = parseCssColorToRgba01(cssColor);\n if (!parsed) return cssColor;\n const a = Math.max(0, Math.min(1, parsed[3] * alphaMultiplier));\n return rgba01ToCssRgba([parsed[0], parsed[1], parsed[2], a]);\n};\n\n\nconst computePlotClipRect = (\n gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number } => {\n const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeft = left * devicePixelRatio;\n const plotRight = canvasWidth - right * devicePixelRatio;\n const plotTop = top * devicePixelRatio;\n const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n return {\n left: plotLeftClip,\n right: plotRightClip,\n top: plotTopClip,\n bottom: plotBottomClip,\n };\n};\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst lerp = (a: number, b: number, t01: number): number => a + (b - a) * clamp01(t01);\n\nconst lerpDomain = (\n from: { readonly min: number; readonly max: number },\n to: { readonly min: number; readonly max: number },\n t01: number\n): { readonly min: number; readonly max: number } => {\n return normalizeDomain(lerp(from.min, to.min, t01), lerp(from.max, to.max, t01));\n};\n\nconst computePlotScissorDevicePx = (\n gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n const plotLeftDevice = gridArea.left * devicePixelRatio;\n const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n const plotTopDevice = gridArea.top * devicePixelRatio;\n const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n const scissorW = Math.max(0, scissorR - scissorX);\n const scissorH = Math.max(0, scissorB - scissorY);\n\n return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nconst clipXToCanvasCssPx = (xClip: number, canvasCssWidth: number): number => ((xClip + 1) / 2) * canvasCssWidth;\nconst clipYToCanvasCssPx = (yClip: number, canvasCssHeight: number): number => ((1 - yClip) / 2) * canvasCssHeight;\n\n// Alias for imported function to maintain compatibility with existing code\nconst isTupleOHLCDataPoint = isTupleOHLCDataPointImported;\n\nconst parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (typeof value !== 'string') return null;\n\n const s = value.trim();\n if (s.length === 0) return null;\n\n if (s.endsWith('%')) {\n const pct = Number.parseFloat(s.slice(0, -1));\n if (!Number.isFinite(pct)) return null;\n return (pct / 100) * basis;\n }\n\n // Be permissive: allow numeric strings like \"120\".\n const n = Number.parseFloat(s);\n return Number.isFinite(n) ? n : null;\n};\n\nconst resolvePieCenterPlotCss = (\n center: PieCenter | undefined,\n plotWidthCss: number,\n plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n const xRaw = center?.[0] ?? '50%';\n const yRaw = center?.[1] ?? '50%';\n\n const x = parseNumberOrPercent(xRaw, plotWidthCss);\n const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n return {\n x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n };\n};\n\nconst isPieRadiusTuple = (\n radius: PieRadius\n): radius is readonly [inner: number | string, outer: number | string] => Array.isArray(radius);\n\nconst resolvePieRadiiCss = (\n radius: PieRadius | undefined,\n maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n // Default similar to common chart libs (mirrors `createPieRenderer.ts`).\n if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n if (isPieRadiusTuple(radius)) {\n const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n }\n\n const outer = parseNumberOrPercent(radius, maxRadiusCss);\n const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\nconst pad2 = (n: number): string => String(Math.trunc(n)).padStart(2, '0');\n\nconst MONTH_SHORT_EN: readonly string[] = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n];\n\nconst formatTimeTickValue = (timestampMs: number, visibleRangeMs: number): string | null => {\n if (!Number.isFinite(timestampMs)) return null;\n if (!Number.isFinite(visibleRangeMs) || visibleRangeMs < 0) visibleRangeMs = 0;\n\n const d = new Date(timestampMs);\n // Guard against out-of-range timestamps that produce an invalid Date.\n if (!Number.isFinite(d.getTime())) return null;\n const yyyy = d.getFullYear();\n const mm = d.getMonth() + 1; // 1-12\n const dd = d.getDate();\n const hh = d.getHours();\n const min = d.getMinutes();\n\n // Requirements (range in ms):\n // - < 1 day: HH:mm\n // - 1-7 days: MM/DD HH:mm\n // - 1-12 weeks (and up to ~3 months): MM/DD\n // - 3-12 months: MMM DD\n // - > 1 year: YYYY/MM\n if (visibleRangeMs < MS_PER_DAY) {\n return `${pad2(hh)}:${pad2(min)}`;\n }\n // Treat the 7-day boundary as inclusive for the “1–7 days” tier.\n if (visibleRangeMs <= 7 * MS_PER_DAY) {\n return `${pad2(mm)}/${pad2(dd)} ${pad2(hh)}:${pad2(min)}`;\n }\n // Keep short calendar dates until the visible range reaches ~3 months.\n // (This covers the 1–12 week requirement, plus the small 12w→3m gap.)\n if (visibleRangeMs < 3 * MS_PER_MONTH_APPROX) {\n return `${pad2(mm)}/${pad2(dd)}`;\n }\n if (visibleRangeMs <= MS_PER_YEAR_APPROX) {\n const mmm = MONTH_SHORT_EN[d.getMonth()] ?? pad2(mm);\n return `${mmm} ${pad2(dd)}`;\n }\n return `${yyyy}/${pad2(mm)}`;\n};\n\nconst generateLinearTicks = (domainMin: number, domainMax: number, tickCount: number): number[] => {\n const count = Math.max(1, Math.floor(tickCount));\n const ticks: number[] = new Array(count);\n for (let i = 0; i < count; i++) {\n const t = count === 1 ? 0.5 : i / (count - 1);\n ticks[i] = domainMin + t * (domainMax - domainMin);\n }\n return ticks;\n};\n\nconst computeAdaptiveTimeXAxisTicks = (params: {\n readonly axisMin: number | null;\n readonly axisMax: number | null;\n readonly xScale: LinearScale;\n readonly plotClipLeft: number;\n readonly plotClipRight: number;\n readonly canvasCssWidth: number;\n readonly visibleRangeMs: number;\n readonly measureCtx: CanvasRenderingContext2D | null;\n readonly measureCache?: Map<string, number>;\n readonly fontSize: number;\n readonly fontFamily: string;\n}): { readonly tickCount: number; readonly tickValues: readonly number[] } => {\n const {\n axisMin,\n axisMax,\n xScale,\n plotClipLeft,\n plotClipRight,\n canvasCssWidth,\n visibleRangeMs,\n measureCtx,\n measureCache,\n fontSize,\n fontFamily,\n } = params;\n\n // Domain fallback matches `createAxisRenderer` (use explicit min/max when provided).\n const domainMin = finiteOrNull(axisMin) ?? xScale.invert(plotClipLeft);\n const domainMax = finiteOrNull(axisMax) ?? xScale.invert(plotClipRight);\n\n if (!measureCtx || canvasCssWidth <= 0) {\n return { tickCount: DEFAULT_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, DEFAULT_TICK_COUNT) };\n }\n\n // Ensure the measurement font matches the overlay labels.\n measureCtx.font = `${fontSize}px ${fontFamily}`;\n if (measureCache && measureCache.size > 2000) measureCache.clear();\n\n // Pre-construct the font part of the cache key to avoid repeated concatenation.\n const cacheKeyPrefix = measureCache ? `${fontSize}px ${fontFamily}@@` : null;\n\n for (let tickCount = MAX_TIME_X_TICK_COUNT; tickCount >= MIN_TIME_X_TICK_COUNT; tickCount--) {\n const tickValues = generateLinearTicks(domainMin, domainMax, tickCount);\n\n // Compute label extents in *canvas-local CSS px* and ensure adjacent labels don't overlap.\n let prevRight = Number.NEGATIVE_INFINITY;\n let ok = true;\n\n for (let i = 0; i < tickValues.length; i++) {\n const v = tickValues[i]!;\n const label = formatTimeTickValue(v, visibleRangeMs);\n if (label == null) continue;\n\n const w = (() => {\n if (!cacheKeyPrefix) return measureCtx.measureText(label).width;\n const key = cacheKeyPrefix + label;\n const cached = measureCache!.get(key);\n if (cached != null) return cached;\n const measured = measureCtx.measureText(label).width;\n measureCache!.set(key, measured);\n return measured;\n })();\n const xClip = xScale.scale(v);\n const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n\n const anchor: TextOverlayAnchor =\n tickCount === 1 ? 'middle' : i === 0 ? 'start' : i === tickValues.length - 1 ? 'end' : 'middle';\n\n const left = anchor === 'start' ? xCss : anchor === 'end' ? xCss - w : xCss - w * 0.5;\n const right = anchor === 'start' ? xCss + w : anchor === 'end' ? xCss : xCss + w * 0.5;\n\n if (left < prevRight + MIN_X_LABEL_GAP_CSS_PX) {\n ok = false;\n break;\n }\n prevRight = right;\n }\n\n if (ok) {\n return { tickCount, tickValues };\n }\n }\n\n return { tickCount: MIN_TIME_X_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, MIN_TIME_X_TICK_COUNT) };\n};\n\nconst computeBaseXDomain = (\n options: ResolvedChartGPUOptions,\n runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null\n): { readonly min: number; readonly max: number } => {\n const bounds = computeGlobalBounds(options.series, runtimeRawBoundsByIndex);\n const baseMin = finiteOrUndefined(options.xAxis.min) ?? bounds.xMin;\n const baseMax = finiteOrUndefined(options.xAxis.max) ?? bounds.xMax;\n return normalizeDomain(baseMin, baseMax);\n};\n\n/**\n * Computes Y-axis domain bounds from the visible/rendered series data.\n * This avoids scanning the full raw dataset when yAxis.autoBounds === 'visible'.\n * \n * Performance: O(n) where n = total points across all visible series data.\n * This is called only when renderSeries changes (zoom/pan/data updates), not per-frame.\n */\nconst computeVisibleYBounds = (series: ResolvedChartGPUOptions['series']): Bounds => {\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let s = 0; s < series.length; s++) {\n const seriesConfig = series[s];\n // Pie series are non-cartesian; they don't participate in y bounds.\n if (seriesConfig.type === 'pie') continue;\n\n // Candlestick series: scan low/high from visible data\n if (seriesConfig.type === 'candlestick') {\n const visibleOHLC = seriesConfig.data as ReadonlyArray<OHLCDataPoint>;\n for (let i = 0; i < visibleOHLC.length; i++) {\n const p = visibleOHLC[i]!;\n const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n if (!Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n // Use Math.min/max to handle inverted low/high gracefully\n const yLow = Math.min(low, high);\n const yHigh = Math.max(low, high);\n\n if (yLow < yMin) yMin = yLow;\n if (yHigh > yMax) yMax = yHigh;\n }\n continue;\n }\n\n // Cartesian series (line, area, bar, scatter): scan y from visible data\n const data = seriesConfig.data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const y = getY(data, i);\n if (!Number.isFinite(y)) continue;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n }\n\n // Fallback for empty/invalid data: return safe default bounds\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n }\n\n // Degenerate domain: add unit span to avoid zero-width range\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin: 0, xMax: 1, yMin, yMax };\n};\n\nconst computeBaseYDomain = (\n options: ResolvedChartGPUOptions,\n runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null,\n visibleBoundsOverride?: Bounds | null\n): { readonly min: number; readonly max: number } => {\n // Explicit min/max ALWAYS take precedence over auto-bounds\n const explicitMin = finiteOrUndefined(options.yAxis.min);\n const explicitMax = finiteOrUndefined(options.yAxis.max);\n\n // If both min and max are explicit, use them directly (no auto-bounds needed)\n if (explicitMin !== undefined && explicitMax !== undefined) {\n return normalizeDomain(explicitMin, explicitMax);\n }\n\n // Determine which bounds to use based on autoBounds mode\n const autoBoundsMode = options.yAxis.autoBounds ?? 'visible';\n let bounds: Bounds;\n\n if (autoBoundsMode === 'visible' && visibleBoundsOverride) {\n // Use visible bounds from renderSeries (zoom-aware, computed from visible data only)\n bounds = visibleBoundsOverride;\n } else {\n // Use global bounds from full dataset (pre-zoom behavior, computed from all raw data)\n bounds = computeGlobalBounds(options.series, runtimeRawBoundsByIndex);\n }\n\n // Merge explicit bounds with computed bounds (partial override support)\n const yMin = explicitMin ?? bounds.yMin;\n const yMax = explicitMax ?? bounds.yMax;\n return normalizeDomain(yMin, yMax);\n};\n\nconst computeVisibleXDomain = (\n baseXDomain: { readonly min: number; readonly max: number },\n zoomRange?: ZoomRange | null\n): { readonly min: number; readonly max: number; readonly spanFraction: number } => {\n if (!zoomRange) return { ...baseXDomain, spanFraction: 1 };\n const span = baseXDomain.max - baseXDomain.min;\n if (!Number.isFinite(span) || span === 0) return { ...baseXDomain, spanFraction: 1 };\n\n const start = zoomRange.start;\n const end = zoomRange.end;\n const xMin = baseXDomain.min + (start / 100) * span;\n const xMax = baseXDomain.min + (end / 100) * span;\n const normalized = normalizeDomain(xMin, xMax);\n\n const fractionRaw = (end - start) / 100;\n const spanFraction = Number.isFinite(fractionRaw) ? Math.max(0, Math.min(1, fractionRaw)) : 1;\n return { min: normalized.min, max: normalized.max, spanFraction };\n};\n\ntype IntroPhase = 'pending' | 'running' | 'done';\n\nconst resolveAnimationConfig = (\n animation: ResolvedChartGPUOptions['animation']\n):\n | {\n readonly durationMs: number;\n readonly delayMs: number;\n readonly easing: EasingFunction;\n }\n | null => {\n if (animation === false || animation == null) return null;\n\n const cfg: AnimationConfig | null = animation === true ? {} : animation;\n if (!cfg) return null;\n\n const durationMsRaw = cfg.duration ?? 300;\n const delayMsRaw = cfg.delay ?? 0;\n\n const durationMs = Number.isFinite(durationMsRaw) ? Math.max(0, durationMsRaw) : 300;\n const delayMs = Number.isFinite(delayMsRaw) ? Math.max(0, delayMsRaw) : 0;\n\n return {\n durationMs,\n delayMs,\n easing: getEasing(cfg.easing),\n };\n};\n\nconst resolveIntroAnimationConfig = (animation: ResolvedChartGPUOptions['animation']) => resolveAnimationConfig(animation);\nconst resolveUpdateAnimationConfig = (animation: ResolvedChartGPUOptions['animation']) => resolveAnimationConfig(animation);\n\n/**\n * Computes container-local CSS pixel anchor coordinates for a candlestick tooltip.\n *\n * The anchor is positioned near the candle body center for stable tooltip positioning\n * even when the cursor is at the edge of the candlestick.\n *\n * Coordinate transformations:\n * 1. Domain values (timestamp, open, close) from CandlestickMatch\n * 2. → xScale/yScale transform to grid-local CSS pixels\n * 3. → Add gridArea offset to get canvas-local CSS pixels\n * 4. → Add canvas offset to get container-local CSS pixels\n *\n * Returns null if any coordinate computation fails (non-finite values).\n */\nconst computeCandlestickTooltipAnchor = (\n match: { readonly point: OHLCDataPoint },\n xScale: LinearScale,\n yScale: LinearScale,\n gridArea: GridArea,\n canvas: HTMLCanvasElement\n): Readonly<{ x: number; y: number }> | null => {\n const point = match.point;\n \n const timestamp = isTupleOHLCDataPoint(point) ? point[0] : point.timestamp;\n const open = isTupleOHLCDataPoint(point) ? point[1] : point.open;\n const close = isTupleOHLCDataPoint(point) ? point[2] : point.close;\n\n if (!Number.isFinite(timestamp) || !Number.isFinite(open) || !Number.isFinite(close)) {\n return null;\n }\n\n // Body center in domain space\n const bodyMidY = (open + close) / 2;\n\n // Transform to grid-local CSS pixels\n const xGridCss = xScale.scale(timestamp);\n const yGridCss = yScale.scale(bodyMidY);\n\n if (!Number.isFinite(xGridCss) || !Number.isFinite(yGridCss)) {\n return null;\n }\n\n // Convert to canvas-local CSS pixels\n const xCanvasCss = gridArea.left + xGridCss;\n const yCanvasCss = gridArea.top + yGridCss;\n\n // Convert to container-local CSS pixels\n const xContainerCss = isHTMLCanvasElement(canvas) ? canvas.offsetLeft + xCanvasCss : xCanvasCss;\n const yContainerCss = isHTMLCanvasElement(canvas) ? canvas.offsetTop + yCanvasCss : yCanvasCss;\n\n if (!Number.isFinite(xContainerCss) || !Number.isFinite(yContainerCss)) {\n return null;\n }\n\n return { x: xContainerCss, y: yContainerCss };\n};\n\nconst computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let s = 0; s < seriesConfigs.length; s++) {\n const data = seriesConfigs[s]!.data as CartesianSeriesData;\n const n = getPointCount(data);\n for (let i = 0; i < n; i++) {\n const y = getY(data, i);\n if (!Number.isFinite(y)) continue;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n }\n\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) return 0;\n if (yMin <= 0 && 0 <= yMax) return 0;\n return Math.abs(yMin) < Math.abs(yMax) ? yMin : yMax;\n};\n\nconst computeBaselineForBarsFromAxis = (\n seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n yScale: LinearScale,\n plotClipRect: Readonly<{ top: number; bottom: number }>\n): number => {\n const yDomainA = yScale.invert(plotClipRect.bottom);\n const yDomainB = yScale.invert(plotClipRect.top);\n const yMin = Math.min(yDomainA, yDomainB);\n const yMax = Math.max(yDomainA, yDomainB);\n\n if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return computeBaselineForBarsFromData(seriesConfigs);\n }\n\n if (yMin <= 0 && 0 <= yMax) return 0;\n if (yMin > 0) return yMin;\n if (yMax < 0) return yMax;\n return computeBaselineForBarsFromData(seriesConfigs);\n};\n\nconst createAnimatedBarYScale = (\n baseYScale: LinearScale,\n plotClipRect: Readonly<{ top: number; bottom: number }>,\n barSeriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n progress01: number\n): LinearScale => {\n const p = clamp01(progress01);\n if (p >= 1) return baseYScale;\n\n const baselineDomain = computeBaselineForBarsFromAxis(barSeriesConfigs, baseYScale, plotClipRect);\n const baselineClip = baseYScale.scale(baselineDomain);\n\n const wrapper: LinearScale = {\n domain(min: number, max: number) {\n baseYScale.domain(min, max);\n return wrapper;\n },\n range(min: number, max: number) {\n baseYScale.range(min, max);\n return wrapper;\n },\n scale(value: number) {\n const v = baseYScale.scale(value);\n if (!Number.isFinite(v) || !Number.isFinite(baselineClip)) return v;\n return baselineClip + (v - baselineClip) * p;\n },\n invert(pixel: number) {\n return baseYScale.invert(pixel);\n },\n };\n\n return wrapper;\n};\n\nexport function createRenderCoordinator(\n gpuContext: GPUContext,\n options: ResolvedChartGPUOptions,\n callbacks?: RenderCoordinatorCallbacks\n): RenderCoordinator {\n if (!gpuContext.initialized) {\n throw new Error('RenderCoordinator: gpuContext must be initialized.');\n }\n const device = gpuContext.device;\n if (!device) {\n throw new Error('RenderCoordinator: gpuContext.device is required.');\n }\n if (!gpuContext.canvas) {\n throw new Error('RenderCoordinator: gpuContext.canvas is required.');\n }\n if (!gpuContext.canvasContext) {\n throw new Error('RenderCoordinator: gpuContext.canvasContext is required.');\n }\n\n // Listen for device loss and emit callback\n // Note: We don't call dispose() here to avoid double-cleanup if user calls dispose() in callback.\n // The coordinator is effectively non-functional after device loss until re-created.\n device.lost.then((info) => {\n callbacks?.onDeviceLost?.(info.message || info.reason || 'unknown');\n }).catch(() => {\n // Ignore errors in device.lost promise (can occur if device is destroyed before lost promise resolves)\n });\n\n const targetFormat = gpuContext.preferredFormat ?? DEFAULT_TARGET_FORMAT;\n \n // DOM-dependent features (overlays, legends) require HTMLCanvasElement.\n const overlayContainer = isHTMLCanvasElement(gpuContext.canvas) ? gpuContext.canvas.parentElement : null;\n const axisLabelOverlay: TextOverlay | null = overlayContainer ? createTextOverlay(overlayContainer) : null;\n // Dedicated overlay for annotations (do not reuse axis label overlay).\n const annotationOverlay: TextOverlay | null = overlayContainer ? createTextOverlay(overlayContainer) : null;\n\n const handleSeriesToggle = (seriesIndex: number, sliceIndex?: number): void => {\n if (disposed) return;\n\n const series = currentOptions.series;\n if (seriesIndex < 0 || seriesIndex >= series.length) return;\n\n const s = series[seriesIndex];\n if (!s) return;\n\n // Handle pie slice toggle\n if (sliceIndex !== undefined && s.type === 'pie') {\n const pieData = (s as ResolvedPieSeriesConfig).data;\n if (sliceIndex < 0 || sliceIndex >= pieData.length) return;\n\n const updatedData = pieData.map((slice, i) =>\n i === sliceIndex\n ? { ...slice, visible: slice.visible === false ? true : false }\n : slice\n );\n\n const updatedSeries = series.map((seriesItem, i) =>\n i === seriesIndex\n ? ({ ...seriesItem, data: updatedData } as typeof seriesItem)\n : seriesItem\n );\n\n setOptions({ ...currentOptions, series: updatedSeries });\n return;\n }\n\n // Toggle regular series visibility\n const updatedSeries = series.map((seriesItem, i) =>\n i === seriesIndex\n ? ({ ...seriesItem, visible: seriesItem.visible === false ? true : false } as typeof seriesItem)\n : seriesItem\n );\n\n // Update options with new series array\n setOptions({ ...currentOptions, series: updatedSeries });\n };\n\n const legend: Legend | null = overlayContainer ? createLegend(overlayContainer, 'right', handleSeriesToggle) : null;\n // Text measurement for axis labels. Only available in DOM contexts (not worker threads).\n const tickMeasureCtx: CanvasRenderingContext2D | null = (() => {\n if (typeof document === 'undefined') {\n // Worker thread: DOM not available.\n return null;\n }\n try {\n const c = document.createElement('canvas');\n return c.getContext('2d');\n } catch {\n return null;\n }\n })();\n const tickMeasureCache: Map<string, number> | null = tickMeasureCtx ? new Map() : null;\n\n let disposed = false;\n let currentOptions: ResolvedChartGPUOptions = options;\n let lastSeriesCount = options.series.length;\n\n // Story 5.16: initial-load intro animation (series marks only).\n let introPhase: IntroPhase = 'pending';\n let introProgress01 = 0;\n const introAnimController = createAnimationController();\n let introAnimId: AnimationId | null = null;\n\n // Story 5.17 (step 1): data update transition state (snapshots only; interpolation occurs later).\n type UpdateTransitionSnapshot = Readonly<{\n readonly xBaseDomain: { readonly min: number; readonly max: number };\n readonly xVisibleDomain: { readonly min: number; readonly max: number };\n readonly yBaseDomain: { readonly min: number; readonly max: number };\n readonly series: ResolvedChartGPUOptions['series'];\n }>;\n\n type UpdateTransition = Readonly<{\n readonly from: UpdateTransitionSnapshot;\n readonly to: UpdateTransitionSnapshot;\n }>;\n\n let hasRenderedOnce = false;\n const updateAnimController = createAnimationController();\n let updateAnimId: AnimationId | null = null;\n let updateProgress01 = 1;\n let updateTransition: UpdateTransition | null = null;\n\n type UpdateInterpolationCaches = Readonly<{\n readonly cartesianDataBySeriesIndex: Array<DataPoint[] | null>;\n readonly pieDataBySeriesIndex: Array<ResolvedPieSeriesConfig['data'] | null>;\n }>;\n\n const updateInterpolationCaches: UpdateInterpolationCaches = {\n cartesianDataBySeriesIndex: [],\n pieDataBySeriesIndex: [],\n };\n\n const resetUpdateInterpolationCaches = (): void => {\n updateInterpolationCaches.cartesianDataBySeriesIndex.length = 0;\n updateInterpolationCaches.pieDataBySeriesIndex.length = 0;\n };\n\n const interpolateCartesianSeriesDataByIndex = (\n fromData: ReadonlyArray<DataPoint>,\n toData: ReadonlyArray<DataPoint>,\n t01: number,\n cache: DataPoint[] | null\n ): DataPoint[] | null => {\n if (fromData.length !== toData.length) return null;\n const n = toData.length;\n if (n === 0) return cache ?? [];\n\n const out =\n cache && cache.length === n\n ? cache\n : (() => {\n const created: DataPoint[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const pTo = toData[i]!;\n const { x } = getPointXY(pTo);\n const size = isTupleDataPoint(pTo) ? pTo[2] : (pTo as any)?.size;\n created[i] = isTupleDataPoint(pTo)\n ? (size == null ? ([x, 0] as const) : ([x, 0, size] as const))\n : (size == null ? ({ x, y: 0 } as const) : ({ x, y: 0, size } as const));\n }\n return created;\n })();\n\n const t = clamp01(t01);\n for (let i = 0; i < n; i++) {\n const yFrom = getPointXY(fromData[i]!).y;\n const yTo = getPointXY(toData[i]!).y;\n const y = Number.isFinite(yFrom) && Number.isFinite(yTo) ? lerp(yFrom, yTo, t) : yTo;\n const p = out[i]!;\n if (isTupleDataPoint(p)) {\n (p as unknown as number[])[1] = y;\n } else {\n (p as any).y = y;\n }\n }\n\n return out;\n };\n\n const interpolatePieSeriesByIndex = (\n fromSeries: ResolvedPieSeriesConfig,\n toSeries: ResolvedPieSeriesConfig,\n t01: number,\n cache: ResolvedPieSeriesConfig['data'] | null\n ): ResolvedPieSeriesConfig => {\n const fromData = fromSeries.data;\n const toData = toSeries.data;\n if (fromData.length !== toData.length) return toSeries;\n\n const n = toData.length;\n const out =\n cache && cache.length === n\n ? cache\n : (() => {\n const created: any[] = new Array(n);\n for (let i = 0; i < n; i++) {\n // Preserve name/color from \"to\"; patch value per frame.\n created[i] = { ...toData[i]!, value: 0 };\n }\n return created as ResolvedPieSeriesConfig['data'];\n })();\n\n const t = clamp01(t01);\n for (let i = 0; i < n; i++) {\n const vFrom = (fromData[i] as any)?.value;\n const vTo = (toData[i] as any)?.value;\n const next =\n typeof vFrom === 'number' && typeof vTo === 'number' && Number.isFinite(vFrom) && Number.isFinite(vTo)\n ? Math.max(0, lerp(vFrom, vTo, t))\n : typeof vTo === 'number' && Number.isFinite(vTo)\n ? vTo\n : 0;\n (out[i] as any).value = next;\n }\n\n return { ...toSeries, data: out };\n };\n\n const interpolateSeriesForUpdate = (\n fromSeries: ResolvedChartGPUOptions['series'],\n toSeries: ResolvedChartGPUOptions['series'],\n t01: number,\n caches: UpdateInterpolationCaches | null\n ): ResolvedChartGPUOptions['series'] => {\n if (fromSeries.length !== toSeries.length) return toSeries;\n\n const out: ResolvedChartGPUOptions['series'][number][] = new Array(toSeries.length);\n\n for (let i = 0; i < toSeries.length; i++) {\n const a = fromSeries[i]!;\n const b = toSeries[i]!;\n\n if (a.type !== b.type) {\n out[i] = b;\n continue;\n }\n\n if (b.type === 'pie') {\n const cache = caches?.pieDataBySeriesIndex[i] ?? null;\n const animated = interpolatePieSeriesByIndex(a as ResolvedPieSeriesConfig, b as ResolvedPieSeriesConfig, t01, cache);\n if (caches) caches.pieDataBySeriesIndex[i] = animated.data as any;\n out[i] = animated;\n continue;\n }\n\n // Cartesian series: interpolate y-values by index. Keep x from \"to\".\n const aAny = a as unknown as { readonly data: ReadonlyArray<DataPoint> };\n const bAny = b as unknown as { readonly data: ReadonlyArray<DataPoint> };\n const aData = aAny.data;\n const bData = bAny.data;\n\n if (aData.length !== bData.length) {\n out[i] = b;\n continue;\n }\n if (bData.length > MAX_ANIMATED_POINTS_PER_SERIES) {\n out[i] = b;\n continue;\n }\n\n const cache = caches?.cartesianDataBySeriesIndex[i] ?? null;\n const animatedData = interpolateCartesianSeriesDataByIndex(aData, bData, t01, cache);\n if (!animatedData) {\n out[i] = b;\n continue;\n }\n if (caches) caches.cartesianDataBySeriesIndex[i] = animatedData;\n\n out[i] = { ...(b as any), data: animatedData };\n }\n\n return out;\n };\n\n const computeUpdateSnapshotAtProgress = (\n transition: UpdateTransition,\n t01: number,\n zoomRange: ZoomRange | null\n ): UpdateTransitionSnapshot => {\n const xBase = lerpDomain(transition.from.xBaseDomain, transition.to.xBaseDomain, t01);\n const xVisible = computeVisibleXDomain(xBase, zoomRange);\n const yBase = lerpDomain(transition.from.yBaseDomain, transition.to.yBaseDomain, t01);\n const series = interpolateSeriesForUpdate(transition.from.series, transition.to.series, t01, null);\n return {\n xBaseDomain: xBase,\n xVisibleDomain: { min: xVisible.min, max: xVisible.max },\n yBaseDomain: yBase,\n series,\n };\n };\n\n // Prevent spamming console.warn for repeated misuse.\n const warnedPieAppendSeries = new Set<number>();\n const warnedSamplingDefeatsFastPath = new Set<number>();\n\n // Coordinator-owned runtime series store (cartesian only).\n // - `runtimeRawDataByIndex[i]` owns a mutable array for streaming appends.\n // - `runtimeRawBoundsByIndex[i]` tracks raw bounds for axis auto-bounds and zoom mapping.\n let runtimeRawDataByIndex: Array<DataPoint[] | OHLCDataPoint[] | null> = new Array(options.series.length).fill(null);\n let runtimeRawBoundsByIndex: Array<Bounds | null> = new Array(options.series.length).fill(null);\n\n // Baseline sampled series list derived from runtime raw data (used as the “full span” baseline).\n // Zoom-visible resampling is derived from this baseline + runtime raw as needed.\n let runtimeBaseSeries: ResolvedChartGPUOptions['series'] = currentOptions.series;\n\n // Zoom-aware sampled series list used for rendering + cartesian hit-testing.\n // Derived from `currentOptions.series` (which still includes baseline sampled `data`).\n let renderSeries: ResolvedChartGPUOptions['series'] = currentOptions.series;\n\n // Cache for visible y-bounds computed from renderSeries (for yAxis.autoBounds === 'visible').\n // Recomputed whenever renderSeries changes (zoom/pan/data updates).\n let cachedVisibleYBounds: Bounds | null = null;\n\n const shouldComputeVisibleYBounds = (opts: ResolvedChartGPUOptions): boolean => {\n const autoBoundsMode = opts.yAxis.autoBounds ?? 'visible';\n if (autoBoundsMode !== 'visible') return false;\n // If both bounds are explicit, auto-bounds (including visible) are never consulted.\n const explicitMin = finiteOrUndefined(opts.yAxis.min);\n const explicitMax = finiteOrUndefined(opts.yAxis.max);\n return !(explicitMin !== undefined && explicitMax !== undefined);\n };\n\n const recomputeCachedVisibleYBoundsIfNeeded = (): void => {\n if (shouldComputeVisibleYBounds(currentOptions)) {\n cachedVisibleYBounds = computeVisibleYBounds(renderSeries);\n } else {\n cachedVisibleYBounds = null;\n }\n };\n\n // Cache for sampled data with buffer zones - enables fast slicing during pan without resampling.\n interface SampledDataCache {\n data: ReadonlyArray<DataPoint> | ReadonlyArray<OHLCDataPoint>;\n cachedRange: { min: number; max: number };\n timestamp: number;\n }\n let lastSampledData: Array<SampledDataCache | null> = [];\n\n // Unified flush scheduler (appends + zoom-aware resampling + optional GPU streaming updates).\n let flushScheduled = false;\n let flushRafId: number | null = null;\n let flushTimeoutId: number | null = null;\n\n // Zoom changes are debounced to avoid churn while wheel/drag is active.\n // When the debounce fires, we mark resampling \"due\" and schedule a unified flush.\n let zoomResampleDebounceTimer: number | null = null;\n let zoomResampleDue = false;\n\n // Zoom changes can fire multiple times per frame; slicing and visible-bounds recompute can be O(n).\n // Coalesce those updates to at most once per rendered frame.\n let sliceRenderSeriesDue = false;\n\n // Coalesced streaming appends (flushed at the start of `render()`).\n const pendingAppendByIndex = new Map<number, Array<DataPoint | OHLCDataPoint>>();\n\n // Tracks what the DataStore currently represents for each series index.\n // Used to decide whether `appendSeries(...)` is a correct fast-path.\n type GpuSeriesKind = 'unknown' | 'fullRawLine' | 'other';\n let gpuSeriesKindByIndex: GpuSeriesKind[] = new Array(currentOptions.series.length).fill('unknown');\n const appendedGpuThisFrame = new Set<number>();\n\n // Tooltip is a DOM overlay element; enable by default unless explicitly disabled.\n let tooltip: Tooltip | null =\n overlayContainer && currentOptions.tooltip?.show !== false ? createTooltip(overlayContainer) : null;\n\n // Cache tooltip state to avoid unnecessary DOM updates\n let lastTooltipContent: string | null = null;\n let lastTooltipX: number | null = null;\n let lastTooltipY: number | null = null;\n\n // Helper functions for tooltip/legend management\n const showTooltipInternal = (x: number, y: number, content: string, _params: TooltipParams | TooltipParams[]) => {\n tooltip?.show(x, y, content);\n };\n\n const hideTooltipInternal = () => {\n tooltip?.hide();\n };\n\n const hideTooltip = () => {\n lastTooltipContent = null;\n lastTooltipX = null;\n lastTooltipY = null;\n hideTooltipInternal();\n };\n\n const updateLegend = (series: ResolvedChartGPUOptions['series'], theme: ResolvedChartGPUOptions['theme']) => {\n legend?.update(series, theme);\n };\n\n updateLegend(currentOptions.series, currentOptions.theme);\n\n let dataStore = createDataStore(device);\n\n const gridRenderer = createGridRenderer(device, { targetFormat });\n const xAxisRenderer = createAxisRenderer(device, { targetFormat });\n const yAxisRenderer = createAxisRenderer(device, { targetFormat });\n const crosshairRenderer = createCrosshairRenderer(device, { targetFormat });\n crosshairRenderer.setVisible(false);\n const highlightRenderer = createHighlightRenderer(device, { targetFormat });\n highlightRenderer.setVisible(false);\n\n // MSAA for the *annotation overlay* (above-series) pass to reduce shimmer during zoom.\n // NOTE: In WebGPU, pipeline sampleCount must match the render pass attachment sampleCount.\n // To keep MSAA scoped, we render the main scene to a single-sample texture, then:\n // - MSAA overlay pass: blit main scene into an MSAA target + draw above-series annotations, resolve to swapchain\n // - Top overlay pass: draw crosshair/axes/highlight (single-sample) on top of the resolved swapchain\n const ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT = 4;\n\n const referenceLineRenderer = createReferenceLineRenderer(device, { targetFormat });\n const annotationMarkerRenderer = createAnnotationMarkerRenderer(device, { targetFormat });\n const referenceLineRendererMsaa = createReferenceLineRenderer(device, {\n targetFormat,\n sampleCount: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT,\n });\n const annotationMarkerRendererMsaa = createAnnotationMarkerRenderer(device, {\n targetFormat,\n sampleCount: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT,\n });\n\n let mainColorTexture: GPUTexture | null = null;\n let mainColorView: GPUTextureView | null = null;\n let overlayMsaaTexture: GPUTexture | null = null;\n let overlayMsaaView: GPUTextureView | null = null;\n let overlayTargetsWidth = 0;\n let overlayTargetsHeight = 0;\n let overlayTargetsFormat: GPUTextureFormat | null = null;\n\n const OVERLAY_BLIT_WGSL = `\nstruct VSOut { @builtin(position) pos: vec4f };\n\n@vertex\nfn vsMain(@builtin(vertex_index) i: u32) -> VSOut {\n var positions = array<vec2f, 3>(\n vec2f(-1.0, -1.0),\n vec2f( 3.0, -1.0),\n vec2f(-1.0, 3.0)\n );\n var o: VSOut;\n o.pos = vec4f(positions[i], 0.0, 1.0);\n return o;\n}\n\n// Using textureLoad (no filtering) for pixel-exact blit into the MSAA overlay pass.\n@group(0) @binding(0) var srcTex: texture_2d<f32>;\n\n@fragment\nfn fsMain(@builtin(position) pos: vec4f) -> @location(0) vec4f {\n let xy = vec2<i32>(pos.xy);\n return textureLoad(srcTex, xy, 0);\n}\n`;\n\n const overlayBlitBindGroupLayout = device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float', viewDimension: '2d' } }],\n });\n\n const overlayBlitPipeline = createRenderPipeline(device, {\n label: 'renderCoordinator/overlayBlitPipeline',\n bindGroupLayouts: [overlayBlitBindGroupLayout],\n vertex: { code: OVERLAY_BLIT_WGSL, label: 'renderCoordinator/overlayBlit.wgsl' },\n fragment: { code: OVERLAY_BLIT_WGSL, label: 'renderCoordinator/overlayBlit.wgsl', formats: targetFormat },\n primitive: { topology: 'triangle-list', cullMode: 'none' },\n multisample: { count: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT },\n });\n\n let overlayBlitBindGroup: GPUBindGroup | null = null;\n\n const destroyTexture = (tex: GPUTexture | null): void => {\n if (!tex) return;\n try {\n tex.destroy();\n } catch {\n // best-effort\n }\n };\n\n const ensureOverlayTargets = (canvasWidthDevicePx: number, canvasHeightDevicePx: number): void => {\n const w = Number.isFinite(canvasWidthDevicePx) ? Math.max(1, Math.floor(canvasWidthDevicePx)) : 1;\n const h = Number.isFinite(canvasHeightDevicePx) ? Math.max(1, Math.floor(canvasHeightDevicePx)) : 1;\n\n if (mainColorTexture && overlayMsaaTexture && overlayBlitBindGroup && overlayTargetsWidth === w && overlayTargetsHeight === h && overlayTargetsFormat === targetFormat) {\n return;\n }\n\n destroyTexture(mainColorTexture);\n destroyTexture(overlayMsaaTexture);\n\n mainColorTexture = device.createTexture({\n label: 'renderCoordinator/mainColorTexture',\n size: { width: w, height: h },\n format: targetFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n mainColorView = mainColorTexture.createView();\n\n overlayMsaaTexture = device.createTexture({\n label: 'renderCoordinator/annotationOverlayMsaaTexture',\n size: { width: w, height: h },\n sampleCount: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT,\n format: targetFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n overlayMsaaView = overlayMsaaTexture.createView();\n\n overlayBlitBindGroup = device.createBindGroup({\n label: 'renderCoordinator/overlayBlitBindGroup',\n layout: overlayBlitBindGroupLayout,\n entries: [{ binding: 0, resource: mainColorView }],\n });\n\n overlayTargetsWidth = w;\n overlayTargetsHeight = h;\n overlayTargetsFormat = targetFormat;\n };\n\n const initialGridArea = computeGridArea(gpuContext, currentOptions);\n \n // Event manager requires HTMLCanvasElement (DOM events).\n const eventManager = isHTMLCanvasElement(gpuContext.canvas) \n ? createEventManager(gpuContext.canvas, initialGridArea)\n : null;\n\n type PointerSource = 'mouse' | 'sync';\n\n type PointerState = Readonly<{\n source: PointerSource;\n x: number;\n y: number;\n gridX: number;\n gridY: number;\n isInGrid: boolean;\n hasPointer: boolean;\n }>;\n\n let pointerState: PointerState = {\n source: 'mouse',\n x: 0,\n y: 0,\n gridX: 0,\n gridY: 0,\n isInGrid: false,\n hasPointer: false,\n };\n\n // Interaction-x state (domain units). This drives chart sync.\n let interactionX: number | null = null;\n let interactionXSource: unknown = undefined;\n const interactionXListeners = new Set<(x: number | null, source?: unknown) => void>();\n\n // Cached interaction scales from the last render (used for pointer -> domain-x mapping).\n let lastInteractionScales:\n | {\n readonly xScale: LinearScale;\n readonly yScale: LinearScale;\n readonly plotWidthCss: number;\n readonly plotHeightCss: number;\n }\n | null = null;\n\n const emitInteractionX = (nextX: number | null, source?: unknown): void => {\n const snapshot = Array.from(interactionXListeners);\n for (const cb of snapshot) cb(nextX, source);\n };\n\n const setInteractionXInternal = (nextX: number | null, source?: unknown): void => {\n const normalized = nextX !== null && Number.isFinite(nextX) ? nextX : null;\n if (interactionX === normalized && interactionXSource === source) return;\n interactionX = normalized;\n interactionXSource = source;\n emitInteractionX(interactionX, interactionXSource);\n };\n\n const requestRender = (): void => {\n callbacks?.onRequestRender?.();\n };\n\n const isFullSpanZoomRange = (range: ZoomRange | null): boolean => {\n if (!range) return true;\n return (\n Number.isFinite(range.start) &&\n Number.isFinite(range.end) &&\n range.start <= 0 &&\n range.end >= 100\n );\n };\n\n const cancelScheduledFlush = (): void => {\n if (flushRafId !== null) {\n cancelAnimationFrame(flushRafId);\n flushRafId = null;\n }\n if (flushTimeoutId !== null) {\n clearTimeout(flushTimeoutId);\n flushTimeoutId = null;\n }\n flushScheduled = false;\n };\n\n const cancelZoomResampleDebounce = (): void => {\n if (zoomResampleDebounceTimer !== null) {\n clearTimeout(zoomResampleDebounceTimer);\n zoomResampleDebounceTimer = null;\n }\n };\n\n const flushPendingAppends = (): boolean => {\n if (pendingAppendByIndex.size === 0) return false;\n\n appendedGpuThisFrame.clear();\n\n const zoomRangeBefore = zoomState?.getRange() ?? null;\n const isFullSpanZoomBefore = isFullSpanZoomRange(zoomRangeBefore);\n const canAutoScroll =\n currentOptions.autoScroll === true &&\n zoomState != null &&\n currentOptions.xAxis.min == null &&\n currentOptions.xAxis.max == null;\n\n // Capture the pre-append visible domain so we can preserve it for “panned away” behavior.\n const prevBaseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const prevVisibleXDomain = zoomRangeBefore ? computeVisibleXDomain(prevBaseXDomain, zoomRangeBefore) : null;\n\n let didAppendAny = false;\n\n for (const [seriesIndex, points] of pendingAppendByIndex) {\n if (points.length === 0) continue;\n const s = currentOptions.series[seriesIndex];\n if (!s || s.type === 'pie') continue;\n didAppendAny = true;\n\n if (s.type === 'candlestick') {\n // Handle candlestick OHLC data.\n let raw = runtimeRawDataByIndex[seriesIndex] as OHLCDataPoint[] | null;\n if (!raw) {\n const seed = (s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>;\n raw = seed.length === 0 ? [] : seed.slice();\n runtimeRawDataByIndex[seriesIndex] = raw;\n runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? null;\n }\n\n const ohlcPoints = points as unknown as ReadonlyArray<OHLCDataPoint>;\n raw.push(...ohlcPoints);\n runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithOHLCDataPoints(\n runtimeRawBoundsByIndex[seriesIndex],\n ohlcPoints\n );\n } else {\n // Handle other cartesian series (line, area, bar, scatter).\n let raw = runtimeRawDataByIndex[seriesIndex] as DataPoint[] | null;\n if (!raw) {\n const seed = (s.rawData ?? s.data) as CartesianSeriesData;\n raw = cartesianDataToDataPointArray(seed);\n runtimeRawDataByIndex[seriesIndex] = raw;\n runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? computeRawBoundsFromCartesianData(seed);\n }\n\n const dataPoints = points as unknown as ReadonlyArray<DataPoint>;\n \n // Optional fast-path: if the GPU buffer currently represents the full, unsampled line series,\n // we can append just the new points to the existing GPU buffer (no full re-upload).\n const canUseFastPath =\n s.type === 'line' && s.sampling === 'none' && isFullSpanZoomBefore && gpuSeriesKindByIndex[seriesIndex] === 'fullRawLine';\n\n if (canUseFastPath) {\n try {\n dataStore.appendSeries(seriesIndex, dataPoints);\n appendedGpuThisFrame.add(seriesIndex);\n } catch {\n // If the DataStore has not been initialized for this index (or any other error occurs),\n // fall back to the normal full upload path later in render().\n }\n } else if (s.type === 'line' && s.sampling !== 'none' && !warnedSamplingDefeatsFastPath.has(seriesIndex)) {\n // Warn users that sampling defeats the incremental append optimization\n warnedSamplingDefeatsFastPath.add(seriesIndex);\n console.warn(\n `[ChartGPU] appendData() on series ${seriesIndex} with sampling='${s.sampling}' causes full buffer re-upload every frame. ` +\n `For optimal streaming performance, use sampling='none'. ` +\n `See docs/internal/INCREMENTAL_APPEND_OPTIMIZATION.md for details.`\n );\n }\n\n raw.push(...dataPoints);\n runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithDataPoints(\n runtimeRawBoundsByIndex[seriesIndex],\n dataPoints\n );\n }\n\n // Invalidate cache for this series since data has changed\n lastSampledData[seriesIndex] = null;\n }\n\n pendingAppendByIndex.clear();\n if (!didAppendAny) return false;\n\n // Dataset-aware zoom span constraints depend on raw point density.\n // When streaming appends add points, recompute and apply constraints so wheel+slider remain consistent.\n if (zoomState) {\n const constraints = computeEffectiveZoomSpanConstraints();\n const withConstraints = zoomState as unknown as {\n setSpanConstraints?: (minSpan: number, maxSpan: number) => void;\n };\n withConstraints.setSpanConstraints?.(constraints.minSpan, constraints.maxSpan);\n }\n\n // Auto-scroll is applied only on append (not on `setOptions`).\n if (canAutoScroll && zoomRangeBefore && prevVisibleXDomain) {\n const r = zoomRangeBefore;\n if (r.end >= 99.5) {\n const span = r.end - r.start;\n const anchored = zoomState! as unknown as {\n setRangeAnchored?: (start: number, end: number, anchor: 'start' | 'end' | 'center') => void;\n };\n // Keep end pinned when constraints clamp the span.\n if (anchored.setRangeAnchored) {\n anchored.setRangeAnchored(100 - span, 100, 'end');\n } else {\n zoomState!.setRange(100 - span, 100);\n }\n } else {\n const nextBaseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const span = nextBaseXDomain.max - nextBaseXDomain.min;\n if (Number.isFinite(span) && span > 0) {\n const nextStartRaw = ((prevVisibleXDomain.min - nextBaseXDomain.min) / span) * 100;\n const nextEndRaw = ((prevVisibleXDomain.max - nextBaseXDomain.min) / span) * 100;\n // Clamp defensively; ZoomState also clamps/orders internally.\n const nextStart = Math.max(0, Math.min(100, nextStartRaw));\n const nextEnd = Math.max(0, Math.min(100, nextEndRaw));\n zoomState!.setRange(nextStart, nextEnd);\n }\n }\n }\n\n recomputeRuntimeBaseSeries();\n\n // If zoom is disabled or full-span, `renderSeries` is just the baseline.\n // (Zoom-visible resampling is handled by the unified flush when needed.)\n const zoomRangeAfter = zoomState?.getRange() ?? null;\n if (zoomRangeAfter == null || isFullSpanZoomRange(zoomRangeAfter)) {\n renderSeries = runtimeBaseSeries;\n // Recompute visible y-bounds from the baseline series\n recomputeCachedVisibleYBoundsIfNeeded();\n }\n\n return true;\n };\n\n const executeFlush = (options?: { readonly requestRenderAfter?: boolean }): void => {\n if (disposed) return;\n\n const requestRenderAfter = options?.requestRenderAfter ?? true;\n\n const didAppend = flushPendingAppends();\n\n const zoomRange = zoomState?.getRange() ?? null;\n const zoomIsFullSpan = isFullSpanZoomRange(zoomRange);\n const zoomActiveNotFullSpan = zoomRange != null && !zoomIsFullSpan;\n\n let didResample = false;\n\n // Zoom changes (debounced): apply on flush.\n if (zoomResampleDue) {\n zoomResampleDue = false;\n cancelZoomResampleDebounce();\n\n if (!zoomRange || zoomIsFullSpan) {\n renderSeries = runtimeBaseSeries;\n // Recompute visible y-bounds from the baseline series\n recomputeCachedVisibleYBoundsIfNeeded();\n } else {\n recomputeRenderSeries();\n }\n didResample = true;\n } else if (didAppend && zoomActiveNotFullSpan) {\n // Appends during an active zoom window require resampling the visible range.\n // (Avoid doing this work when zoom is full-span or disabled.)\n zoomResampleDue = false;\n cancelZoomResampleDebounce();\n recomputeRenderSeries();\n didResample = true;\n }\n\n if ((didAppend || didResample) && requestRenderAfter) {\n requestRender();\n }\n };\n\n const scheduleFlush = (options?: { readonly immediate?: boolean }): void => {\n if (disposed) return;\n if (flushScheduled && !options?.immediate) return;\n\n // Cancel any previous schedule so we coalesce to exactly one pending flush.\n if (flushRafId !== null) {\n cancelAnimationFrame(flushRafId);\n flushRafId = null;\n }\n if (flushTimeoutId !== null) {\n clearTimeout(flushTimeoutId);\n flushTimeoutId = null;\n }\n\n flushScheduled = true;\n\n flushRafId = requestAnimationFrame(() => {\n flushRafId = null;\n if (disposed) {\n cancelScheduledFlush();\n return;\n }\n // rAF fired first: cancel the fallback timeout.\n if (flushTimeoutId !== null) {\n clearTimeout(flushTimeoutId);\n flushTimeoutId = null;\n }\n flushScheduled = false;\n executeFlush();\n });\n\n // Fallback: ensure we flush even if rAF is delayed (high-frequency streams > 60Hz).\n flushTimeoutId = (typeof self !== 'undefined' ? self : window).setTimeout(() => {\n if (disposed) {\n cancelScheduledFlush();\n return;\n }\n if (!flushScheduled) return;\n\n if (flushRafId !== null) {\n cancelAnimationFrame(flushRafId);\n flushRafId = null;\n }\n flushScheduled = false;\n flushTimeoutId = null;\n executeFlush();\n }, 16);\n };\n\n const scheduleZoomResample = (): void => {\n if (disposed) return;\n\n cancelZoomResampleDebounce();\n zoomResampleDue = false;\n\n zoomResampleDebounceTimer = (typeof self !== 'undefined' ? self : window).setTimeout(() => {\n zoomResampleDebounceTimer = null;\n if (disposed) return;\n zoomResampleDue = true;\n scheduleFlush();\n }, 100);\n };\n\n const getPlotSizeCssPx = (\n canvas: HTMLCanvasElement,\n gridArea: GridArea\n ): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n let canvasWidthCss: number;\n let canvasHeightCss: number;\n\n\n // HTMLCanvasElement: use getBoundingClientRect() for actual CSS dimensions\n const rect = canvas.getBoundingClientRect();\n if (!(rect.width > 0) || !(rect.height > 0)) return null;\n canvasWidthCss = rect.width;\n canvasHeightCss = rect.height;\n\n const plotWidthCss = canvasWidthCss - gridArea.left - gridArea.right;\n const plotHeightCss = canvasHeightCss - gridArea.top - gridArea.bottom;\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return null;\n\n return { plotWidthCss, plotHeightCss };\n };\n\n const computeInteractionScalesGridCssPx = (\n gridArea: GridArea,\n domains: { readonly xDomain: { readonly min: number; readonly max: number }; readonly yDomain: { readonly min: number; readonly max: number } }\n ):\n | {\n readonly xScale: LinearScale;\n readonly yScale: LinearScale;\n readonly plotWidthCss: number;\n readonly plotHeightCss: number;\n }\n | null => {\n const canvas = gpuContext.canvas;\n if (!canvas) return null;\n\n const plotSize = getPlotSizeCssPx(canvas, gridArea);\n if (!plotSize) return null;\n\n // IMPORTANT: grid-local CSS px ranges (0..plotWidth/Height), for interaction hit-testing.\n const xScale = createLinearScale().domain(domains.xDomain.min, domains.xDomain.max).range(0, plotSize.plotWidthCss);\n const yScale = createLinearScale().domain(domains.yDomain.min, domains.yDomain.max).range(plotSize.plotHeightCss, 0);\n\n const result = { xScale, yScale, plotWidthCss: plotSize.plotWidthCss, plotHeightCss: plotSize.plotHeightCss };\n\n return result;\n };\n\n const buildTooltipParams = (seriesIndex: number, dataIndex: number, point: DataPoint): TooltipParams => {\n const s = currentOptions.series[seriesIndex];\n const { x, y } = getPointXY(point);\n return {\n seriesName: s?.name ?? '',\n seriesIndex,\n dataIndex,\n value: [x, y],\n color: s?.color ?? '#888',\n };\n };\n\n const buildCandlestickTooltipParams = (\n seriesIndex: number,\n dataIndex: number,\n point: OHLCDataPoint\n ): TooltipParams => {\n const s = currentOptions.series[seriesIndex];\n if (isTupleOHLCDataPoint(point)) {\n return {\n seriesName: s?.name ?? '',\n seriesIndex,\n dataIndex,\n value: [point[0], point[1], point[2], point[3], point[4]] as const,\n color: s?.color ?? '#888',\n };\n } else {\n return {\n seriesName: s?.name ?? '',\n seriesIndex,\n dataIndex,\n value: [point.timestamp, point.open, point.close, point.low, point.high] as const,\n color: s?.color ?? '#888',\n };\n }\n };\n\n // Helper: Find pie slice at pointer position (extracted to avoid duplication)\n const findPieSliceAtPointer = (\n series: ResolvedChartGPUOptions['series'],\n gridX: number,\n gridY: number,\n plotWidthCss: number,\n plotHeightCss: number\n ): ReturnType<typeof findPieSlice> | null => {\n const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n if (!(maxRadiusCss > 0)) return null;\n\n // Iterate from last to first for correct z-ordering (last series drawn on top)\n for (let i = series.length - 1; i >= 0; i--) {\n const s = series[i];\n if (s.type !== 'pie') continue;\n // Skip invisible series (pie hit-testing should respect visibility)\n if (s.visible === false) continue;\n const pieSeries = s as ResolvedPieSeriesConfig;\n const center = resolvePieCenterPlotCss(pieSeries.center, plotWidthCss, plotHeightCss);\n const radii = resolvePieRadiiCss(pieSeries.radius, maxRadiusCss);\n const m = findPieSlice(gridX, gridY, { seriesIndex: i, series: pieSeries }, center, radii);\n if (m) return m;\n }\n return null;\n };\n\n // Helper: Find candlestick match at pointer position (hoisted to avoid closure allocation)\n const findCandlestickAtPointer = (\n series: ResolvedChartGPUOptions['series'],\n gridX: number,\n gridY: number,\n interactionScales: NonNullable<ReturnType<typeof computeInteractionScalesGridCssPx>>\n ): { params: TooltipParams; match: { point: OHLCDataPoint }; seriesIndex: number } | null => {\n // Iterate from last to first for correct z-ordering (last series drawn on top)\n for (let i = series.length - 1; i >= 0; i--) {\n const s = series[i];\n if (s.type !== 'candlestick') continue;\n // Skip invisible series (candlestick hit-testing should respect visibility)\n if (s.visible === false) continue;\n\n const cs = s as ResolvedCandlestickSeriesConfig;\n const barWidthClip = computeCandlestickBodyWidthRange(\n cs,\n cs.data,\n interactionScales.xScale,\n interactionScales.plotWidthCss\n );\n\n const m = findCandlestick(\n [cs],\n gridX,\n gridY,\n interactionScales.xScale,\n interactionScales.yScale,\n barWidthClip\n );\n if (!m) continue;\n\n const params = buildCandlestickTooltipParams(i, m.dataIndex, m.point);\n return { params, match: { point: m.point }, seriesIndex: i };\n }\n return null;\n };\n\n const onMouseMove = (payload: ChartGPUEventPayload): void => {\n pointerState = {\n source: 'mouse',\n x: payload.x,\n y: payload.y,\n gridX: payload.gridX,\n gridY: payload.gridY,\n isInGrid: payload.isInGrid,\n hasPointer: true,\n };\n\n // If we're over the plot and we have recent interaction scales, update interaction-x in domain units.\n // (Best-effort; render() refreshes scales and overlays.)\n if (payload.isInGrid && lastInteractionScales) {\n const xDomain = lastInteractionScales.xScale.invert(payload.gridX);\n setInteractionXInternal(Number.isFinite(xDomain) ? xDomain : null, 'mouse');\n } else if (!payload.isInGrid) {\n // Clear interaction-x when leaving the plot area (keeps synced charts from “sticking”).\n setInteractionXInternal(null, 'mouse');\n }\n\n crosshairRenderer.setVisible(payload.isInGrid);\n requestRender();\n };\n\n const onMouseLeave = (_payload: ChartGPUEventPayload): void => {\n // Only clear interaction overlays for real pointer interaction.\n // If we're being driven by a sync-x, leaving the canvas shouldn't hide the overlays.\n if (pointerState.source !== 'mouse') return;\n\n pointerState = { ...pointerState, isInGrid: false, hasPointer: false };\n crosshairRenderer.setVisible(false);\n hideTooltip();\n setInteractionXInternal(null, 'mouse');\n requestRender();\n };\n\n // Register event listeners only if event manager is available (HTMLCanvasElement).\n if (eventManager) {\n eventManager.on('mousemove', onMouseMove);\n eventManager.on('mouseleave', onMouseLeave);\n }\n\n // Optional internal “inside zoom” (wheel zoom + drag pan).\n let zoomState: ZoomState | null = null;\n let insideZoom: ReturnType<typeof createInsideZoom> | null = null;\n let unsubscribeZoom: (() => void) | null = null;\n let lastOptionsZoomRange: Readonly<{ start: number; end: number }> | null = null;\n const zoomRangeListeners = new Set<(range: Readonly<{ start: number; end: number }>) => void>();\n\n const emitZoomRange = (range: Readonly<{ start: number; end: number }>): void => {\n const snapshot = Array.from(zoomRangeListeners);\n for (const cb of snapshot) cb(range);\n };\n\n const getZoomOptionsConfig = (\n opts: ResolvedChartGPUOptions\n ): { readonly start: number; readonly end: number; readonly hasInside: boolean } | null => {\n // Zoom is enabled when *either* inside or slider exists. A single shared percent-space\n // window is used for both.\n const insideCfg = opts.dataZoom?.find((z) => z?.type === 'inside');\n const sliderCfg = opts.dataZoom?.find((z) => z?.type === 'slider');\n const cfg = insideCfg ?? sliderCfg;\n if (!cfg) return null;\n const start = Number.isFinite(cfg.start) ? cfg.start! : 0;\n const end = Number.isFinite(cfg.end) ? cfg.end! : 100;\n return { start, end, hasInside: !!insideCfg };\n };\n\n const clampPercent = (v: number): number => Math.min(100, Math.max(0, v));\n\n const getZoomSpanConstraintsFromOptions = (\n opts: ResolvedChartGPUOptions\n ): { readonly minSpan?: number; readonly maxSpan?: number } => {\n let minSpan: number | null = null;\n let maxSpan: number | null = null;\n\n const list = opts.dataZoom ?? [];\n for (const z of list) {\n if (!z) continue;\n if (z.type !== 'inside' && z.type !== 'slider') continue;\n\n if (Number.isFinite(z.minSpan as number)) {\n const v = clampPercent(z.minSpan as number);\n minSpan = minSpan == null ? v : Math.max(minSpan, v);\n }\n if (Number.isFinite(z.maxSpan as number)) {\n const v = clampPercent(z.maxSpan as number);\n maxSpan = maxSpan == null ? v : Math.min(maxSpan, v);\n }\n }\n\n return { minSpan: minSpan ?? undefined, maxSpan: maxSpan ?? undefined };\n };\n\n const computeDatasetAwareDefaultMinSpan = (): number | null => {\n // Dataset-aware defaults only apply to numeric/time x domains (category is discrete UI-driven).\n if (currentOptions.xAxis.type === 'category') return null;\n\n let maxPoints = 0;\n for (let i = 0; i < currentOptions.series.length; i++) {\n const s = currentOptions.series[i]!;\n if (s.type === 'pie') continue;\n if (s.type === 'candlestick') {\n const raw =\n (runtimeRawDataByIndex[i] as ReadonlyArray<OHLCDataPoint> | null) ??\n ((s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>);\n maxPoints = Math.max(maxPoints, raw.length);\n continue;\n }\n\n const raw =\n (runtimeRawDataByIndex[i] as DataPoint[] | null) ??\n cartesianDataToDataPointArray((s.rawData ?? s.data) as CartesianSeriesData);\n maxPoints = Math.max(maxPoints, raw.length);\n }\n\n if (maxPoints < 2) return null;\n const v = 100 / (maxPoints - 1);\n return Number.isFinite(v) ? clampPercent(v) : null;\n };\n\n const computeEffectiveZoomSpanConstraints = (): { readonly minSpan: number; readonly maxSpan: number } => {\n const fromOptions = getZoomSpanConstraintsFromOptions(currentOptions);\n const datasetMin = computeDatasetAwareDefaultMinSpan();\n\n // Preserve legacy behavior when no constraints (and no dataset signal) are available.\n // The coordinator will typically override this with datasetMin when the data supports it.\n const minSpan = Number.isFinite(fromOptions.minSpan as number)\n ? clampPercent(fromOptions.minSpan as number)\n : datasetMin ?? 0.5;\n const maxSpan = Number.isFinite(fromOptions.maxSpan as number)\n ? clampPercent(fromOptions.maxSpan as number)\n : 100;\n\n return { minSpan, maxSpan };\n };\n\n const updateZoom = (): void => {\n const cfg = getZoomOptionsConfig(currentOptions);\n\n if (!cfg) {\n insideZoom?.dispose();\n insideZoom = null;\n unsubscribeZoom?.();\n unsubscribeZoom = null;\n zoomState = null;\n lastOptionsZoomRange = null;\n return;\n }\n\n if (!zoomState) {\n const constraints = computeEffectiveZoomSpanConstraints();\n zoomState = createZoomState(cfg.start, cfg.end, constraints);\n lastOptionsZoomRange = { start: cfg.start, end: cfg.end };\n unsubscribeZoom = zoomState.onChange((range) => {\n // Coalesce slicing (and visible-bounds recompute) to at most once per rendered frame.\n sliceRenderSeriesDue = true;\n // Immediate render for UI feedback (axes/crosshair/slider).\n requestRender();\n // Debounce resampling; the unified flush will do the work.\n scheduleZoomResample();\n // Ensure listeners get a stable readonly object.\n emitZoomRange({ start: range.start, end: range.end });\n });\n } else {\n const constraints = computeEffectiveZoomSpanConstraints();\n const withConstraints = zoomState as unknown as {\n setSpanConstraints?: (minSpan: number, maxSpan: number) => void;\n };\n withConstraints.setSpanConstraints?.(constraints.minSpan, constraints.maxSpan);\n\n if (\n lastOptionsZoomRange == null ||\n lastOptionsZoomRange.start !== cfg.start ||\n lastOptionsZoomRange.end !== cfg.end\n ) {\n // Only apply option-provided start/end when:\n // - zoom is first created, or\n // - start/end actually changed in options\n zoomState.setRange(cfg.start, cfg.end);\n lastOptionsZoomRange = { start: cfg.start, end: cfg.end };\n }\n }\n\n // Only enable inside zoom handler when `{ type: 'inside' }` exists.\n // Requires event manager (HTMLCanvasElement only).\n if (cfg.hasInside && eventManager) {\n if (!insideZoom) {\n insideZoom = createInsideZoom(eventManager, zoomState);\n insideZoom.enable();\n }\n } else {\n insideZoom?.dispose();\n insideZoom = null;\n }\n };\n\n const initRuntimeSeriesFromOptions = (): void => {\n const count = currentOptions.series.length;\n runtimeRawDataByIndex = new Array(count).fill(null);\n runtimeRawBoundsByIndex = new Array(count).fill(null);\n pendingAppendByIndex.clear();\n\n for (let i = 0; i < count; i++) {\n const s = currentOptions.series[i]!;\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n // Store candlestick raw OHLC data (not for streaming append, but for zoom-aware resampling).\n const rawOHLC = (s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>;\n const owned = rawOHLC.length === 0 ? [] : rawOHLC.slice();\n runtimeRawDataByIndex[i] = owned;\n runtimeRawBoundsByIndex[i] = s.rawBounds ?? null;\n continue;\n }\n\n const raw = (s.rawData ?? s.data) as CartesianSeriesData;\n // Coordinator-owned: convert to mutable DataPoint[] array (streaming appends mutate this).\n const owned = cartesianDataToDataPointArray(raw);\n runtimeRawDataByIndex[i] = owned;\n runtimeRawBoundsByIndex[i] = s.rawBounds ?? computeRawBoundsFromCartesianData(raw);\n }\n };\n\n const recomputeRuntimeBaseSeries = (): void => {\n const next: ResolvedChartGPUOptions['series'][number][] = new Array(currentOptions.series.length);\n for (let i = 0; i < currentOptions.series.length; i++) {\n const s = currentOptions.series[i]!;\n if (s.type === 'pie') {\n next[i] = s;\n continue;\n }\n\n if (s.type === 'candlestick') {\n const rawOHLC =\n (runtimeRawDataByIndex[i] as ReadonlyArray<OHLCDataPoint> | null) ??\n ((s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>);\n const bounds = runtimeRawBoundsByIndex[i] ?? s.rawBounds ?? undefined;\n const baselineSampled = s.sampling === 'ohlc' && rawOHLC.length > s.samplingThreshold\n ? ohlcSample(rawOHLC, s.samplingThreshold)\n : rawOHLC;\n next[i] = { ...s, rawData: rawOHLC, rawBounds: bounds, data: baselineSampled };\n continue;\n }\n\n const raw =\n (runtimeRawDataByIndex[i] as DataPoint[] | null) ?? \n cartesianDataToDataPointArray((s.rawData ?? s.data) as CartesianSeriesData);\n const bounds = runtimeRawBoundsByIndex[i] ?? s.rawBounds ?? undefined;\n const baselineSampled = sampleSeriesDataPoints(raw, s.sampling, s.samplingThreshold);\n next[i] = { ...s, rawData: raw, rawBounds: bounds, data: baselineSampled };\n }\n runtimeBaseSeries = next;\n };\n\n function sliceRenderSeriesToVisibleRange(): void {\n const zoomRange = zoomState?.getRange() ?? null;\n const baseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const visibleX = computeVisibleXDomain(baseXDomain, zoomRange);\n\n // Fast path: no zoom or full span - use baseline directly\n const isFullSpan =\n zoomRange == null ||\n (Number.isFinite(zoomRange.start) &&\n Number.isFinite(zoomRange.end) &&\n zoomRange.start <= 0 &&\n zoomRange.end >= 100);\n \n if (isFullSpan) {\n renderSeries = runtimeBaseSeries;\n // Recompute visible y-bounds from the full baseline series\n recomputeCachedVisibleYBoundsIfNeeded();\n return;\n }\n\n const next: ResolvedChartGPUOptions['series'][number][] = new Array(runtimeBaseSeries.length);\n\n for (let i = 0; i < runtimeBaseSeries.length; i++) {\n const baseline = runtimeBaseSeries[i]!;\n \n // Pie charts don't need slicing\n if (baseline.type === 'pie') {\n next[i] = baseline;\n continue;\n }\n\n const cache = lastSampledData[i];\n \n // Strategy 1: Use cache if it covers visible range\n if (cache && \n visibleX.min >= cache.cachedRange.min && \n visibleX.max <= cache.cachedRange.max) {\n \n if (baseline.type === 'candlestick') {\n next[i] = {\n ...baseline,\n data: sliceVisibleRangeByOHLC(cache.data as ReadonlyArray<OHLCDataPoint>, visibleX.min, visibleX.max)\n };\n } else {\n next[i] = {\n ...baseline,\n data: sliceVisibleRangeByX(cache.data as CartesianSeriesData, visibleX.min, visibleX.max)\n };\n }\n continue;\n }\n \n // Strategy 2: Fallback to baseline sampled data\n if (baseline.type === 'candlestick') {\n next[i] = {\n ...baseline,\n data: sliceVisibleRangeByOHLC(baseline.data as ReadonlyArray<OHLCDataPoint>, visibleX.min, visibleX.max)\n };\n } else {\n next[i] = {\n ...baseline,\n data: sliceVisibleRangeByX(baseline.data as CartesianSeriesData, visibleX.min, visibleX.max)\n };\n }\n }\n\n renderSeries = next;\n // Recompute visible y-bounds from the sliced renderSeries\n recomputeCachedVisibleYBoundsIfNeeded();\n }\n\n function recomputeRenderSeries(): void {\n const zoomRange = zoomState?.getRange() ?? null;\n const baseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const visibleX = computeVisibleXDomain(baseXDomain, zoomRange);\n\n // Add buffer zone (±10% beyond visible range) for caching\n const bufferFactor = 0.1;\n const visibleSpan = visibleX.max - visibleX.min;\n const bufferSize = visibleSpan * bufferFactor;\n const bufferedMin = visibleX.min - bufferSize;\n const bufferedMax = visibleX.max + bufferSize;\n\n // Sampling scale behavior:\n // - Use `samplingThreshold` as baseline at full span.\n // - As zoom span shrinks, raise the threshold so fewer points are dropped (more detail).\n // - Clamp to avoid huge allocations / pathological thresholds.\n const MIN_TARGET_POINTS = 2;\n const MAX_TARGET_POINTS_ABS = 200_000;\n const MAX_TARGET_MULTIPLIER = 32;\n const spanFracSafe = Math.max(1e-3, Math.min(1, visibleX.spanFraction));\n\n const next: ResolvedChartGPUOptions['series'][number][] = new Array(runtimeBaseSeries.length);\n\n for (let i = 0; i < runtimeBaseSeries.length; i++) {\n const s = runtimeBaseSeries[i]!;\n\n if (s.type === 'pie') {\n next[i] = s;\n continue;\n }\n\n // Fast path: no zoom window / full span. Use baseline resolved `data` (already sampled by resolver).\n const isFullSpan =\n zoomRange == null ||\n (Number.isFinite(zoomRange.start) &&\n Number.isFinite(zoomRange.end) &&\n zoomRange.start <= 0 &&\n zoomRange.end >= 100);\n if (isFullSpan) {\n next[i] = s;\n continue;\n }\n\n // Candlestick series: OHLC-specific slicing + sampling.\n if (s.type === 'candlestick') {\n const rawOHLC =\n (runtimeRawDataByIndex[i] as ReadonlyArray<OHLCDataPoint> | null) ??\n ((s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>);\n // Slice to buffered range for sampling\n const bufferedOHLC = sliceVisibleRangeByOHLC(rawOHLC, bufferedMin, bufferedMax);\n\n const sampling = s.sampling;\n const baseThreshold = s.samplingThreshold;\n\n const baseT = Number.isFinite(baseThreshold) ? Math.max(1, baseThreshold | 0) : 1;\n const maxTarget = Math.min(MAX_TARGET_POINTS_ABS, Math.max(MIN_TARGET_POINTS, baseT * MAX_TARGET_MULTIPLIER));\n const target = clampInt(Math.round(baseT / spanFracSafe), MIN_TARGET_POINTS, maxTarget);\n\n const sampled = sampling === 'ohlc' && bufferedOHLC.length > target\n ? ohlcSample(bufferedOHLC, target)\n : bufferedOHLC;\n\n // Store sampled data in cache with buffered range\n lastSampledData[i] = {\n data: sampled as unknown as ReadonlyArray<DataPoint>,\n cachedRange: { min: bufferedMin, max: bufferedMax },\n timestamp: Date.now()\n };\n\n // Slice to actual visible range for renderSeries\n const visibleSampled = sliceVisibleRangeByOHLC(sampled, visibleX.min, visibleX.max);\n next[i] = { ...s, data: visibleSampled };\n continue;\n }\n\n // Cartesian series (line, area, bar, scatter).\n const rawData =\n (runtimeRawDataByIndex[i] as DataPoint[] | null) ?? \n cartesianDataToDataPointArray((s.rawData ?? s.data) as CartesianSeriesData);\n // Slice to buffered range for sampling\n const bufferedRaw = sliceVisibleRangeByX(rawData, bufferedMin, bufferedMax);\n\n const sampling = s.sampling;\n const baseThreshold = s.samplingThreshold;\n\n const baseT = Number.isFinite(baseThreshold) ? Math.max(1, baseThreshold | 0) : 1;\n const maxTarget = Math.min(MAX_TARGET_POINTS_ABS, Math.max(MIN_TARGET_POINTS, baseT * MAX_TARGET_MULTIPLIER));\n const target = clampInt(Math.round(baseT / spanFracSafe), MIN_TARGET_POINTS, maxTarget);\n\n const sampled = sampleSeriesDataPoints(bufferedRaw as CartesianSeriesData, sampling, target);\n\n // Store sampled data in cache with buffered range\n lastSampledData[i] = {\n data: sampled as unknown as ReadonlyArray<DataPoint>,\n cachedRange: { min: bufferedMin, max: bufferedMax },\n timestamp: Date.now()\n };\n\n // Slice to actual visible range for renderSeries\n const visibleSampled = sliceVisibleRangeByX(sampled as CartesianSeriesData, visibleX.min, visibleX.max);\n next[i] = { ...s, data: visibleSampled };\n }\n\n renderSeries = next;\n // Recompute visible y-bounds from the updated renderSeries\n recomputeCachedVisibleYBoundsIfNeeded();\n }\n\n initRuntimeSeriesFromOptions();\n recomputeRuntimeBaseSeries();\n updateZoom();\n recomputeRenderSeries();\n lastSampledData = new Array(currentOptions.series.length).fill(null);\n\n const areaRenderers: Array<ReturnType<typeof createAreaRenderer>> = [];\n const lineRenderers: Array<ReturnType<typeof createLineRenderer>> = [];\n const scatterRenderers: Array<ReturnType<typeof createScatterRenderer>> = [];\n const scatterDensityRenderers: Array<ReturnType<typeof createScatterDensityRenderer>> = [];\n const pieRenderers: Array<ReturnType<typeof createPieRenderer>> = [];\n const candlestickRenderers: Array<ReturnType<typeof createCandlestickRenderer>> = [];\n const barRenderer = createBarRenderer(device, { targetFormat });\n\n const ensureAreaRendererCount = (count: number): void => {\n while (areaRenderers.length > count) {\n const r = areaRenderers.pop();\n r?.dispose();\n }\n while (areaRenderers.length < count) {\n areaRenderers.push(createAreaRenderer(device, { targetFormat }));\n }\n };\n\n const ensureLineRendererCount = (count: number): void => {\n while (lineRenderers.length > count) {\n const r = lineRenderers.pop();\n r?.dispose();\n }\n while (lineRenderers.length < count) {\n lineRenderers.push(createLineRenderer(device, { targetFormat }));\n }\n };\n\n const ensureScatterRendererCount = (count: number): void => {\n while (scatterRenderers.length > count) {\n const r = scatterRenderers.pop();\n r?.dispose();\n }\n while (scatterRenderers.length < count) {\n scatterRenderers.push(createScatterRenderer(device, { targetFormat }));\n }\n };\n\n const ensureScatterDensityRendererCount = (count: number): void => {\n while (scatterDensityRenderers.length > count) {\n const r = scatterDensityRenderers.pop();\n r?.dispose();\n }\n while (scatterDensityRenderers.length < count) {\n scatterDensityRenderers.push(createScatterDensityRenderer(device, { targetFormat }));\n }\n };\n\n const ensurePieRendererCount = (count: number): void => {\n while (pieRenderers.length > count) {\n const r = pieRenderers.pop();\n r?.dispose();\n }\n while (pieRenderers.length < count) {\n pieRenderers.push(createPieRenderer(device, { targetFormat }));\n }\n };\n\n const ensureCandlestickRendererCount = (count: number): void => {\n while (candlestickRenderers.length > count) {\n const r = candlestickRenderers.pop();\n r?.dispose();\n }\n while (candlestickRenderers.length < count) {\n candlestickRenderers.push(createCandlestickRenderer(device, { targetFormat }));\n }\n };\n\n ensureAreaRendererCount(currentOptions.series.length);\n ensureLineRendererCount(currentOptions.series.length);\n ensureScatterRendererCount(currentOptions.series.length);\n ensureScatterDensityRendererCount(currentOptions.series.length);\n ensurePieRendererCount(currentOptions.series.length);\n ensureCandlestickRendererCount(currentOptions.series.length);\n\n const assertNotDisposed = (): void => {\n if (disposed) throw new Error('RenderCoordinator is disposed.');\n };\n\n const cancelUpdateTransition = (): void => {\n if (updateAnimId) {\n try {\n updateAnimController.cancel(updateAnimId);\n } catch {\n // best-effort\n }\n }\n updateAnimId = null;\n updateProgress01 = 1;\n updateTransition = null;\n resetUpdateInterpolationCaches();\n };\n\n const isDomainEqual = (a: { readonly min: number; readonly max: number }, b: { readonly min: number; readonly max: number }): boolean =>\n a.min === b.min && a.max === b.max;\n\n const didSeriesDataLikelyChange = (\n prev: ResolvedChartGPUOptions['series'],\n next: ResolvedChartGPUOptions['series']\n ): boolean => {\n if (prev.length !== next.length) return true;\n for (let i = 0; i < prev.length; i++) {\n const a = prev[i]!;\n const b = next[i]!;\n if (a.type !== b.type) return true;\n\n // Prefer cheap reference checks (good enough for eligibility gating).\n if (a.type === 'pie') {\n const aPie = a as ResolvedPieSeriesConfig;\n const bPie = b as ResolvedPieSeriesConfig;\n if (aPie.data !== bPie.data) return true;\n if (aPie.data.length !== bPie.data.length) return true;\n } else {\n const aAny = a as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n const bAny = b as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n const aRaw = (aAny.rawData ?? aAny.data) as ReadonlyArray<DataPoint>;\n const bRaw = (bAny.rawData ?? bAny.data) as ReadonlyArray<DataPoint>;\n if (aRaw !== bRaw) return true;\n if (aRaw.length !== bRaw.length) return true;\n }\n }\n return false;\n };\n\n /**\n * Checks if only series visibility changed (no data, type, or structural changes).\n * Used to avoid starting update animations during simple visibility toggles.\n */\n const didOnlyVisibilityChange = (\n prev: ResolvedChartGPUOptions['series'],\n next: ResolvedChartGPUOptions['series']\n ): boolean => {\n if (prev.length !== next.length) return false;\n\n let hasVisibilityChange = false;\n for (let i = 0; i < prev.length; i++) {\n const a = prev[i]!;\n const b = next[i]!;\n\n // Check if anything other than visibility changed\n if (a.type !== b.type) return false;\n\n if (a.type === 'pie') {\n const aPie = a as ResolvedPieSeriesConfig;\n const bPie = b as ResolvedPieSeriesConfig;\n\n // For pie charts, check if data arrays have the same length\n if (aPie.data.length !== bPie.data.length) return false;\n\n // Check each slice to ensure only visibility changed\n for (let j = 0; j < aPie.data.length; j++) {\n const sliceA = aPie.data[j];\n const sliceB = bPie.data[j];\n\n // If both slices are undefined/null, continue\n if (!sliceA && !sliceB) continue;\n if (!sliceA || !sliceB) return false;\n\n // Check if anything other than visibility changed in this slice\n if (sliceA.name !== sliceB.name) return false;\n if (sliceA.value !== sliceB.value) return false;\n if (sliceA.color !== sliceB.color) return false;\n\n // Check if visibility changed\n const aSliceVisible = sliceA.visible !== false;\n const bSliceVisible = sliceB.visible !== false;\n if (aSliceVisible !== bSliceVisible) {\n hasVisibilityChange = true;\n }\n }\n } else {\n const aAny = a as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n const bAny = b as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n const aRaw = (aAny.rawData ?? aAny.data) as ReadonlyArray<DataPoint>;\n const bRaw = (bAny.rawData ?? bAny.data) as ReadonlyArray<DataPoint>;\n if (aRaw !== bRaw) return false;\n if (aRaw.length !== bRaw.length) return false;\n }\n\n // Check if visibility actually changed for this series\n const aVisible = a.visible !== false;\n const bVisible = b.visible !== false;\n if (aVisible !== bVisible) {\n hasVisibilityChange = true;\n }\n }\n\n return hasVisibilityChange;\n };\n\n const setOptions: RenderCoordinator['setOptions'] = (resolvedOptions) => {\n assertNotDisposed();\n\n // Capture \"from\" snapshot BEFORE overwriting coordinator state.\n const fromZoomRange = zoomState?.getRange() ?? null;\n const fromSnapshot: UpdateTransitionSnapshot = (() => {\n // Requirement (mid-flight updates): if a transition is running, rebase from the current blended state.\n if (updateTransition && updateAnimId) {\n try {\n updateAnimController.update(performance.now());\n } catch {\n // best-effort\n }\n return computeUpdateSnapshotAtProgress(updateTransition, updateProgress01, fromZoomRange);\n }\n\n const fromXBase = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const fromXVisible = computeVisibleXDomain(fromXBase, fromZoomRange);\n const fromYBase = computeBaseYDomain(currentOptions, runtimeRawBoundsByIndex, cachedVisibleYBounds);\n return {\n xBaseDomain: fromXBase,\n xVisibleDomain: { min: fromXVisible.min, max: fromXVisible.max },\n yBaseDomain: fromYBase,\n series: renderSeries,\n };\n })();\n\n // Cancel any prior update transition AFTER capturing the rebased \"from\" snapshot.\n cancelUpdateTransition();\n const likelyDataChanged = didSeriesDataLikelyChange(currentOptions.series, resolvedOptions.series);\n const onlyVisibilityChanged = didOnlyVisibilityChange(currentOptions.series, resolvedOptions.series);\n\n currentOptions = resolvedOptions;\n runtimeBaseSeries = resolvedOptions.series;\n renderSeries = resolvedOptions.series;\n // Recompute visible y-bounds from the new series\n cachedVisibleYBounds = null;\n gpuSeriesKindByIndex = new Array(resolvedOptions.series.length).fill('unknown');\n lastSampledData = new Array(resolvedOptions.series.length).fill(null);\n legend?.update(resolvedOptions.series, resolvedOptions.theme);\n cancelZoomResampleDebounce();\n zoomResampleDue = false;\n cancelScheduledFlush();\n initRuntimeSeriesFromOptions();\n recomputeRuntimeBaseSeries();\n updateZoom();\n recomputeRenderSeries();\n\n // Tooltip enablement may change at runtime.\n if (overlayContainer) {\n const shouldHaveTooltip = currentOptions.tooltip?.show !== false;\n if (shouldHaveTooltip && !tooltip) {\n tooltip = createTooltip(overlayContainer);\n lastTooltipContent = null;\n lastTooltipX = null;\n lastTooltipY = null;\n }\n if (!shouldHaveTooltip && tooltip) {\n hideTooltip();\n }\n } else {\n hideTooltip();\n }\n\n const nextCount = resolvedOptions.series.length;\n ensureAreaRendererCount(nextCount);\n ensureLineRendererCount(nextCount);\n ensureScatterRendererCount(nextCount);\n ensureScatterDensityRendererCount(nextCount);\n ensurePieRendererCount(nextCount);\n ensureCandlestickRendererCount(nextCount);\n\n // When the series count shrinks, explicitly destroy per-index GPU buffers for removed series.\n // This avoids recreating the entire DataStore and keeps existing buffers for retained indices.\n if (nextCount < lastSeriesCount) {\n for (let i = nextCount; i < lastSeriesCount; i++) {\n dataStore.removeSeries(i);\n }\n }\n lastSeriesCount = nextCount;\n\n // If animation is explicitly disabled mid-flight, stop the intro without scheduling more frames.\n if (currentOptions.animation === false && introPhase === 'running') {\n introAnimController.cancelAll();\n introAnimId = null;\n introPhase = 'done';\n introProgress01 = 1;\n }\n\n // If animation is explicitly disabled, ensure any running update transition is stopped.\n if (currentOptions.animation === false) {\n cancelUpdateTransition();\n // Request a render to reflect the option changes immediately\n requestRender();\n return;\n }\n\n // Capture \"to\" snapshot after recompute.\n const toZoomRange = zoomState?.getRange() ?? null;\n const toXBase = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const toXVisible = computeVisibleXDomain(toXBase, toZoomRange);\n const toYBase = computeBaseYDomain(currentOptions, runtimeRawBoundsByIndex, cachedVisibleYBounds);\n const toSeriesForTransition = renderSeries;\n\n const domainChanged = !isDomainEqual(fromSnapshot.xBaseDomain, toXBase) || !isDomainEqual(fromSnapshot.yBaseDomain, toYBase);\n\n // Skip update animations when only visibility changed.\n // This allows the intro animation system to handle visibility changes smoothly,\n // whether an intro animation is running or not.\n const shouldSkipUpdateAnimation = onlyVisibilityChanged;\n\n const shouldAnimateUpdate = hasRenderedOnce && (domainChanged || likelyDataChanged) && !shouldSkipUpdateAnimation;\n if (!shouldAnimateUpdate) {\n // When visibility changes after intro is complete, retrigger the startup animation for all chart types\n if (onlyVisibilityChanged && introPhase === 'done' && hasRenderedOnce) {\n // Reset intro animation state to retrigger on next render\n introAnimController.cancelAll();\n introAnimId = null;\n introPhase = 'pending';\n introProgress01 = 0;\n }\n\n // Request a render even when not animating (e.g., theme changes, option updates, visibility toggles during intro)\n requestRender();\n return;\n }\n\n const updateCfg = resolveUpdateAnimationConfig(currentOptions.animation);\n if (!updateCfg) return;\n\n updateTransition = {\n from: {\n xBaseDomain: fromSnapshot.xBaseDomain,\n xVisibleDomain: fromSnapshot.xVisibleDomain,\n yBaseDomain: fromSnapshot.yBaseDomain,\n series: fromSnapshot.series,\n },\n to: {\n xBaseDomain: toXBase,\n xVisibleDomain: { min: toXVisible.min, max: toXVisible.max },\n yBaseDomain: toYBase,\n series: toSeriesForTransition,\n },\n };\n resetUpdateInterpolationCaches();\n\n const totalMs = updateCfg.delayMs + updateCfg.durationMs;\n const easingWithDelay: EasingFunction = (t01) => {\n const t = clamp01(t01);\n if (!(totalMs > 0)) return 1;\n\n const elapsedMs = t * totalMs;\n if (elapsedMs <= updateCfg.delayMs) return 0;\n\n if (!(updateCfg.durationMs > 0)) return 1;\n const innerT = (elapsedMs - updateCfg.delayMs) / updateCfg.durationMs;\n return updateCfg.easing(innerT);\n };\n\n updateProgress01 = 0;\n const id = updateAnimController.animate(\n 0,\n 1,\n totalMs,\n easingWithDelay,\n (value) => {\n if (disposed || updateAnimId !== id) return;\n updateProgress01 = clamp01(value);\n // Render-on-demand: request frames only while the update transition is active.\n if (updateProgress01 < 1) requestRender();\n },\n () => {\n if (disposed || updateAnimId !== id) return;\n updateProgress01 = 1;\n updateTransition = null;\n updateAnimId = null;\n resetUpdateInterpolationCaches();\n }\n );\n updateAnimId = id;\n\n // Request initial render to kick off the animation.\n // Without this, the animation won't start until something else triggers a render\n // (e.g., pointer movement, which may not happen if the user is interacting with\n // UI overlays like the legend).\n requestRender();\n };\n\n const appendData: RenderCoordinator['appendData'] = (seriesIndex, newPoints) => {\n assertNotDisposed();\n if (!Number.isFinite(seriesIndex)) return;\n if (seriesIndex < 0 || seriesIndex >= currentOptions.series.length) return;\n if (!newPoints || newPoints.length === 0) return;\n\n const s = currentOptions.series[seriesIndex]!;\n if (s.type === 'pie') {\n // Pie series are non-cartesian and currently not supported by streaming append.\n if (!warnedPieAppendSeries.has(seriesIndex)) {\n warnedPieAppendSeries.add(seriesIndex);\n console.warn(\n `RenderCoordinator.appendData(${seriesIndex}, ...): pie series are not supported by streaming append.`\n );\n }\n return;\n }\n\n const existing = pendingAppendByIndex.get(seriesIndex);\n if (existing) {\n existing.push(...(newPoints as Array<DataPoint | OHLCDataPoint>));\n } else {\n // Copy into a mutable staging array so repeated appends coalesce without extra allocations.\n pendingAppendByIndex.set(seriesIndex, Array.from(newPoints as Array<DataPoint | OHLCDataPoint>));\n }\n\n // Coalesce appends + any required resampling + GPU streaming updates into a single flush.\n scheduleFlush();\n };\n\n const render: RenderCoordinator['render'] = () => {\n assertNotDisposed();\n if (!gpuContext.canvasContext || !gpuContext.canvas) return;\n\n // Safety: if a render is triggered for other reasons (e.g. pointer movement) while appends\n // are queued, flush them now so this frame draws up-to-date data. This avoids doing any work\n // when there are no appends.\n if (pendingAppendByIndex.size > 0 || zoomResampleDue) {\n cancelScheduledFlush();\n executeFlush({ requestRenderAfter: false });\n }\n\n if (sliceRenderSeriesDue) {\n sliceRenderSeriesDue = false;\n sliceRenderSeriesToVisibleRange();\n }\n\n const hasCartesianSeries = currentOptions.series.some((s) => s.type !== 'pie');\n const seriesForIntro = renderSeries;\n\n // Story 5.16: start/update intro animation once we have drawable series marks.\n if (introPhase !== 'done') {\n const introCfg = resolveIntroAnimationConfig(currentOptions.animation);\n\n const hasDrawableSeriesMarks = (() => {\n for (let i = 0; i < seriesForIntro.length; i++) {\n const s = seriesForIntro[i]!;\n switch (s.type) {\n case 'pie': {\n // Pie renderer only emits slices with value > 0.\n if (s.data.some((it) => typeof it?.value === 'number' && Number.isFinite(it.value) && it.value > 0)) {\n return true;\n }\n break;\n }\n case 'line':\n case 'area':\n case 'bar':\n case 'scatter':\n case 'candlestick': {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const dataLength =\n Array.isArray(s.data) || ArrayBuffer.isView(s.data)\n ? (s.data as ArrayLike<unknown>).length\n : (s.data as { x: ArrayLike<unknown> }).x.length;\n if (dataLength > 0) return true;\n break;\n }\n default:\n assertUnreachable(s);\n }\n }\n return false;\n })();\n\n if (introPhase === 'pending' && introCfg && hasDrawableSeriesMarks) {\n const totalMs = introCfg.delayMs + introCfg.durationMs;\n const easingWithDelay: EasingFunction = (t01) => {\n const t = clamp01(t01);\n if (!(totalMs > 0)) return 1;\n\n const elapsedMs = t * totalMs;\n if (elapsedMs <= introCfg.delayMs) return 0;\n\n if (!(introCfg.durationMs > 0)) return 1;\n const innerT = (elapsedMs - introCfg.delayMs) / introCfg.durationMs;\n return introCfg.easing(innerT);\n };\n\n introProgress01 = 0;\n introPhase = 'running';\n introAnimId = introAnimController.animate(\n 0,\n 1,\n totalMs,\n easingWithDelay,\n (value) => {\n if (disposed || introPhase !== 'running') return;\n introProgress01 = clamp01(value);\n // Render-on-demand: request frames only while the intro is active.\n if (introProgress01 < 1) requestRender();\n },\n () => {\n if (disposed) return;\n introPhase = 'done';\n introProgress01 = 1;\n introAnimId = null;\n }\n );\n }\n\n // Progress animations based on wall-clock time. This is cheap when no animations are active.\n introAnimController.update(performance.now());\n }\n\n // Story 5.17: progress update animation based on wall-clock time.\n // (Interpolation is applied below; this tick just advances progress.)\n if (updateTransition !== null && updateAnimId) {\n updateAnimController.update(performance.now());\n }\n\n const gridArea = computeGridArea(gpuContext, currentOptions);\n eventManager?.updateGridArea(gridArea);\n const zoomRange = zoomState?.getRange() ?? null;\n\n const updateP = updateTransition ? clamp01(updateProgress01) : 1;\n const baseXDomain = updateTransition\n ? lerpDomain(updateTransition.from.xBaseDomain, updateTransition.to.xBaseDomain, updateP)\n : computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n const yBaseDomain = updateTransition\n ? lerpDomain(updateTransition.from.yBaseDomain, updateTransition.to.yBaseDomain, updateP)\n : computeBaseYDomain(currentOptions, runtimeRawBoundsByIndex, cachedVisibleYBounds);\n const visibleXDomain = computeVisibleXDomain(baseXDomain, zoomRange);\n\n const plotClipRect = computePlotClipRect(gridArea);\n const plotScissor = computePlotScissorDevicePx(gridArea);\n\n const xScale = createLinearScale()\n .domain(visibleXDomain.min, visibleXDomain.max)\n .range(plotClipRect.left, plotClipRect.right);\n const yScale = createLinearScale().domain(yBaseDomain.min, yBaseDomain.max).range(plotClipRect.bottom, plotClipRect.top);\n\n // PERFORMANCE: Cache canvas CSS dimensions (used for both GPU overlays and label processing)\n // Annotations (GPU overlays) are specified in data-space and converted to CANVAS-LOCAL CSS pixels.\n const canvas = gpuContext.canvas;\n // IMPORTANT: For GPU overlay annotations only, derive CSS size from device pixels to avoid\n // DOM `clientWidth/clientHeight` mismatch with the WebGPU render target size.\n const canvasCssForAnnotations = getCanvasCssSizeFromDevicePixels(canvas);\n const canvasCssWidthForAnnotations = canvasCssForAnnotations.width;\n const canvasCssHeightForAnnotations = canvasCssForAnnotations.height;\n\n const plotLeftCss = canvasCssWidthForAnnotations > 0 ? clipXToCanvasCssPx(plotClipRect.left, canvasCssWidthForAnnotations) : 0;\n const plotRightCss = canvasCssWidthForAnnotations > 0 ? clipXToCanvasCssPx(plotClipRect.right, canvasCssWidthForAnnotations) : 0;\n const plotTopCss = canvasCssHeightForAnnotations > 0 ? clipYToCanvasCssPx(plotClipRect.top, canvasCssHeightForAnnotations) : 0;\n const plotBottomCss = canvasCssHeightForAnnotations > 0 ? clipYToCanvasCssPx(plotClipRect.bottom, canvasCssHeightForAnnotations) : 0;\n const plotWidthCss = Math.max(0, plotRightCss - plotLeftCss);\n const plotHeightCss = Math.max(0, plotBottomCss - plotTopCss);\n\n // Process annotations (convert to GPU instances for rendering)\n const annotations: ReadonlyArray<AnnotationConfig> = hasCartesianSeries ? (currentOptions.annotations ?? []) : [];\n const annotationResult = processAnnotations({\n annotations,\n xScale,\n yScale,\n plotBounds: {\n leftCss: plotLeftCss,\n rightCss: plotRightCss,\n topCss: plotTopCss,\n bottomCss: plotBottomCss,\n widthCss: plotWidthCss,\n heightCss: plotHeightCss,\n },\n canvasCssWidth: canvasCssWidthForAnnotations,\n canvasCssHeight: canvasCssHeightForAnnotations,\n theme: currentOptions.theme,\n });\n\n // Extract annotation instances for GPU rendering\n const combinedReferenceLines: ReadonlyArray<ReferenceLineInstance> =\n annotationResult.linesBelow.length + annotationResult.linesAbove.length > 0\n ? [...annotationResult.linesBelow, ...annotationResult.linesAbove]\n : [];\n const combinedMarkers: ReadonlyArray<AnnotationMarkerInstance> =\n annotationResult.markersBelow.length + annotationResult.markersAbove.length > 0\n ? [...annotationResult.markersBelow, ...annotationResult.markersAbove]\n : [];\n const referenceLineBelowCount = annotationResult.linesBelow.length;\n const referenceLineAboveCount = annotationResult.linesAbove.length;\n const markerBelowCount = annotationResult.markersBelow.length;\n const markerAboveCount = annotationResult.markersAbove.length;\n\n // Story 6: compute an x tick count that prevents label overlap (time axis only).\n // IMPORTANT: compute in CSS px, since labels are DOM elements in CSS px.\n // Note: This requires HTMLCanvasElement for accurate CSS pixel measurement.\n const canvasCssWidth = getCanvasCssWidth(gpuContext.canvas);\n const visibleXRangeMs = Math.abs(visibleXDomain.max - visibleXDomain.min);\n\n let xTickCount = DEFAULT_TICK_COUNT;\n let xTickValues: readonly number[] = [];\n if (currentOptions.xAxis.type === 'time') {\n const computed = computeAdaptiveTimeXAxisTicks({\n axisMin: finiteOrNull(currentOptions.xAxis.min),\n axisMax: finiteOrNull(currentOptions.xAxis.max),\n xScale,\n plotClipLeft: plotClipRect.left,\n plotClipRight: plotClipRect.right,\n canvasCssWidth,\n visibleRangeMs: visibleXRangeMs,\n measureCtx: tickMeasureCtx,\n measureCache: tickMeasureCache ?? undefined,\n fontSize: currentOptions.theme.fontSize,\n fontFamily: currentOptions.theme.fontFamily || 'sans-serif',\n });\n xTickCount = computed.tickCount;\n xTickValues = computed.tickValues;\n } else {\n // Keep existing behavior for non-time x axes.\n const domainMin = finiteOrUndefined(currentOptions.xAxis.min) ?? xScale.invert(plotClipRect.left);\n const domainMax = finiteOrUndefined(currentOptions.xAxis.max) ?? xScale.invert(plotClipRect.right);\n xTickValues = generateLinearTicks(domainMin, domainMax, xTickCount);\n }\n\n const interactionScales = computeInteractionScalesGridCssPx(gridArea, {\n xDomain: { min: visibleXDomain.min, max: visibleXDomain.max },\n yDomain: yBaseDomain,\n });\n lastInteractionScales = interactionScales;\n\n // Story 5.17: during update transitions, render animated series snapshots.\n const seriesForRender =\n updateTransition && updateP < 1\n ? interpolateSeriesForUpdate(updateTransition.from.series, updateTransition.to.series, updateP, updateInterpolationCaches)\n : renderSeries;\n\n // Keep `interactionX` in sync with real pointer movement (domain units).\n if (\n pointerState.source === 'mouse' &&\n pointerState.hasPointer &&\n pointerState.isInGrid &&\n interactionScales\n ) {\n const xDomain = interactionScales.xScale.invert(pointerState.gridX);\n setInteractionXInternal(Number.isFinite(xDomain) ? xDomain : null, 'mouse');\n }\n\n // Compute the effective interaction state:\n // - mouse: use the latest pointer event payload\n // - sync: derive a synthetic pointer position from `interactionX` (x only; y is arbitrary)\n let effectivePointer: PointerState = pointerState;\n if (pointerState.source === 'sync') {\n if (interactionX === null || !interactionScales) {\n effectivePointer = { ...pointerState, hasPointer: false, isInGrid: false };\n } else {\n const gridX = interactionScales.xScale.scale(interactionX);\n const gridY = interactionScales.plotHeightCss * 0.5;\n const isInGrid =\n Number.isFinite(gridX) &&\n Number.isFinite(gridY) &&\n gridX >= 0 &&\n gridX <= interactionScales.plotWidthCss &&\n gridY >= 0 &&\n gridY <= interactionScales.plotHeightCss;\n\n effectivePointer = {\n source: 'sync',\n gridX: Number.isFinite(gridX) ? gridX : 0,\n gridY: Number.isFinite(gridY) ? gridY : 0,\n // Crosshair/tooltip expect CANVAS-LOCAL CSS px.\n x: gridArea.left + (Number.isFinite(gridX) ? gridX : 0),\n y: gridArea.top + (Number.isFinite(gridY) ? gridY : 0),\n isInGrid,\n hasPointer: isInGrid,\n };\n }\n }\n\n // Prepare overlay renderers (grid, axes, crosshair, highlight)\n prepareOverlays(\n { gridRenderer, xAxisRenderer, yAxisRenderer, crosshairRenderer, highlightRenderer },\n {\n currentOptions,\n xScale,\n yScale,\n gridArea,\n xTickCount,\n hasCartesianSeries,\n effectivePointer,\n interactionScales,\n seriesForRender,\n withAlpha,\n }\n );\n\n // Tooltip: on hover, find matches and render tooltip near cursor.\n // Note: Tooltips require HTMLCanvasElement (DOM-specific positioning).\n if (effectivePointer.hasPointer && effectivePointer.isInGrid && currentOptions.tooltip?.show !== false) {\n const canvas = gpuContext.canvas;\n\n if (interactionScales && canvas && isHTMLCanvasElement(canvas)) {\n const formatter = currentOptions.tooltip?.formatter;\n const trigger = currentOptions.tooltip?.trigger ?? 'item';\n\n const containerX = canvas.offsetLeft + effectivePointer.x;\n const containerY = canvas.offsetTop + effectivePointer.y;\n\n if (effectivePointer.source === 'sync') {\n // Sync semantics:\n // - Tooltip should be driven by x only (no y).\n // - In 'axis' mode, show one entry per series nearest in x.\n // - In 'item' mode, pick a deterministic single entry (first matching series).\n // findPointsAtX handles visibility filtering internally and returns correct series indices\n const matches = findPointsAtX(seriesForRender, effectivePointer.gridX, interactionScales.xScale);\n if (matches.length === 0) {\n hideTooltip();\n } else if (trigger === 'axis') {\n const paramsArray = matches.map((m) => buildTooltipParams(m.seriesIndex, m.dataIndex, m.point));\n const content = formatter\n ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)(paramsArray)\n : formatTooltipAxis(paramsArray);\n if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n lastTooltipContent = content;\n lastTooltipX = containerX;\n lastTooltipY = containerY;\n showTooltipInternal(containerX, containerY, content, paramsArray);\n } else if (!content) {\n hideTooltip();\n }\n } else {\n const m0 = matches[0];\n const params = buildTooltipParams(m0.seriesIndex, m0.dataIndex, m0.point);\n const content = formatter ? (formatter as (p: TooltipParams) => string)(params) : formatTooltipItem(params);\n if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n lastTooltipContent = content;\n lastTooltipX = containerX;\n lastTooltipY = containerY;\n showTooltipInternal(containerX, containerY, content, params);\n } else if (!content) {\n hideTooltip();\n }\n }\n } else if (trigger === 'axis') {\n // Story 4.14: pie slice tooltip hit-testing (mouse only).\n // If the cursor is over a pie slice, prefer showing that slice tooltip.\n // findPieSliceAtPointer handles visibility filtering internally and returns correct series indices\n const pieMatch = findPieSliceAtPointer(\n seriesForRender,\n effectivePointer.gridX,\n effectivePointer.gridY,\n interactionScales.plotWidthCss,\n interactionScales.plotHeightCss\n );\n\n if (pieMatch) {\n const params: TooltipParams = {\n seriesName: pieMatch.slice.name,\n seriesIndex: pieMatch.seriesIndex,\n dataIndex: pieMatch.dataIndex,\n value: [0, pieMatch.slice.value],\n color: pieMatch.slice.color,\n };\n\n const content = formatter\n ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)([params])\n : formatTooltipItem(params);\n if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n lastTooltipContent = content;\n lastTooltipX = containerX;\n lastTooltipY = containerY;\n showTooltipInternal(containerX, containerY, content, [params]);\n } else if (!content) {\n hideTooltip();\n }\n } else {\n // Candlestick body hit-testing (mouse, axis trigger): include only when inside candle body.\n // Hit-testing functions handle visibility filtering internally and return correct series indices\n const candlestickResult = findCandlestickAtPointer(\n seriesForRender,\n effectivePointer.gridX,\n effectivePointer.gridY,\n interactionScales\n );\n\n const matches = findPointsAtX(seriesForRender, effectivePointer.gridX, interactionScales.xScale);\n if (matches.length === 0) {\n if (candlestickResult) {\n const paramsArray = [candlestickResult.params];\n const content = formatter\n ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)(paramsArray)\n : formatTooltipAxis(paramsArray);\n if (content) {\n // Use candlestick anchor for tooltip positioning\n const anchor = computeCandlestickTooltipAnchor(\n candlestickResult.match,\n interactionScales.xScale,\n interactionScales.yScale,\n gridArea,\n canvas\n );\n const tooltipX = anchor?.x ?? containerX;\n const tooltipY = anchor?.y ?? containerY;\n if (content !== lastTooltipContent || tooltipX !== lastTooltipX || tooltipY !== lastTooltipY) {\n lastTooltipContent = content;\n lastTooltipX = tooltipX;\n lastTooltipY = tooltipY;\n showTooltipInternal(tooltipX, tooltipY, content, paramsArray);\n }\n } else {\n hideTooltip();\n }\n } else {\n hideTooltip();\n }\n } else {\n const paramsArray = matches.map((m) => buildTooltipParams(m.seriesIndex, m.dataIndex, m.point));\n if (candlestickResult) paramsArray.push(candlestickResult.params);\n const content = formatter\n ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)(paramsArray)\n : formatTooltipAxis(paramsArray);\n if (content) {\n // Use candlestick anchor if candlestick is present in tooltip\n let tooltipX = containerX;\n let tooltipY = containerY;\n if (candlestickResult) {\n const anchor = computeCandlestickTooltipAnchor(\n candlestickResult.match,\n interactionScales.xScale,\n interactionScales.yScale,\n gridArea,\n canvas\n );\n if (anchor) {\n tooltipX = anchor.x;\n tooltipY = anchor.y;\n }\n }\n if (content !== lastTooltipContent || tooltipX !== lastTooltipX || tooltipY !== lastTooltipY) {\n lastTooltipContent = content;\n lastTooltipX = tooltipX;\n lastTooltipY = tooltipY;\n showTooltipInternal(tooltipX, tooltipY, content, paramsArray);\n }\n } else {\n hideTooltip();\n }\n }\n }\n } else {\n // Story 4.14: pie slice tooltip hit-testing (mouse only).\n // If the cursor is over a pie slice, prefer showing that slice tooltip.\n // findPieSliceAtPointer handles visibility filtering internally and returns correct series indices\n const pieMatch = findPieSliceAtPointer(\n seriesForRender,\n effectivePointer.gridX,\n effectivePointer.gridY,\n interactionScales.plotWidthCss,\n interactionScales.plotHeightCss\n );\n\n if (pieMatch) {\n const params: TooltipParams = {\n seriesName: pieMatch.slice.name,\n seriesIndex: pieMatch.seriesIndex,\n dataIndex: pieMatch.dataIndex,\n value: [0, pieMatch.slice.value],\n color: pieMatch.slice.color,\n };\n const content = formatter\n ? (formatter as (p: TooltipParams) => string)(params)\n : formatTooltipItem(params);\n if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n lastTooltipContent = content;\n lastTooltipX = containerX;\n lastTooltipY = containerY;\n showTooltipInternal(containerX, containerY, content, params);\n } else if (!content) {\n hideTooltip();\n }\n } else {\n // Candlestick body hit-testing (mouse, item trigger): prefer candle body over nearest-point logic.\n // Hit-testing functions handle visibility filtering internally and return correct series indices\n const candlestickResult = findCandlestickAtPointer(\n seriesForRender,\n effectivePointer.gridX,\n effectivePointer.gridY,\n interactionScales\n );\n if (candlestickResult) {\n const content = formatter\n ? (formatter as (p: TooltipParams) => string)(candlestickResult.params)\n : formatTooltipItem(candlestickResult.params);\n if (content) {\n // Use candlestick anchor for tooltip positioning\n const anchor = computeCandlestickTooltipAnchor(\n candlestickResult.match,\n interactionScales.xScale,\n interactionScales.yScale,\n gridArea,\n canvas\n );\n const tooltipX = anchor?.x ?? containerX;\n const tooltipY = anchor?.y ?? containerY;\n if (content !== lastTooltipContent || tooltipX !== lastTooltipX || tooltipY !== lastTooltipY) {\n lastTooltipContent = content;\n lastTooltipX = tooltipX;\n lastTooltipY = tooltipY;\n showTooltipInternal(tooltipX, tooltipY, content, candlestickResult.params);\n }\n } else {\n hideTooltip();\n }\n return;\n }\n\n const match = findNearestPoint(\n seriesForRender,\n effectivePointer.gridX,\n effectivePointer.gridY,\n interactionScales.xScale,\n interactionScales.yScale\n );\n if (!match) {\n hideTooltip();\n } else {\n const params = buildTooltipParams(match.seriesIndex, match.dataIndex, match.point);\n const content = formatter\n ? (formatter as (p: TooltipParams) => string)(params)\n : formatTooltipItem(params);\n if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n lastTooltipContent = content;\n lastTooltipX = containerX;\n lastTooltipY = containerY;\n showTooltipInternal(containerX, containerY, content, params);\n } else if (!content) {\n hideTooltip();\n }\n }\n }\n }\n } else {\n hideTooltip();\n }\n } else {\n hideTooltip();\n }\n\n // Compute maxRadiusCss for pie intro animation\n const plotSize = interactionScales ?? (canvas && isHTMLCanvasElement(canvas) ? getPlotSizeCssPx(canvas, gridArea) : null);\n const maxRadiusCss =\n plotSize && typeof plotSize.plotWidthCss === 'number' && typeof plotSize.plotHeightCss === 'number'\n ? 0.5 * Math.min(plotSize.plotWidthCss, plotSize.plotHeightCss)\n : 0;\n\n // Prepare all series renderers (area, line, bar, scatter, pie, candlestick)\n const seriesPreparation = prepareSeries(\n {\n lineRenderers,\n areaRenderers,\n barRenderer,\n scatterRenderers,\n scatterDensityRenderers,\n pieRenderers,\n candlestickRenderers,\n },\n {\n currentOptions,\n seriesForRender,\n xScale,\n yScale,\n gridArea,\n dataStore,\n appendedGpuThisFrame,\n gpuSeriesKindByIndex,\n zoomState,\n visibleXDomain,\n introPhase,\n introProgress01,\n withAlpha,\n maxRadiusCss,\n }\n );\n\n const { visibleBarSeriesConfigs } = seriesPreparation;\n\n // Prepare bar renderer with animated scale if intro is running\n const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n const yScaleForBars = introP < 1 ? createAnimatedBarYScale(yScale, plotClipRect, visibleBarSeriesConfigs, introP) : yScale;\n barRenderer.prepare(visibleBarSeriesConfigs, dataStore, xScale, yScaleForBars, gridArea);\n\n // Prepare annotation GPU overlays (reference lines + point markers).\n // Note: these renderers expect CANVAS-LOCAL CSS pixel coordinates; the coordinator owns\n // data-space → canvas-space conversion and plot scissor state.\n if (hasCartesianSeries) {\n referenceLineRenderer.prepare(gridArea, combinedReferenceLines);\n referenceLineRendererMsaa.prepare(gridArea, combinedReferenceLines);\n annotationMarkerRenderer.prepare({\n canvasWidth: gridArea.canvasWidth,\n canvasHeight: gridArea.canvasHeight,\n devicePixelRatio: gridArea.devicePixelRatio,\n instances: combinedMarkers,\n });\n annotationMarkerRendererMsaa.prepare({\n canvasWidth: gridArea.canvasWidth,\n canvasHeight: gridArea.canvasHeight,\n devicePixelRatio: gridArea.devicePixelRatio,\n instances: combinedMarkers,\n });\n } else {\n // Ensure prior frame instances don't persist visually if series mode changes.\n referenceLineRenderer.prepare(gridArea, []);\n referenceLineRendererMsaa.prepare(gridArea, []);\n annotationMarkerRenderer.prepare({\n canvasWidth: gridArea.canvasWidth,\n canvasHeight: gridArea.canvasHeight,\n devicePixelRatio: gridArea.devicePixelRatio,\n instances: [],\n });\n annotationMarkerRendererMsaa.prepare({\n canvasWidth: gridArea.canvasWidth,\n canvasHeight: gridArea.canvasHeight,\n devicePixelRatio: gridArea.devicePixelRatio,\n instances: [],\n });\n }\n\n ensureOverlayTargets(gridArea.canvasWidth, gridArea.canvasHeight);\n\n // Swapchain view for the resolved MSAA overlay pass and for the final (load) overlay pass.\n const swapchainView = gpuContext.canvasContext.getCurrentTexture().createView();\n const encoder = device.createCommandEncoder({ label: 'renderCoordinator/commandEncoder' });\n const clearValue = parseCssColorToGPUColor(currentOptions.theme.backgroundColor, { r: 0, g: 0, b: 0, a: 1 });\n\n // Encode compute passes (scatter density) before the render pass.\n encodeScatterDensityCompute(\n { lineRenderers, areaRenderers, barRenderer, scatterRenderers, scatterDensityRenderers, pieRenderers, candlestickRenderers },\n seriesForRender,\n encoder\n );\n\n const mainPass = encoder.beginRenderPass({\n label: 'renderCoordinator/mainPass',\n colorAttachments: [\n {\n view: mainColorView!,\n clearValue,\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n });\n\n // Render order:\n // - grid first (background)\n // - pies early (non-cartesian, visible behind cartesian series)\n // - area fills next (so they don't cover strokes/axes)\n // - bars next (fills)\n // - scatter next (points on top of fills, below strokes/overlays)\n // - line strokes next\n // - highlight next (on top of strokes)\n // - axes last (on top)\n if (gridRenderer) {\n gridRenderer.render(mainPass);\n }\n\n // Render all series to the main pass with proper layering\n renderSeriesPass(\n { lineRenderers, areaRenderers, barRenderer, scatterRenderers, scatterDensityRenderers, pieRenderers, candlestickRenderers },\n { referenceLineRenderer, referenceLineRendererMsaa, annotationMarkerRenderer, annotationMarkerRendererMsaa },\n {\n hasCartesianSeries,\n gridArea,\n mainPass,\n plotScissor,\n introPhase,\n introProgress01,\n referenceLineBelowCount,\n markerBelowCount,\n },\n seriesPreparation\n );\n\n mainPass.end();\n\n // MSAA annotation overlay pass: blit main color → MSAA target, then draw above-series annotations.\n const overlayPass = encoder.beginRenderPass({\n label: 'renderCoordinator/annotationOverlayMsaaPass',\n colorAttachments: [\n {\n view: overlayMsaaView!,\n resolveTarget: swapchainView,\n clearValue,\n loadOp: 'clear',\n storeOp: 'discard',\n },\n ],\n });\n\n overlayPass.setPipeline(overlayBlitPipeline);\n overlayPass.setBindGroup(0, overlayBlitBindGroup!);\n overlayPass.draw(3);\n\n // Render above-series annotations to the overlay pass\n renderAboveSeriesAnnotations(\n { referenceLineRenderer, referenceLineRendererMsaa, annotationMarkerRenderer, annotationMarkerRendererMsaa },\n {\n hasCartesianSeries,\n gridArea,\n overlayPass,\n plotScissor,\n referenceLineBelowCount,\n referenceLineAboveCount,\n markerBelowCount,\n markerAboveCount,\n }\n );\n\n overlayPass.end();\n\n // Top overlays (single-sample): axes, highlights, crosshair.\n const topOverlayPass = encoder.beginRenderPass({\n label: 'renderCoordinator/topOverlayPass',\n colorAttachments: [\n {\n view: swapchainView,\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n });\n\n highlightRenderer.render(topOverlayPass);\n if (hasCartesianSeries) {\n xAxisRenderer.render(topOverlayPass);\n yAxisRenderer.render(topOverlayPass);\n }\n crosshairRenderer.render(topOverlayPass);\n\n topOverlayPass.end();\n device.queue.submit([encoder.finish()]);\n\n hasRenderedOnce = true;\n\n // Generate axis labels for DOM overlay\n renderAxisLabels(axisLabelOverlay, overlayContainer, {\n gpuContext,\n currentOptions,\n xScale,\n yScale,\n xTickValues,\n plotClipRect,\n visibleXRangeMs,\n });\n\n // Generate annotation labels (DOM overlay)\n renderAnnotationLabels(annotationOverlay, overlayContainer, {\n currentOptions,\n xScale,\n yScale,\n canvasCssWidthForAnnotations,\n canvasCssHeightForAnnotations,\n plotLeftCss,\n plotTopCss,\n plotWidthCss,\n plotHeightCss,\n canvas,\n });\n };\n\n\n const dispose: RenderCoordinator['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n // Story 5.16: stop intro animation and avoid further render requests.\n try {\n if (introAnimId) introAnimController.cancel(introAnimId);\n introAnimController.cancelAll();\n } catch {\n // best-effort\n }\n introAnimId = null;\n introPhase = 'done';\n introProgress01 = 1;\n\n // Story 5.17: stop update animation and avoid further render requests.\n try {\n if (updateAnimId) updateAnimController.cancel(updateAnimId);\n updateAnimController.cancelAll();\n } catch {\n // best-effort\n }\n updateAnimId = null;\n updateProgress01 = 1;\n updateTransition = null;\n\n cancelScheduledFlush();\n cancelZoomResampleDebounce();\n zoomResampleDue = false;\n\n pendingAppendByIndex.clear();\n\n insideZoom?.dispose();\n insideZoom = null;\n unsubscribeZoom?.();\n unsubscribeZoom = null;\n zoomState = null;\n lastOptionsZoomRange = null;\n zoomRangeListeners.clear();\n\n eventManager?.dispose();\n crosshairRenderer.dispose();\n highlightRenderer.dispose();\n\n for (let i = 0; i < areaRenderers.length; i++) {\n areaRenderers[i].dispose();\n }\n areaRenderers.length = 0;\n\n for (let i = 0; i < lineRenderers.length; i++) {\n lineRenderers[i].dispose();\n }\n lineRenderers.length = 0;\n\n for (let i = 0; i < scatterRenderers.length; i++) {\n scatterRenderers[i].dispose();\n }\n scatterRenderers.length = 0;\n\n for (let i = 0; i < pieRenderers.length; i++) {\n pieRenderers[i].dispose();\n }\n pieRenderers.length = 0;\n\n for (let i = 0; i < candlestickRenderers.length; i++) {\n candlestickRenderers[i].dispose();\n }\n candlestickRenderers.length = 0;\n\n barRenderer.dispose();\n\n gridRenderer.dispose();\n xAxisRenderer.dispose();\n yAxisRenderer.dispose();\n referenceLineRenderer.dispose();\n annotationMarkerRenderer.dispose();\n referenceLineRendererMsaa.dispose();\n annotationMarkerRendererMsaa.dispose();\n\n destroyTexture(mainColorTexture);\n destroyTexture(overlayMsaaTexture);\n mainColorTexture = null;\n mainColorView = null;\n overlayMsaaTexture = null;\n overlayMsaaView = null;\n overlayBlitBindGroup = null;\n\n dataStore.dispose();\n\n // Dispose tooltip/legend before the text overlay (all touch container positioning).\n tooltip?.dispose();\n tooltip = null;\n legend?.dispose();\n axisLabelOverlay?.dispose();\n annotationOverlay?.dispose();\n };\n\n const getInteractionX: RenderCoordinator['getInteractionX'] = () => interactionX;\n\n const setInteractionX: RenderCoordinator['setInteractionX'] = (x, source) => {\n assertNotDisposed();\n const normalized = x !== null && Number.isFinite(x) ? x : null;\n\n // External interaction should not depend on y, so we treat it as “sync” mode.\n pointerState = { ...pointerState, source: normalized === null ? 'mouse' : 'sync' };\n\n setInteractionXInternal(normalized, source);\n\n if (normalized === null && pointerState.hasPointer === false) {\n crosshairRenderer.setVisible(false);\n highlightRenderer.setVisible(false);\n hideTooltipInternal();\n }\n requestRender();\n };\n\n const onInteractionXChange: RenderCoordinator['onInteractionXChange'] = (callback) => {\n assertNotDisposed();\n interactionXListeners.add(callback);\n return () => {\n interactionXListeners.delete(callback);\n };\n };\n\n const getZoomRange: RenderCoordinator['getZoomRange'] = () => {\n return zoomState?.getRange() ?? null;\n };\n\n const setZoomRange: RenderCoordinator['setZoomRange'] = (start, end) => {\n assertNotDisposed();\n if (!zoomState) return;\n zoomState.setRange(start, end);\n // onChange will requestRender + emit.\n };\n\n const onZoomRangeChange: RenderCoordinator['onZoomRangeChange'] = (cb) => {\n assertNotDisposed();\n zoomRangeListeners.add(cb);\n return () => {\n zoomRangeListeners.delete(cb);\n };\n };\n\n return {\n setOptions,\n appendData,\n getInteractionX,\n setInteractionX,\n onInteractionXChange,\n getZoomRange,\n setZoomRange,\n onZoomRangeChange,\n render,\n dispose,\n };\n}\n\n","import type {\n AreaStyleConfig,\n CandlestickItemStyleConfig,\n CandlestickStyle,\n ChartGPUOptions,\n GridConfig,\n LineStyleConfig,\n} from './types';\n\nexport const defaultGrid = {\n left: 60,\n right: 20,\n top: 40,\n bottom: 40,\n} as const satisfies Required<GridConfig>;\n\nexport const defaultPalette = [\n '#5470C6',\n '#91CC75',\n '#FAC858',\n '#EE6666',\n '#73C0DE',\n '#3BA272',\n '#FC8452',\n '#9A60B4',\n '#EA7CCC',\n] as const;\n\nexport const defaultLineStyle = {\n width: 2,\n opacity: 1,\n} as const satisfies Required<Omit<LineStyleConfig, 'color'>>;\n\nexport const defaultAreaStyle = {\n opacity: 0.25,\n} as const satisfies Required<Omit<AreaStyleConfig, 'color'>>;\n\nexport const candlestickDefaults = {\n style: 'classic' as CandlestickStyle,\n itemStyle: {\n upColor: '#22c55e',\n downColor: '#ef4444',\n upBorderColor: '#22c55e',\n downBorderColor: '#ef4444',\n borderWidth: 1,\n } as const satisfies Required<CandlestickItemStyleConfig>,\n barWidth: '80%' as const,\n barMinWidth: 1,\n barMaxWidth: 50,\n sampling: 'ohlc' as const,\n samplingThreshold: 5000,\n} as const;\n\nexport const scatterDefaults = {\n mode: 'points' as const,\n // Bin size in CSS pixels for density mode. Must be > 0.\n binSize: 2,\n densityColormap: 'viridis' as const,\n densityNormalization: 'log' as const,\n} as const;\n\nexport const defaultOptions = {\n grid: defaultGrid,\n xAxis: { type: 'value' },\n yAxis: { type: 'value', autoBounds: 'visible' },\n autoScroll: false,\n theme: 'dark',\n palette: defaultPalette,\n series: [],\n} as const satisfies Readonly<\n Required<Pick<ChartGPUOptions, 'grid' | 'xAxis' | 'yAxis' | 'autoScroll' | 'theme' | 'palette'>> & {\n readonly series: readonly [];\n }\n>;\n\n","import type { ThemeConfig } from './types';\n\nconst palette = [\n '#00E5FF',\n '#FF2D95',\n '#B026FF',\n '#00F5A0',\n '#FFD300',\n '#FF6B00',\n '#4D5BFF',\n '#FF3D3D',\n] as const;\n\nexport const darkTheme = {\n backgroundColor: '#1a1a2e',\n textColor: '#e0e0e0',\n axisLineColor: 'rgba(224,224,224,0.35)',\n axisTickColor: 'rgba(224,224,224,0.55)',\n gridLineColor: 'rgba(255,255,255,0.1)',\n colorPalette: [...palette],\n fontFamily:\n 'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n fontSize: 12,\n} satisfies ThemeConfig;\n","import type { ThemeConfig } from './types';\n\nconst palette = [\n '#1F77B4',\n '#FF7F0E',\n '#2CA02C',\n '#D62728',\n '#9467BD',\n '#8C564B',\n '#E377C2',\n '#17BECF',\n] as const;\n\nexport const lightTheme = {\n backgroundColor: '#ffffff',\n textColor: '#333333',\n axisLineColor: 'rgba(0,0,0,0.35)',\n axisTickColor: 'rgba(0,0,0,0.55)',\n gridLineColor: 'rgba(0,0,0,0.1)',\n colorPalette: [...palette],\n fontFamily:\n 'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n fontSize: 12,\n} satisfies ThemeConfig;\n","import type { ThemeConfig } from './types';\nimport { darkTheme } from './darkTheme';\nimport { lightTheme } from './lightTheme';\n\nexport { darkTheme, lightTheme };\nexport type { ThemeConfig };\n\nexport type ThemeName = 'dark' | 'light';\n\nexport function getTheme(name: ThemeName): ThemeConfig {\n return name === 'dark' ? darkTheme : lightTheme;\n}\n","import type {\n AreaStyleConfig,\n AnnotationConfig,\n AnnotationLabel,\n AnnotationLabelAnchor,\n AnnotationLabelBackground,\n AnnotationPointMarker,\n AxisConfig,\n CandlestickItemStyleConfig,\n CandlestickSeriesConfig,\n CandlestickStyle,\n ChartGPUOptions,\n DataZoomConfig,\n GridConfig,\n LineStyleConfig,\n OHLCDataPoint,\n OHLCDataPointTuple,\n AreaSeriesConfig,\n BarSeriesConfig,\n LineSeriesConfig,\n PieDataItem,\n PieSeriesConfig,\n ScatterSeriesConfig,\n ScatterSymbol,\n SeriesSampling,\n} from './types';\nimport {\n candlestickDefaults,\n defaultAreaStyle,\n defaultLineStyle,\n defaultOptions,\n defaultPalette,\n scatterDefaults,\n} from './defaults';\nimport { getTheme } from '../themes';\nimport type { ThemeConfig } from '../themes/types';\nimport { sampleSeriesDataPoints } from '../data/sampleSeries';\nimport { ohlcSample } from '../data/ohlcSample';\nimport { computeRawBoundsFromCartesianData } from '../data/cartesianData';\n\nexport type ResolvedGridConfig = Readonly<Required<GridConfig>>;\nexport type ResolvedLineStyleConfig = Readonly<Required<Omit<LineStyleConfig, 'color'>> & { readonly color: string }>;\nexport type ResolvedAreaStyleConfig = Readonly<Required<Omit<AreaStyleConfig, 'color'>> & { readonly color: string }>;\n\nexport type RawBounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\nexport type ResolvedLineSeriesConfig = Readonly<\n Omit<LineSeriesConfig, 'color' | 'lineStyle' | 'areaStyle' | 'sampling' | 'samplingThreshold' | 'data'> & {\n readonly color: string;\n readonly lineStyle: ResolvedLineStyleConfig;\n readonly areaStyle?: ResolvedAreaStyleConfig;\n readonly sampling: SeriesSampling;\n readonly samplingThreshold: number;\n /**\n * Original (unsampled) series data.\n *\n * Used at runtime for zoom-aware re-sampling so we can increase detail when zoomed-in without\n * losing outliers or permanently discarding points.\n */\n readonly rawData: Readonly<LineSeriesConfig['data']>;\n readonly data: Readonly<LineSeriesConfig['data']>;\n /**\n * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n * cannot clip outliers.\n */\n readonly rawBounds?: RawBounds;\n }\n>;\n\nexport type ResolvedAreaSeriesConfig = Readonly<\n Omit<AreaSeriesConfig, 'color' | 'areaStyle' | 'sampling' | 'samplingThreshold' | 'data'> & {\n readonly color: string;\n readonly areaStyle: ResolvedAreaStyleConfig;\n readonly sampling: SeriesSampling;\n readonly samplingThreshold: number;\n /** Original (unsampled) series data (see `ResolvedLineSeriesConfig.rawData`). */\n readonly rawData: Readonly<AreaSeriesConfig['data']>;\n readonly data: Readonly<AreaSeriesConfig['data']>;\n /**\n * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n * cannot clip outliers.\n */\n readonly rawBounds?: RawBounds;\n }\n>;\n\nexport type ResolvedBarSeriesConfig = Readonly<\n Omit<BarSeriesConfig, 'color' | 'sampling' | 'samplingThreshold' | 'data'> & {\n readonly color: string;\n readonly sampling: SeriesSampling;\n readonly samplingThreshold: number;\n /** Original (unsampled) series data (see `ResolvedLineSeriesConfig.rawData`). */\n readonly rawData: Readonly<BarSeriesConfig['data']>;\n readonly data: Readonly<BarSeriesConfig['data']>;\n /**\n * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n * cannot clip outliers.\n */\n readonly rawBounds?: RawBounds;\n }\n>;\n\nexport type ResolvedScatterSeriesConfig = Readonly<\n Omit<\n ScatterSeriesConfig,\n 'color' | 'sampling' | 'samplingThreshold' | 'data' | 'mode' | 'binSize' | 'densityColormap' | 'densityNormalization'\n > & {\n readonly color: string;\n readonly sampling: SeriesSampling;\n readonly samplingThreshold: number;\n readonly mode: NonNullable<ScatterSeriesConfig['mode']>;\n readonly binSize: number;\n readonly densityColormap: NonNullable<ScatterSeriesConfig['densityColormap']>;\n readonly densityNormalization: NonNullable<ScatterSeriesConfig['densityNormalization']>;\n /** Original (unsampled) series data (see `ResolvedLineSeriesConfig.rawData`). */\n readonly rawData: Readonly<ScatterSeriesConfig['data']>;\n readonly data: Readonly<ScatterSeriesConfig['data']>;\n /**\n * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n * cannot clip outliers.\n */\n readonly rawBounds?: RawBounds;\n }\n>;\n\nexport type ResolvedPieDataItem = Readonly<\n Omit<PieDataItem, 'color' | 'visible'> & {\n readonly color: string;\n readonly visible: boolean;\n }\n>;\n\nexport type ResolvedPieSeriesConfig = Readonly<\n Omit<PieSeriesConfig, 'color' | 'data'> & {\n readonly color: string;\n readonly data: ReadonlyArray<ResolvedPieDataItem>;\n }\n>;\n\nexport type ResolvedCandlestickItemStyleConfig = Readonly<Required<CandlestickItemStyleConfig>>;\n\nexport type ResolvedCandlestickSeriesConfig = Readonly<\n Omit<CandlestickSeriesConfig, 'color' | 'style' | 'itemStyle' | 'barWidth' | 'barMinWidth' | 'barMaxWidth' | 'sampling' | 'samplingThreshold' | 'data'> & {\n readonly color: string;\n readonly style: CandlestickStyle;\n readonly itemStyle: ResolvedCandlestickItemStyleConfig;\n readonly barWidth: number | string;\n readonly barMinWidth: number;\n readonly barMaxWidth: number;\n readonly sampling: 'none' | 'ohlc';\n readonly samplingThreshold: number;\n /** Original (unsampled) series data. */\n readonly rawData: Readonly<CandlestickSeriesConfig['data']>;\n readonly data: Readonly<CandlestickSeriesConfig['data']>;\n /**\n * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n * cannot clip outliers.\n */\n readonly rawBounds?: RawBounds;\n }\n>;\n\nexport type ResolvedSeriesConfig =\n | ResolvedLineSeriesConfig\n | ResolvedAreaSeriesConfig\n | ResolvedBarSeriesConfig\n | ResolvedScatterSeriesConfig\n | ResolvedPieSeriesConfig\n | ResolvedCandlestickSeriesConfig;\n\nexport interface ResolvedChartGPUOptions\n extends Omit<ChartGPUOptions, 'grid' | 'xAxis' | 'yAxis' | 'theme' | 'palette' | 'series' | 'legend'> {\n readonly grid: ResolvedGridConfig;\n readonly xAxis: AxisConfig;\n readonly yAxis: AxisConfig;\n readonly autoScroll: boolean;\n readonly theme: ThemeConfig;\n readonly palette: ReadonlyArray<string>;\n readonly series: ReadonlyArray<ResolvedSeriesConfig>;\n readonly annotations?: ReadonlyArray<AnnotationConfig>;\n readonly legend?: import('./types').LegendConfig;\n}\n\nconst sanitizeDataZoom = (input: unknown): ReadonlyArray<DataZoomConfig> | undefined => {\n if (!Array.isArray(input)) return undefined;\n\n const out: DataZoomConfig[] = [];\n\n for (const item of input) {\n if (item === null || typeof item !== 'object' || Array.isArray(item)) continue;\n const record = item as Record<string, unknown>;\n\n const type = record.type;\n if (type !== 'inside' && type !== 'slider') continue;\n\n const xAxisIndexRaw = record.xAxisIndex;\n const startRaw = record.start;\n const endRaw = record.end;\n const minSpanRaw = record.minSpan;\n const maxSpanRaw = record.maxSpan;\n\n const xAxisIndex =\n typeof xAxisIndexRaw === 'number' && Number.isFinite(xAxisIndexRaw) ? xAxisIndexRaw : undefined;\n const start = typeof startRaw === 'number' && Number.isFinite(startRaw) ? startRaw : undefined;\n const end = typeof endRaw === 'number' && Number.isFinite(endRaw) ? endRaw : undefined;\n const minSpan =\n typeof minSpanRaw === 'number' && Number.isFinite(minSpanRaw) ? minSpanRaw : undefined;\n const maxSpan =\n typeof maxSpanRaw === 'number' && Number.isFinite(maxSpanRaw) ? maxSpanRaw : undefined;\n\n out.push({ type, xAxisIndex, start, end, minSpan, maxSpan });\n }\n\n return out;\n};\n\nconst sanitizeAnnotations = (input: unknown): ReadonlyArray<AnnotationConfig> | undefined => {\n if (!Array.isArray(input)) return undefined;\n\n const out: AnnotationConfig[] = [];\n\n const isLabelAnchor = (v: unknown): v is AnnotationLabelAnchor =>\n v === 'start' || v === 'center' || v === 'end';\n\n const isScatterSymbol = (v: unknown): v is ScatterSymbol =>\n v === 'circle' || v === 'rect' || v === 'triangle';\n\n const sanitizeString = (v: unknown): string | undefined => {\n if (typeof v !== 'string') return undefined;\n const t = v.trim();\n return t.length > 0 ? t : undefined;\n };\n\n const sanitizeFiniteNumber = (v: unknown): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n\n const sanitizeOpacity01 = (v: unknown): number | undefined => {\n const n = sanitizeFiniteNumber(v);\n if (n == null) return undefined;\n return Math.min(1, Math.max(0, n));\n };\n\n const sanitizeLineDash = (v: unknown): readonly number[] | undefined => {\n if (!Array.isArray(v)) return undefined;\n const cleaned = v\n .filter((x): x is number => typeof x === 'number' && Number.isFinite(x))\n .map((x) => x);\n if (cleaned.length === 0) return undefined;\n Object.freeze(cleaned);\n return cleaned;\n };\n\n const sanitizePadding = (v: unknown): number | readonly [number, number, number, number] | undefined => {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (!Array.isArray(v) || v.length !== 4) return undefined;\n const t = sanitizeFiniteNumber(v[0]);\n const r = sanitizeFiniteNumber(v[1]);\n const b = sanitizeFiniteNumber(v[2]);\n const l = sanitizeFiniteNumber(v[3]);\n if (t == null || r == null || b == null || l == null) return undefined;\n return [t, r, b, l] as const;\n };\n\n for (const item of input) {\n if (item === null || typeof item !== 'object' || Array.isArray(item)) continue;\n const record = item as Record<string, unknown>;\n\n const type = record.type;\n if (type !== 'lineX' && type !== 'lineY' && type !== 'point' && type !== 'text') continue;\n\n const id = sanitizeString(record.id);\n const layerRaw = record.layer;\n const layer = layerRaw === 'belowSeries' || layerRaw === 'aboveSeries' ? layerRaw : undefined;\n\n const styleRaw = record.style;\n const style =\n styleRaw && typeof styleRaw === 'object' && !Array.isArray(styleRaw)\n ? (() => {\n const s = styleRaw as Record<string, unknown>;\n const color = sanitizeString(s.color);\n const lineWidth = sanitizeFiniteNumber(s.lineWidth);\n const lineDash = sanitizeLineDash(s.lineDash);\n const opacity = sanitizeOpacity01(s.opacity);\n const next: Record<string, unknown> = {\n ...(color ? { color } : {}),\n ...(lineWidth != null ? { lineWidth } : {}),\n ...(lineDash ? { lineDash } : {}),\n ...(opacity != null ? { opacity } : {}),\n };\n return Object.keys(next).length > 0 ? (next as AnnotationConfig['style']) : undefined;\n })()\n : undefined;\n\n const labelRaw = record.label;\n const label =\n labelRaw && typeof labelRaw === 'object' && !Array.isArray(labelRaw)\n ? (() => {\n const l = labelRaw as Record<string, unknown>;\n const text = sanitizeString(l.text);\n const template = sanitizeString(l.template);\n const decimalsRaw = l.decimals;\n const decimals =\n typeof decimalsRaw === 'number' && Number.isFinite(decimalsRaw) && decimalsRaw >= 0\n ? Math.min(20, Math.floor(decimalsRaw))\n : undefined;\n const offsetRaw = l.offset;\n const offset =\n Array.isArray(offsetRaw) &&\n offsetRaw.length === 2 &&\n typeof offsetRaw[0] === 'number' &&\n Number.isFinite(offsetRaw[0]) &&\n typeof offsetRaw[1] === 'number' &&\n Number.isFinite(offsetRaw[1])\n ? ([offsetRaw[0], offsetRaw[1]] as const)\n : undefined;\n const anchorRaw = l.anchor;\n const anchor = isLabelAnchor(anchorRaw) ? anchorRaw : undefined;\n const bgRaw = l.background;\n const background =\n bgRaw && typeof bgRaw === 'object' && !Array.isArray(bgRaw)\n ? (() => {\n const bg = bgRaw as Record<string, unknown>;\n const color = sanitizeString(bg.color);\n const opacity = sanitizeOpacity01(bg.opacity);\n const padding = sanitizePadding(bg.padding);\n const borderRadius = sanitizeFiniteNumber(bg.borderRadius);\n const next: AnnotationLabelBackground = {\n ...(color ? { color } : {}),\n ...(opacity != null ? { opacity } : {}),\n ...(padding != null ? { padding } : {}),\n ...(borderRadius != null ? { borderRadius } : {}),\n };\n return Object.keys(next).length > 0 ? next : undefined;\n })()\n : undefined;\n\n const next: AnnotationLabel = {\n ...(text ? { text } : {}),\n ...(template ? { template } : {}),\n ...(decimals != null ? { decimals } : {}),\n ...(offset ? { offset } : {}),\n ...(anchor ? { anchor } : {}),\n ...(background ? { background } : {}),\n };\n\n return Object.keys(next).length > 0 ? next : undefined;\n })()\n : undefined;\n\n if (type === 'lineX') {\n const x = sanitizeFiniteNumber(record.x);\n if (x == null) continue;\n const base: AnnotationConfig = { type: 'lineX', x, ...(id ? { id } : {}), ...(layer ? { layer } : {}), ...(style ? { style } : {}), ...(label ? { label } : {}) };\n out.push(base);\n continue;\n }\n\n if (type === 'lineY') {\n const y = sanitizeFiniteNumber(record.y);\n if (y == null) continue;\n const base: AnnotationConfig = { type: 'lineY', y, ...(id ? { id } : {}), ...(layer ? { layer } : {}), ...(style ? { style } : {}), ...(label ? { label } : {}) };\n out.push(base);\n continue;\n }\n\n if (type === 'point') {\n const x = sanitizeFiniteNumber(record.x);\n const y = sanitizeFiniteNumber(record.y);\n if (x == null || y == null) continue;\n const markerRaw = record.marker;\n const marker =\n markerRaw && typeof markerRaw === 'object' && !Array.isArray(markerRaw)\n ? (() => {\n const m = markerRaw as Record<string, unknown>;\n const symbolRaw = m.symbol;\n const symbol = isScatterSymbol(symbolRaw) ? symbolRaw : undefined;\n const size = sanitizeFiniteNumber(m.size);\n const mStyleRaw = m.style;\n const mStyle =\n mStyleRaw && typeof mStyleRaw === 'object' && !Array.isArray(mStyleRaw)\n ? (() => {\n const s = mStyleRaw as Record<string, unknown>;\n const color = sanitizeString(s.color);\n const opacity = sanitizeOpacity01(s.opacity);\n const lineWidth = sanitizeFiniteNumber(s.lineWidth);\n const lineDash = sanitizeLineDash(s.lineDash);\n const next: Record<string, unknown> = {\n ...(color ? { color } : {}),\n ...(opacity != null ? { opacity } : {}),\n ...(lineWidth != null ? { lineWidth } : {}),\n ...(lineDash ? { lineDash } : {}),\n };\n return Object.keys(next).length > 0 ? (next as AnnotationConfig['style']) : undefined;\n })()\n : undefined;\n const next: AnnotationPointMarker = {\n ...(symbol ? { symbol } : {}),\n ...(size != null ? { size } : {}),\n ...(mStyle ? { style: mStyle } : {}),\n };\n return Object.keys(next).length > 0 ? next : undefined;\n })()\n : undefined;\n\n const base: AnnotationConfig = {\n type: 'point',\n x,\n y,\n ...(marker ? { marker } : {}),\n ...(id ? { id } : {}),\n ...(layer ? { layer } : {}),\n ...(style ? { style } : {}),\n ...(label ? { label } : {}),\n };\n out.push(base);\n continue;\n }\n\n // type === 'text'\n {\n const positionRaw = record.position;\n const text = sanitizeString(record.text);\n if (!text) continue;\n if (!positionRaw || typeof positionRaw !== 'object' || Array.isArray(positionRaw)) continue;\n const p = positionRaw as Record<string, unknown>;\n const space = p.space;\n if (space !== 'data' && space !== 'plot') continue;\n const x = sanitizeFiniteNumber(p.x);\n const y = sanitizeFiniteNumber(p.y);\n if (x == null || y == null) continue;\n const position = { space, x, y } as const;\n\n const base: AnnotationConfig = {\n type: 'text',\n position,\n text,\n ...(id ? { id } : {}),\n ...(layer ? { layer } : {}),\n ...(style ? { style } : {}),\n ...(label ? { label } : {}),\n };\n out.push(base);\n continue;\n }\n }\n\n if (out.length === 0) return undefined;\n Object.freeze(out);\n return out;\n};\n\nconst sanitizePalette = (palette: unknown): string[] => {\n if (!Array.isArray(palette)) return [];\n return palette\n .filter((c): c is string => typeof c === 'string')\n .map((c) => c.trim())\n .filter((c) => c.length > 0);\n};\n\nconst resolveTheme = (themeInput: unknown): ThemeConfig => {\n const base = getTheme('dark');\n\n if (typeof themeInput === 'string') {\n const name = themeInput.trim().toLowerCase();\n return name === 'light' ? getTheme('light') : getTheme('dark');\n }\n\n if (themeInput === null || typeof themeInput !== 'object' || Array.isArray(themeInput)) {\n return base;\n }\n\n const input = themeInput as Partial<Record<keyof ThemeConfig, unknown>>;\n const takeString = (key: keyof ThemeConfig): string | undefined => {\n const v = input[key];\n if (typeof v !== 'string') return undefined;\n const trimmed = v.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n };\n\n const fontSizeRaw = input.fontSize;\n const fontSize =\n typeof fontSizeRaw === 'number' && Number.isFinite(fontSizeRaw) ? fontSizeRaw : undefined;\n\n const colorPaletteCandidate = sanitizePalette(input.colorPalette);\n\n return {\n backgroundColor: takeString('backgroundColor') ?? base.backgroundColor,\n textColor: takeString('textColor') ?? base.textColor,\n axisLineColor: takeString('axisLineColor') ?? base.axisLineColor,\n axisTickColor: takeString('axisTickColor') ?? base.axisTickColor,\n gridLineColor: takeString('gridLineColor') ?? base.gridLineColor,\n colorPalette: colorPaletteCandidate.length > 0 ? colorPaletteCandidate : Array.from(base.colorPalette),\n fontFamily: takeString('fontFamily') ?? base.fontFamily,\n fontSize: fontSize ?? base.fontSize,\n };\n};\n\nconst normalizeOptionalColor = (color: unknown): string | undefined => {\n if (typeof color !== 'string') return undefined;\n const trimmed = color.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n};\n\nconst normalizeSampling = (value: unknown): SeriesSampling | undefined => {\n if (typeof value !== 'string') return undefined;\n const v = value.trim().toLowerCase();\n return v === 'none' || v === 'lttb' || v === 'average' || v === 'max' || v === 'min' || v === 'ohlc'\n ? (v as SeriesSampling)\n : undefined;\n};\n\nconst normalizeScatterMode = (value: unknown): NonNullable<ScatterSeriesConfig['mode']> | undefined => {\n if (typeof value !== 'string') return undefined;\n const v = value.trim().toLowerCase();\n return v === 'points' || v === 'density' ? (v as NonNullable<ScatterSeriesConfig['mode']>) : undefined;\n};\n\nconst normalizeDensityNormalization = (\n value: unknown\n): NonNullable<ScatterSeriesConfig['densityNormalization']> | undefined => {\n if (typeof value !== 'string') return undefined;\n const v = value.trim().toLowerCase();\n return v === 'linear' || v === 'sqrt' || v === 'log'\n ? (v as NonNullable<ScatterSeriesConfig['densityNormalization']>)\n : undefined;\n};\n\nconst normalizeDensityBinSize = (value: unknown): number | undefined => {\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n const v = Math.floor(value);\n return v > 0 ? Math.max(1, v) : undefined;\n};\n\nconst normalizeDensityColormap = (\n value: unknown\n): NonNullable<ScatterSeriesConfig['densityColormap']> | undefined => {\n if (typeof value === 'string') {\n const v = value.trim().toLowerCase();\n return v === 'viridis' || v === 'plasma' || v === 'inferno'\n ? (v as NonNullable<ScatterSeriesConfig['densityColormap']>)\n : undefined;\n }\n\n if (!Array.isArray(value)) return undefined;\n\n const isAlreadyCleanStringArray =\n value.length > 0 && value.every((c) => typeof c === 'string' && c.length > 0 && c === c.trim());\n\n if (isAlreadyCleanStringArray) {\n const arr = value as string[];\n if (!Object.isFrozen(arr)) Object.freeze(arr);\n return arr as readonly string[];\n }\n\n const sanitized = value\n .filter((c): c is string => typeof c === 'string')\n .map((c) => c.trim())\n .filter((c) => c.length > 0);\n\n if (sanitized.length === 0) return undefined;\n Object.freeze(sanitized);\n return sanitized as readonly string[];\n};\n\nconst normalizeCandlestickSampling = (value: unknown): 'none' | 'ohlc' | undefined => {\n if (typeof value !== 'string') return undefined;\n const v = value.trim().toLowerCase();\n return v === 'none' || v === 'ohlc' ? (v as 'none' | 'ohlc') : undefined;\n};\n\nconst normalizeSamplingThreshold = (value: unknown): number | undefined => {\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n const t = Math.floor(value);\n return t > 0 ? t : undefined;\n};\n\nconst normalizeAxisAutoBounds = (value: unknown): AxisConfig['autoBounds'] | undefined => {\n if (typeof value !== 'string') return undefined;\n const v = value.trim().toLowerCase();\n return v === 'global' || v === 'visible' ? (v as AxisConfig['autoBounds']) : undefined;\n};\n\nconst isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst computeRawBoundsFromOHLC = (data: ReadonlyArray<OHLCDataPoint>): RawBounds | undefined => {\n if (data.length === 0) return undefined;\n\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n // Hoist tuple-vs-object detection once (assume homogeneous arrays).\n const isTuple = isTupleOHLCDataPoint(data[0]!);\n\n if (isTuple) {\n // Tuple format path: [timestamp, open, close, low, high]\n const dataAsTuples = data as ReadonlyArray<OHLCDataPointTuple>;\n\n for (let i = 0; i < dataAsTuples.length; i++) {\n const p = dataAsTuples[i]!;\n const x = p[0];\n const low = p[3];\n const high = p[4];\n if (!Number.isFinite(x) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n const yLow = Math.min(low, high);\n const yHigh = Math.max(low, high);\n\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (yLow < yMin) yMin = yLow;\n if (yHigh > yMax) yMax = yHigh;\n }\n } else {\n // Object format path: { timestamp, open, close, low, high }\n const dataAsObjects = data as ReadonlyArray<Exclude<OHLCDataPoint, OHLCDataPointTuple>>;\n\n for (let i = 0; i < dataAsObjects.length; i++) {\n const p = dataAsObjects[i]!;\n const x = p.timestamp;\n const low = p.low;\n const high = p.high;\n if (!Number.isFinite(x) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n const yLow = Math.min(low, high);\n const yHigh = Math.max(low, high);\n\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (yLow < yMin) yMin = yLow;\n if (yHigh > yMax) yMax = yHigh;\n }\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return undefined;\n }\n\n // Keep bounds usable for downstream scale derivation.\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst assertUnreachable = (value: never): never => {\n // Should never happen if SeriesConfig union is exhaustively handled.\n // This is defensive runtime safety for JS callers / invalid inputs.\n throw new Error(\n `Unhandled series type: ${\n (value as unknown as { readonly type?: unknown } | null)?.type ?? 'unknown'\n }`\n );\n};\n\nlet candlestickWarned = false;\nconst warnCandlestickNotImplemented = (): void => {\n if (!candlestickWarned) {\n console.warn(\n 'ChartGPU: Candlestick series rendering is not yet implemented. Series will be skipped.'\n );\n candlestickWarned = true;\n }\n};\n\nexport function resolveOptions(userOptions: ChartGPUOptions = {}): ResolvedChartGPUOptions {\n const baseTheme = resolveTheme(userOptions.theme);\n\n // runtime safety for JS callers\n const autoScrollRaw = (userOptions as unknown as { readonly autoScroll?: unknown }).autoScroll;\n const autoScroll = typeof autoScrollRaw === 'boolean' ? autoScrollRaw : defaultOptions.autoScroll;\n\n // runtime safety for JS callers\n const animationRaw = (userOptions as unknown as { readonly animation?: unknown }).animation;\n const animationCandidate: ChartGPUOptions['animation'] =\n typeof animationRaw === 'boolean' ||\n (animationRaw !== null && typeof animationRaw === 'object' && !Array.isArray(animationRaw))\n ? (animationRaw as ChartGPUOptions['animation'])\n : undefined;\n // Default: animation enabled (with defaults) unless explicitly disabled.\n const animation: ChartGPUOptions['animation'] = animationCandidate ?? true;\n\n // Backward compatibility:\n // - If `userOptions.palette` is provided (non-empty), treat it as an override for the theme palette.\n const paletteOverride = sanitizePalette(userOptions.palette);\n\n const themeCandidate: ThemeConfig =\n paletteOverride.length > 0 ? { ...baseTheme, colorPalette: paletteOverride } : baseTheme;\n\n // Ensure palette used for modulo indexing is never empty.\n const paletteFromTheme = sanitizePalette(themeCandidate.colorPalette);\n const safePalette =\n paletteFromTheme.length > 0\n ? paletteFromTheme\n : sanitizePalette(defaultOptions.palette ?? defaultPalette).length > 0\n ? sanitizePalette(defaultOptions.palette ?? defaultPalette)\n : Array.from(defaultPalette);\n\n const paletteForIndexing = safePalette.length > 0 ? safePalette : ['#000000'];\n const theme: ThemeConfig = { ...themeCandidate, colorPalette: paletteForIndexing.slice() };\n\n const grid: ResolvedGridConfig = {\n left: userOptions.grid?.left ?? defaultOptions.grid.left,\n right: userOptions.grid?.right ?? defaultOptions.grid.right,\n top: userOptions.grid?.top ?? defaultOptions.grid.top,\n bottom: userOptions.grid?.bottom ?? defaultOptions.grid.bottom,\n };\n\n const xAxis: AxisConfig = userOptions.xAxis\n ? {\n ...defaultOptions.xAxis,\n ...userOptions.xAxis,\n // runtime safety for JS callers\n type: (userOptions.xAxis as unknown as Partial<AxisConfig>).type ?? defaultOptions.xAxis.type,\n autoBounds:\n normalizeAxisAutoBounds((userOptions.xAxis as unknown as { readonly autoBounds?: unknown }).autoBounds) ??\n (defaultOptions.xAxis as AxisConfig).autoBounds,\n }\n : { ...defaultOptions.xAxis };\n\n const yAxis: AxisConfig = userOptions.yAxis\n ? {\n ...defaultOptions.yAxis,\n ...userOptions.yAxis,\n // runtime safety for JS callers\n type: (userOptions.yAxis as unknown as Partial<AxisConfig>).type ?? defaultOptions.yAxis.type,\n autoBounds:\n normalizeAxisAutoBounds((userOptions.yAxis as unknown as { readonly autoBounds?: unknown }).autoBounds) ??\n defaultOptions.yAxis.autoBounds,\n }\n : { ...defaultOptions.yAxis };\n\n const series: ReadonlyArray<ResolvedSeriesConfig> = (userOptions.series ?? []).map((s, i) => {\n const explicitColor = normalizeOptionalColor(s.color);\n const inheritedColor = theme.colorPalette[i % theme.colorPalette.length];\n const color = explicitColor ?? inheritedColor;\n\n // Ensure visible defaults to true (converts undefined to true, preserves explicit false)\n const visible = s.visible !== false;\n\n const sampling: SeriesSampling = normalizeSampling((s as unknown as { sampling?: unknown }).sampling) ?? 'lttb';\n const samplingThreshold: number =\n normalizeSamplingThreshold((s as unknown as { samplingThreshold?: unknown }).samplingThreshold) ?? 5000;\n\n switch (s.type) {\n case 'area': {\n // Resolve effective fill color with precedence: areaStyle.color → series.color → palette\n const areaStyleColor = normalizeOptionalColor(s.areaStyle?.color);\n const effectiveColor = areaStyleColor ?? explicitColor ?? inheritedColor;\n\n const areaStyle: ResolvedAreaStyleConfig = {\n opacity: s.areaStyle?.opacity ?? defaultAreaStyle.opacity,\n color: effectiveColor,\n };\n\n const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n return {\n ...s,\n visible,\n rawData: s.data,\n data: sampleSeriesDataPoints(s.data, sampling, samplingThreshold),\n color: effectiveColor,\n areaStyle,\n sampling,\n samplingThreshold,\n rawBounds,\n };\n }\n case 'line': {\n // Resolve effective stroke color with precedence: lineStyle.color → series.color → palette\n const lineStyleColor = normalizeOptionalColor(s.lineStyle?.color);\n const effectiveStrokeColor = lineStyleColor ?? explicitColor ?? inheritedColor;\n\n const lineStyle: ResolvedLineStyleConfig = {\n width: s.lineStyle?.width ?? defaultLineStyle.width,\n opacity: s.lineStyle?.opacity ?? defaultLineStyle.opacity,\n color: effectiveStrokeColor,\n };\n\n // Avoid leaking the unresolved (user) areaStyle shape via object spread.\n const { areaStyle: _userAreaStyle, ...rest } = s;\n const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n const sampledData = sampleSeriesDataPoints(s.data, sampling, samplingThreshold);\n\n return {\n ...rest,\n visible,\n rawData: s.data,\n data: sampledData,\n color: effectiveStrokeColor,\n lineStyle,\n ...(s.areaStyle\n ? {\n areaStyle: {\n opacity: s.areaStyle.opacity ?? defaultAreaStyle.opacity,\n // Fill color precedence: areaStyle.color → resolved stroke color\n color: normalizeOptionalColor(s.areaStyle.color) ?? effectiveStrokeColor,\n },\n }\n : {}),\n sampling,\n samplingThreshold,\n rawBounds,\n };\n }\n case 'bar': {\n const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n return {\n ...s,\n visible,\n rawData: s.data,\n data: sampleSeriesDataPoints(s.data, sampling, samplingThreshold),\n color,\n sampling,\n samplingThreshold,\n rawBounds,\n };\n }\n case 'scatter': {\n const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n const mode =\n normalizeScatterMode((s as unknown as { readonly mode?: unknown }).mode) ?? scatterDefaults.mode;\n const binSize =\n normalizeDensityBinSize((s as unknown as { readonly binSize?: unknown }).binSize) ?? scatterDefaults.binSize;\n const densityColormap =\n normalizeDensityColormap((s as unknown as { readonly densityColormap?: unknown }).densityColormap) ??\n scatterDefaults.densityColormap;\n const densityNormalization =\n normalizeDensityNormalization(\n (s as unknown as { readonly densityNormalization?: unknown }).densityNormalization\n ) ?? scatterDefaults.densityNormalization;\n return {\n ...s,\n visible,\n rawData: s.data,\n data: sampleSeriesDataPoints(s.data, sampling, samplingThreshold),\n color,\n mode,\n binSize,\n densityColormap,\n densityNormalization,\n sampling,\n samplingThreshold,\n rawBounds,\n };\n }\n case 'pie': {\n // Pie series intentionally do NOT support sampling at runtime.\n // For JS callers, strip any extra sampling keys so they don't leak through the resolver.\n const { sampling: _sampling, samplingThreshold: _samplingThreshold, ...rest } = s as PieSeriesConfig & {\n readonly sampling?: unknown;\n readonly samplingThreshold?: unknown;\n };\n\n const resolvedData: ReadonlyArray<ResolvedPieDataItem> = (s.data ?? []).map((item, itemIndex) => {\n const itemColor = normalizeOptionalColor(item?.color);\n const fallback = theme.colorPalette[(i + itemIndex) % theme.colorPalette.length];\n // Ensure visible defaults to true (converts undefined to true, preserves explicit false)\n const itemVisible = item?.visible !== false;\n return {\n ...item,\n color: itemColor ?? fallback,\n visible: itemVisible,\n };\n });\n\n return { ...rest, visible, color, data: resolvedData };\n }\n case 'candlestick': {\n warnCandlestickNotImplemented();\n\n const resolvedSampling: 'none' | 'ohlc' =\n normalizeCandlestickSampling((s as unknown as { sampling?: unknown }).sampling) ??\n candlestickDefaults.sampling;\n\n const resolvedSamplingThreshold: number =\n normalizeSamplingThreshold((s as unknown as { samplingThreshold?: unknown }).samplingThreshold) ??\n candlestickDefaults.samplingThreshold;\n\n const resolvedItemStyle: ResolvedCandlestickItemStyleConfig = {\n upColor: normalizeOptionalColor(s.itemStyle?.upColor) ?? candlestickDefaults.itemStyle.upColor,\n downColor: normalizeOptionalColor(s.itemStyle?.downColor) ?? candlestickDefaults.itemStyle.downColor,\n upBorderColor: normalizeOptionalColor(s.itemStyle?.upBorderColor) ?? candlestickDefaults.itemStyle.upBorderColor,\n downBorderColor: normalizeOptionalColor(s.itemStyle?.downBorderColor) ?? candlestickDefaults.itemStyle.downBorderColor,\n borderWidth: typeof s.itemStyle?.borderWidth === 'number' && Number.isFinite(s.itemStyle.borderWidth)\n ? s.itemStyle.borderWidth\n : candlestickDefaults.itemStyle.borderWidth,\n };\n\n const rawBounds = computeRawBoundsFromOHLC(s.data);\n\n const sampledData =\n resolvedSampling === 'ohlc' && s.data.length > resolvedSamplingThreshold\n ? ohlcSample(s.data, resolvedSamplingThreshold)\n : s.data;\n\n return {\n ...s,\n visible,\n rawData: s.data,\n data: sampledData,\n color,\n style: s.style ?? candlestickDefaults.style,\n itemStyle: resolvedItemStyle,\n barWidth: s.barWidth ?? candlestickDefaults.barWidth,\n barMinWidth: s.barMinWidth ?? candlestickDefaults.barMinWidth,\n barMaxWidth: s.barMaxWidth ?? candlestickDefaults.barMaxWidth,\n sampling: resolvedSampling,\n samplingThreshold: resolvedSamplingThreshold,\n rawBounds,\n };\n }\n default: {\n return assertUnreachable(s);\n }\n }\n });\n\n return {\n grid,\n xAxis,\n yAxis,\n autoScroll,\n dataZoom: sanitizeDataZoom((userOptions as ChartGPUOptions).dataZoom),\n annotations: sanitizeAnnotations((userOptions as ChartGPUOptions).annotations),\n animation,\n theme,\n palette: theme.colorPalette,\n series,\n legend: userOptions.legend,\n };\n}\n\n/**\n * Data zoom slider dimensions (CSS pixels).\n *\n * Note: these are internal implementation details used to reserve chart space for the\n * slider overlay. We intentionally do not re-export them from the public entrypoint.\n */\nconst DATA_ZOOM_SLIDER_HEIGHT_CSS_PX = 32;\nconst DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX = 8;\nconst DATA_ZOOM_SLIDER_RESERVE_CSS_PX =\n DATA_ZOOM_SLIDER_HEIGHT_CSS_PX + DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX;\n\n/**\n * Checks if options include a slider-type dataZoom configuration.\n * \n * @param options - Chart options to check\n * @returns True if slider dataZoom exists\n */\nconst hasSliderDataZoom = (options: ChartGPUOptions): boolean =>\n options.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n\n/**\n * Resolves chart options with slider bottom-space reservation.\n * \n * This function wraps `resolveOptions()` and applies additional grid bottom spacing\n * when a slider-type dataZoom is configured. The reservation ensures x-axis labels\n * and ticks are visible above the slider overlay.\n * \n * **Usage**: Use this function instead of `resolveOptions()` when creating charts\n * to ensure consistent slider layout.\n * \n * @param userOptions - User-provided chart options\n * @returns Resolved options with slider bottom-space applied if needed\n */\nexport function resolveOptionsForChart(userOptions: ChartGPUOptions = {}): ResolvedChartGPUOptions {\n const base: ResolvedChartGPUOptions = { ...resolveOptions(userOptions), tooltip: userOptions.tooltip };\n if (!hasSliderDataZoom(userOptions)) return base;\n return {\n ...base,\n grid: {\n ...base.grid,\n bottom: base.grid.bottom + DATA_ZOOM_SLIDER_RESERVE_CSS_PX,\n },\n };\n}\n\nexport const OptionResolver = { resolve: resolveOptions } as const;\n\n","import type { ZoomRange, ZoomState } from '../interaction/createZoomState';\nimport type { ThemeConfig } from '../themes/types';\n\nexport interface DataZoomSlider {\n update(theme: ThemeConfig): void;\n dispose(): void;\n}\n\nexport interface DataZoomSliderOptions {\n readonly height?: number;\n readonly marginTop?: number;\n readonly zIndex?: number;\n readonly showPreview?: boolean;\n}\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\n\nconst normalizeRange = (range: ZoomRange): ZoomRange => {\n let { start, end } = range;\n if (start > end) {\n const t = start;\n start = end;\n end = t;\n }\n return { start: clamp(start, 0, 100), end: clamp(end, 0, 100) };\n};\n\ntype DragMode = 'left-handle' | 'right-handle' | 'pan-window';\n\nexport function createDataZoomSlider(\n container: HTMLElement,\n zoomState: ZoomState,\n options?: DataZoomSliderOptions\n): DataZoomSlider {\n const height = options?.height ?? 32;\n const marginTop = options?.marginTop ?? 8;\n const zIndex = options?.zIndex ?? 4;\n const showPreview = options?.showPreview ?? false;\n\n const root = document.createElement('div');\n root.style.display = 'block';\n root.style.width = '100%';\n root.style.height = `${height}px`;\n root.style.marginTop = `${marginTop}px`;\n root.style.boxSizing = 'border-box';\n root.style.position = 'relative';\n root.style.zIndex = `${zIndex}`;\n root.style.userSelect = 'none';\n root.style.touchAction = 'none';\n\n // track: full-width bar that hosts preview + window selection.\n const track = document.createElement('div');\n track.style.position = 'relative';\n track.style.height = '100%';\n track.style.width = '100%';\n track.style.boxSizing = 'border-box';\n track.style.borderRadius = '8px';\n track.style.borderStyle = 'solid';\n track.style.borderWidth = '1px';\n track.style.overflow = 'hidden';\n root.appendChild(track);\n\n // preview: miniature context under the selection (optional; can be a solid bar for now).\n const preview = document.createElement('div');\n preview.style.position = 'absolute';\n preview.style.inset = '0';\n preview.style.pointerEvents = 'none';\n preview.style.opacity = '0.4';\n preview.style.display = showPreview ? 'block' : 'none';\n track.appendChild(preview);\n\n // window: the selected range.\n const windowEl = document.createElement('div');\n windowEl.style.position = 'absolute';\n windowEl.style.top = '0';\n windowEl.style.bottom = '0';\n windowEl.style.left = '0%';\n windowEl.style.width = '100%';\n windowEl.style.boxSizing = 'border-box';\n windowEl.style.cursor = 'grab';\n track.appendChild(windowEl);\n\n // left/right handles.\n const leftHandle = document.createElement('div');\n leftHandle.style.position = 'absolute';\n leftHandle.style.left = '0';\n leftHandle.style.top = '0';\n leftHandle.style.bottom = '0';\n leftHandle.style.width = '10px';\n leftHandle.style.cursor = 'ew-resize';\n windowEl.appendChild(leftHandle);\n\n const rightHandle = document.createElement('div');\n rightHandle.style.position = 'absolute';\n rightHandle.style.right = '0';\n rightHandle.style.top = '0';\n rightHandle.style.bottom = '0';\n rightHandle.style.width = '10px';\n rightHandle.style.cursor = 'ew-resize';\n windowEl.appendChild(rightHandle);\n\n // center grip (hit target for panning).\n const centerGrip = document.createElement('div');\n centerGrip.style.position = 'absolute';\n centerGrip.style.left = '10px';\n centerGrip.style.right = '10px';\n centerGrip.style.top = '0';\n centerGrip.style.bottom = '0';\n centerGrip.style.cursor = 'grab';\n windowEl.appendChild(centerGrip);\n\n container.appendChild(root);\n\n let disposed = false;\n let activeDragCleanup: (() => void) | null = null;\n\n const applyRangeToDom = (range: ZoomRange): void => {\n const r = normalizeRange(range);\n const span = clamp(r.end - r.start, 0, 100);\n windowEl.style.left = `${r.start}%`;\n windowEl.style.width = `${span}%`;\n };\n\n const getTrackWidthPx = (): number | null => {\n // getBoundingClientRect() is robust even if the container is scaled.\n const w = track.getBoundingClientRect().width;\n return Number.isFinite(w) && w > 0 ? w : null;\n };\n\n const pxToPercent = (dxPx: number): number | null => {\n const w = getTrackWidthPx();\n if (w === null) return null;\n const p = (dxPx / w) * 100;\n return Number.isFinite(p) ? p : null;\n };\n\n const setPointerCaptureBestEffort = (el: Element, pointerId: number): void => {\n try {\n (el as HTMLElement).setPointerCapture(pointerId);\n } catch {\n // Ignore (best-effort).\n }\n };\n\n const releasePointerCaptureBestEffort = (el: Element, pointerId: number): void => {\n try {\n (el as HTMLElement).releasePointerCapture(pointerId);\n } catch {\n // Ignore (best-effort).\n }\n };\n\n const startDrag = (e: PointerEvent, mode: DragMode): void => {\n if (disposed) return;\n if (e.button !== 0) return;\n\n e.preventDefault();\n\n // If we somehow start a new drag while another is in-flight, clean up first.\n activeDragCleanup?.();\n activeDragCleanup = null;\n\n const dragStartX = e.clientX;\n const startRange = zoomState.getRange();\n\n const target = e.currentTarget instanceof Element ? e.currentTarget : windowEl;\n setPointerCaptureBestEffort(target, e.pointerId);\n\n if (mode === 'pan-window') {\n windowEl.style.cursor = 'grabbing';\n centerGrip.style.cursor = 'grabbing';\n }\n\n const onMove = (ev: PointerEvent): void => {\n if (disposed) return;\n if (ev.pointerId !== e.pointerId) return;\n\n ev.preventDefault();\n\n const dxPercent = pxToPercent(ev.clientX - dragStartX);\n if (dxPercent === null) return;\n\n switch (mode) {\n case 'left-handle': {\n // UX: don't allow handle crossing; clamp left <= current end.\n const nextStart = Math.min(startRange.end, startRange.start + dxPercent);\n const anchored = zoomState as unknown as Partial<{\n setRangeAnchored: (start: number, end: number, anchor: 'start' | 'end' | 'center') => void;\n }>;\n if (anchored.setRangeAnchored) {\n // When clamped by minSpan/maxSpan, keep the right edge anchored (prevents jumpiness).\n anchored.setRangeAnchored(nextStart, startRange.end, 'end');\n } else {\n zoomState.setRange(nextStart, startRange.end);\n }\n return;\n }\n case 'right-handle': {\n // UX: don't allow handle crossing; clamp right >= current start.\n const nextEnd = Math.max(startRange.start, startRange.end + dxPercent);\n const anchored = zoomState as unknown as Partial<{\n setRangeAnchored: (start: number, end: number, anchor: 'start' | 'end' | 'center') => void;\n }>;\n if (anchored.setRangeAnchored) {\n // When clamped by minSpan/maxSpan, keep the left edge anchored (prevents jumpiness).\n anchored.setRangeAnchored(startRange.start, nextEnd, 'start');\n } else {\n zoomState.setRange(startRange.start, nextEnd);\n }\n return;\n }\n case 'pan-window': {\n zoomState.setRange(startRange.start + dxPercent, startRange.end + dxPercent);\n return;\n }\n }\n };\n\n let cleanedUp = false;\n\n const cleanup = (): void => {\n if (cleanedUp) return;\n cleanedUp = true;\n\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', finish);\n window.removeEventListener('pointercancel', finish);\n\n if (mode === 'pan-window') {\n windowEl.style.cursor = 'grab';\n centerGrip.style.cursor = 'grab';\n }\n\n releasePointerCaptureBestEffort(target, e.pointerId);\n\n // Only clear if we're still the active drag.\n if (activeDragCleanup === cleanup) activeDragCleanup = null;\n };\n\n const finish = (ev: PointerEvent): void => {\n if (ev.pointerId !== e.pointerId) return;\n cleanup();\n };\n\n activeDragCleanup = cleanup;\n\n window.addEventListener('pointermove', onMove, { passive: false });\n window.addEventListener('pointerup', finish, { passive: true });\n window.addEventListener('pointercancel', finish, { passive: true });\n };\n\n const onLeftDown = (e: PointerEvent): void => startDrag(e, 'left-handle');\n const onRightDown = (e: PointerEvent): void => startDrag(e, 'right-handle');\n const onPanDown = (e: PointerEvent): void => startDrag(e, 'pan-window');\n\n leftHandle.addEventListener('pointerdown', onLeftDown, { passive: false });\n rightHandle.addEventListener('pointerdown', onRightDown, { passive: false });\n centerGrip.addEventListener('pointerdown', onPanDown, { passive: false });\n\n // Keep DOM in sync with state.\n const unsubscribe = zoomState.onChange((range) => {\n if (disposed) return;\n applyRangeToDom(range);\n });\n\n // Initialize UI.\n applyRangeToDom(zoomState.getRange());\n\n const update: DataZoomSlider['update'] = (theme) => {\n if (disposed) return;\n\n // Baseline track styling.\n track.style.background = theme.backgroundColor;\n track.style.borderColor = theme.axisLineColor;\n\n // Preview styling (placeholder).\n preview.style.background = theme.gridLineColor;\n\n // Window styling.\n windowEl.style.background = theme.gridLineColor;\n windowEl.style.border = `1px solid ${theme.axisTickColor}`;\n windowEl.style.borderRadius = '8px';\n windowEl.style.boxSizing = 'border-box';\n\n // Handles styling.\n const handleBorder = `1px solid ${theme.axisLineColor}`;\n leftHandle.style.background = theme.axisTickColor;\n leftHandle.style.borderRight = handleBorder;\n rightHandle.style.background = theme.axisTickColor;\n rightHandle.style.borderLeft = handleBorder;\n\n // Center grip styling: subtle stripes.\n centerGrip.style.background = 'transparent';\n centerGrip.style.backgroundImage =\n 'linear-gradient(90deg, rgba(255,255,255,0.0) 0, rgba(255,255,255,0.0) 42%, rgba(255,255,255,0.18) 42%, rgba(255,255,255,0.18) 46%, rgba(255,255,255,0.0) 46%, rgba(255,255,255,0.0) 54%, rgba(255,255,255,0.18) 54%, rgba(255,255,255,0.18) 58%, rgba(255,255,255,0.0) 58%, rgba(255,255,255,0.0) 100%)';\n centerGrip.style.mixBlendMode = 'normal';\n };\n\n const dispose: DataZoomSlider['dispose'] = () => {\n if (disposed) return;\n disposed = true;\n\n // If dispose happens during an active drag, ensure we remove all window listeners.\n activeDragCleanup?.();\n activeDragCleanup = null;\n\n try {\n unsubscribe();\n } catch {\n // Best-effort.\n }\n\n leftHandle.removeEventListener('pointerdown', onLeftDown);\n rightHandle.removeEventListener('pointerdown', onRightDown);\n centerGrip.removeEventListener('pointerdown', onPanDown);\n\n root.remove();\n };\n\n return { update, dispose };\n}\n\n","/**\n * WebGPU support detection and validation\n * \n * Provides utilities to check if WebGPU is available and usable in the current environment.\n * Results are memoized to avoid redundant checks.\n */\n\n/**\n * Result of WebGPU support check\n */\nexport interface WebGPUSupportResult {\n /** Whether WebGPU is supported and available */\n readonly supported: boolean;\n /** Optional reason explaining why WebGPU is not supported */\n readonly reason?: string;\n}\n\n// Memoized support check result\nlet cachedSupportCheck: Promise<WebGPUSupportResult> | null = null;\n\n/**\n * Checks if WebGPU is supported and available in the current environment.\n * \n * This function performs comprehensive checks:\n * - SSR-safe: validates that window and navigator are available\n * - Checks for navigator.gpu API presence\n * - Attempts to request a WebGPU adapter to verify actual support\n * - First tries high-performance adapter to match GPUContext behavior\n * - Falls back to default adapter if high-performance fails\n * \n * The result is memoized for performance, so multiple calls return the same promise.\n * \n * @returns Promise resolving to support check result with optional reason\n * \n * @example\n * ```typescript\n * const { supported, reason } = await checkWebGPUSupport();\n * if (!supported) {\n * console.error('WebGPU not available:', reason);\n * }\n * ```\n */\nexport async function checkWebGPUSupport(): Promise<WebGPUSupportResult> {\n // Return cached result if available\n if (cachedSupportCheck) {\n return cachedSupportCheck;\n }\n\n // Create and cache the promise\n cachedSupportCheck = (async (): Promise<WebGPUSupportResult> => {\n // SSR-safe checks: ensure we're in a browser environment\n if (typeof window === 'undefined') {\n return {\n supported: false,\n reason: 'Not running in a browser environment (window is undefined).',\n };\n }\n\n if (typeof navigator === 'undefined') {\n return {\n supported: false,\n reason: 'Navigator is not available in this environment.',\n };\n }\n\n // Check for navigator.gpu API\n if (!navigator.gpu) {\n return {\n supported: false,\n reason: 'WebGPU API (navigator.gpu) is not available. Your browser does not support WebGPU.',\n };\n }\n\n // Attempt to request an adapter to verify actual support\n try {\n // First attempt: high-performance adapter (aligns with GPUContext behavior)\n let adapter = await navigator.gpu.requestAdapter({\n powerPreference: 'high-performance',\n });\n\n // Second attempt: default adapter if high-performance is unavailable\n if (!adapter) {\n adapter = await navigator.gpu.requestAdapter();\n }\n\n // If both attempts fail, WebGPU is not usable\n if (!adapter) {\n return {\n supported: false,\n reason: 'No compatible WebGPU adapter found. This may occur if: (1) no GPU is available, (2) GPU drivers are outdated or incompatible, (3) running in a VM or headless environment, or (4) WebGPU is disabled in browser settings.',\n };\n }\n\n // Success: WebGPU is supported and an adapter is available\n return { supported: true };\n } catch (error) {\n // Adapter request threw an error\n let reason = 'Failed to request WebGPU adapter.';\n\n // Try to extract useful error information\n if (error instanceof DOMException) {\n reason = `Failed to request WebGPU adapter: ${error.name}`;\n if (error.message) {\n reason += ` - ${error.message}`;\n }\n } else if (error instanceof Error) {\n reason = `Failed to request WebGPU adapter: ${error.message}`;\n } else {\n reason = `Failed to request WebGPU adapter: ${String(error)}`;\n }\n\n return { supported: false, reason };\n }\n })();\n\n return cachedSupportCheck;\n}\n","import { GPUContext } from './core/GPUContext';\nimport { createRenderCoordinator } from './core/createRenderCoordinator';\nimport type { RenderCoordinator } from './core/createRenderCoordinator';\nimport { resolveOptionsForChart } from './config/OptionResolver';\nimport type { ResolvedCandlestickSeriesConfig, ResolvedChartGPUOptions, ResolvedPieSeriesConfig } from './config/OptionResolver';\nimport type {\n CartesianSeriesData,\n ChartGPUOptions,\n DataPoint,\n DataPointTuple,\n OHLCDataPoint,\n OHLCDataPointTuple,\n PieCenter,\n PieRadius,\n} from './config/types';\nimport { createDataZoomSlider } from './components/createDataZoomSlider';\nimport type { DataZoomSlider } from './components/createDataZoomSlider';\nimport type { ZoomRange, ZoomState } from './interaction/createZoomState';\nimport { computeCandlestickBodyWidthRange, findCandlestick } from './interaction/findCandlestick';\nimport { findNearestPoint } from './interaction/findNearestPoint';\nimport type { NearestPointMatch } from './interaction/findNearestPoint';\nimport { findPieSlice } from './interaction/findPieSlice';\nimport { createLinearScale } from './utils/scales';\nimport type { LinearScale } from './utils/scales';\nimport { checkWebGPUSupport } from './utils/checkWebGPU';\nimport type {\n PerformanceMetrics,\n PerformanceCapabilities,\n ExactFPS,\n Milliseconds,\n Bytes,\n FrameTimeStats,\n GPUTimingStats,\n MemoryStats,\n FrameDropStats,\n} from './config/types';\nimport {\n computeRawBoundsFromCartesianData,\n getPointCount as getCartesianPointCount,\n getSize as getCartesianSize,\n getX as getCartesianX,\n getY as getCartesianY,\n} from './data/cartesianData';\n\n/**\n * Circular buffer size for frame timestamps (120 frames = 2 seconds at 60fps).\n */\nconst FRAME_BUFFER_SIZE = 120;\n\n/**\n * Expected frame time at 60fps (16.67ms).\n */\nconst EXPECTED_FRAME_TIME_MS = 1000 / 60;\n\n/**\n * Frame drop threshold multiplier (1.5x expected frame time).\n */\nconst FRAME_DROP_THRESHOLD_MULTIPLIER = 1.5;\n\n/**\n * Hit-test match for a chart element.\n */\nexport type ChartGPUHitTestMatch = Readonly<{\n readonly kind: 'cartesian' | 'candlestick' | 'pie';\n readonly seriesIndex: number;\n readonly dataIndex: number;\n readonly value: readonly [number, number];\n}>;\n\n/**\n * Result of a hit-test operation on a chart.\n */\nexport type ChartGPUHitTestResult = Readonly<{\n readonly isInGrid: boolean;\n readonly canvasX: number;\n readonly canvasY: number;\n readonly gridX: number;\n readonly gridY: number;\n readonly match: ChartGPUHitTestMatch | null;\n}>;\n\nexport interface ChartGPUInstance {\n readonly options: Readonly<ChartGPUOptions>;\n readonly disposed: boolean;\n setOption(options: ChartGPUOptions): void;\n /**\n * Appends new points to a cartesian series at runtime (streaming).\n *\n * For candlestick series, pass `OHLCDataPoint[]`.\n * For other cartesian series (line, area, bar, scatter), pass `DataPoint[]`.\n * Pie series are non-cartesian and are not supported by streaming append.\n */\n appendData(seriesIndex: number, newPoints: DataPoint[] | OHLCDataPoint[]): void;\n resize(): void;\n dispose(): void;\n on(eventName: 'crosshairMove', callback: ChartGPUCrosshairMoveCallback): void;\n on(eventName: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n off(eventName: 'crosshairMove', callback: ChartGPUCrosshairMoveCallback): void;\n off(eventName: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n /**\n * Gets the current “interaction x” in domain units (or `null` when inactive).\n *\n * This is derived from pointer movement inside the plot grid and can also be driven\n * externally via `setInteractionX(...)` (e.g. chart sync).\n */\n getInteractionX(): number | null;\n /**\n * Drives the chart’s crosshair + tooltip from a domain-space x value.\n *\n * Passing `null` clears the interaction (hides crosshair/tooltip).\n */\n setInteractionX(x: number | null, source?: unknown): void;\n /**\n * Alias for `setInteractionX(...)` for chart sync semantics.\n */\n setCrosshairX(x: number | null, source?: unknown): void;\n /**\n * Subscribes to interaction x changes (domain units).\n *\n * Returns an unsubscribe function.\n */\n onInteractionXChange(callback: (x: number | null, source?: unknown) => void): () => void;\n /**\n * Returns the current percent-space zoom window (or `null` when zoom is disabled).\n */\n getZoomRange(): Readonly<{ start: number; end: number }> | null;\n /**\n * Sets the percent-space zoom window.\n *\n * No-op when zoom is disabled.\n */\n setZoomRange(start: number, end: number): void;\n /**\n * Gets the latest performance metrics.\n * Returns exact FPS and detailed frame statistics.\n * \n * @returns Current performance metrics, or null if not available\n */\n getPerformanceMetrics(): Readonly<PerformanceMetrics> | null;\n /**\n * Gets the performance capabilities of the current environment.\n * Indicates which performance features are supported.\n * \n * @returns Performance capabilities, or null if not initialized\n */\n getPerformanceCapabilities(): Readonly<PerformanceCapabilities> | null;\n /**\n * Registers a callback to be notified of performance metric updates.\n * Callback is invoked every frame with the latest metrics.\n * \n * @param callback - Function to call with updated metrics\n * @returns Unsubscribe function to remove the callback\n */\n onPerformanceUpdate(callback: (metrics: Readonly<PerformanceMetrics>) => void): () => void;\n /**\n * Performs hit-testing on a pointer or mouse event.\n *\n * Returns coordinates and matched chart element (if any).\n * Accepts both `PointerEvent` (for hover/click) and `MouseEvent` (for contextmenu/right-click).\n *\n * @param e - Pointer or mouse event to test\n * @returns Hit-test result with coordinates and optional match\n */\n hitTest(e: PointerEvent | MouseEvent): ChartGPUHitTestResult;\n}\n\n// Type-only alias so callsites can write `ChartGPU[]` for chart instances (while `ChartGPU` the value\n// remains the creation API exported from `src/index.ts`).\nexport type ChartGPU = ChartGPUInstance;\n\nexport type ChartGPUEventName = 'click' | 'mouseover' | 'mouseout' | 'crosshairMove';\n\nexport type ChartGPUEventPayload = Readonly<{\n readonly seriesIndex: number | null;\n readonly dataIndex: number | null;\n readonly value: readonly [number, number] | null;\n readonly seriesName: string | null;\n readonly event: PointerEvent;\n}>;\n\nexport type ChartGPUCrosshairMovePayload = Readonly<{\n readonly x: number | null;\n readonly source?: unknown;\n}>;\n\nexport type ChartGPUEventCallback = (payload: ChartGPUEventPayload) => void;\n\nexport type ChartGPUCrosshairMoveCallback = (payload: ChartGPUCrosshairMovePayload) => void;\n\ntype AnyChartGPUEventCallback = ChartGPUEventCallback | ChartGPUCrosshairMoveCallback;\n\ntype ListenerRegistry = Readonly<Record<ChartGPUEventName, Set<AnyChartGPUEventCallback>>>;\n\ntype TapCandidate = {\n readonly pointerId: number;\n readonly startClientX: number;\n readonly startClientY: number;\n readonly startTimeMs: number;\n};\n\nconst DEFAULT_TAP_MAX_DISTANCE_CSS_PX = 6;\nconst DEFAULT_TAP_MAX_TIME_MS = 500;\n\ntype Bounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\nconst isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n return { x: p.x, y: p.y };\n};\n\nconst cartesianDataToDataPointArray = (data: CartesianSeriesData): DataPoint[] => {\n // Clone DataPoint[] so we can mutate for streaming appends without touching user input.\n if (Array.isArray(data)) return data.length === 0 ? [] : (data.slice() as DataPoint[]);\n\n const n = getCartesianPointCount(data);\n if (n === 0) return [];\n\n const out: DataPoint[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const x = getCartesianX(data, i);\n const y = getCartesianY(data, i);\n const size = getCartesianSize(data, i);\n out[i] = (size === undefined ? [x, y] : [x, y, size]) as DataPointTuple;\n }\n return out;\n};\n\nconst getOHLCTimestamp = (p: OHLCDataPoint): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\nconst getOHLCClose = (p: OHLCDataPoint): number => (isTupleOHLCDataPoint(p) ? p[2] : p.close);\n\nconst hasSliderDataZoom = (options: ChartGPUOptions): boolean => options.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\n\ntype InteractionScalesCache = {\n rectWidthCss: number;\n rectHeightCss: number;\n plotWidthCss: number;\n plotHeightCss: number;\n xDomainMin: number;\n xDomainMax: number;\n yDomainMin: number;\n yDomainMax: number;\n xScale: LinearScale;\n yScale: LinearScale;\n};\n\nconst computeRawBoundsFromData = (data: ReadonlyArray<DataPoint>): Bounds | null => {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < data.length; i++) {\n const { x, y } = getPointXY(data[i]!);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return null;\n }\n\n // Keep bounds usable for downstream scale derivation.\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst extendBoundsWithDataPoints = (bounds: Bounds | null, points: ReadonlyArray<DataPoint>): Bounds | null => {\n if (points.length === 0) return bounds;\n\n let b = bounds;\n if (!b) {\n const seeded = computeRawBoundsFromData(points);\n if (!seeded) return bounds;\n b = seeded;\n }\n\n let xMin = b.xMin;\n let xMax = b.xMax;\n let yMin = b.yMin;\n let yMax = b.yMax;\n\n for (let i = 0; i < points.length; i++) {\n const { x, y } = getPointXY(points[i]!);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n if (x < xMin) xMin = x;\n if (x > xMax) xMax = x;\n if (y < yMin) yMin = y;\n if (y > yMax) yMax = y;\n }\n\n // Keep bounds usable for downstream scale derivation.\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst extendBoundsWithOHLCDataPoints = (bounds: Bounds | null, points: ReadonlyArray<OHLCDataPoint>): Bounds | null => {\n if (points.length === 0) return bounds;\n\n let xMin = bounds?.xMin ?? Number.POSITIVE_INFINITY;\n let xMax = bounds?.xMax ?? Number.NEGATIVE_INFINITY;\n let yMin = bounds?.yMin ?? Number.POSITIVE_INFINITY;\n let yMax = bounds?.yMax ?? Number.NEGATIVE_INFINITY;\n\n for (let i = 0; i < points.length; i++) {\n const p = points[i]!;\n const timestamp = getOHLCTimestamp(p);\n const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n\n if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n if (timestamp < xMin) xMin = timestamp;\n if (timestamp > xMax) xMax = timestamp;\n if (low < yMin) yMin = low;\n if (high > yMax) yMax = high;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return bounds;\n }\n\n // Keep bounds usable for downstream scale derivation.\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst computeGlobalBounds = (\n series: ResolvedChartGPUOptions['series'],\n runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null\n): Bounds => {\n let xMin = Number.POSITIVE_INFINITY;\n let xMax = Number.NEGATIVE_INFINITY;\n let yMin = Number.POSITIVE_INFINITY;\n let yMax = Number.NEGATIVE_INFINITY;\n\n for (let s = 0; s < series.length; s++) {\n const seriesConfig = series[s]!;\n // Pie series are non-cartesian; they don't participate in x/y bounds.\n if (seriesConfig.type === 'pie') continue;\n\n // Prefer the chart-owned runtime bounds (kept up to date by appendData()).\n const runtimeBoundsCandidate = runtimeRawBoundsByIndex?.[s] ?? null;\n if (runtimeBoundsCandidate) {\n const b = runtimeBoundsCandidate;\n if (\n Number.isFinite(b.xMin) &&\n Number.isFinite(b.xMax) &&\n Number.isFinite(b.yMin) &&\n Number.isFinite(b.yMax)\n ) {\n if (b.xMin < xMin) xMin = b.xMin;\n if (b.xMax > xMax) xMax = b.xMax;\n if (b.yMin < yMin) yMin = b.yMin;\n if (b.yMax > yMax) yMax = b.yMax;\n continue;\n }\n }\n\n // Prefer resolver-provided bounds when available (avoids O(n) scans on initial setOption()).\n // (Resolved series types include `rawBounds` for cartesian series; keep this defensive.)\n const rawBoundsCandidate = (seriesConfig as unknown as { rawBounds?: Bounds | null }).rawBounds ?? null;\n if (rawBoundsCandidate) {\n const b = rawBoundsCandidate;\n if (\n Number.isFinite(b.xMin) &&\n Number.isFinite(b.xMax) &&\n Number.isFinite(b.yMin) &&\n Number.isFinite(b.yMax)\n ) {\n if (b.xMin < xMin) xMin = b.xMin;\n if (b.xMax > xMax) xMax = b.xMax;\n if (b.yMin < yMin) yMin = b.yMin;\n if (b.yMax > yMax) yMax = b.yMax;\n continue;\n }\n }\n\n if (seriesConfig.type === 'candlestick') {\n // Fallback scan when resolver-provided bounds aren't present.\n const data = seriesConfig.data as ReadonlyArray<OHLCDataPoint>;\n for (let i = 0; i < data.length; i++) {\n const p = data[i]!;\n const timestamp = getOHLCTimestamp(p);\n const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n\n if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n if (timestamp < xMin) xMin = timestamp;\n if (timestamp > xMax) xMax = timestamp;\n if (low < yMin) yMin = low;\n if (high > yMax) yMax = high;\n }\n continue;\n }\n\n const b = computeRawBoundsFromCartesianData(seriesConfig.data as CartesianSeriesData);\n if (!b) continue;\n if (b.xMin < xMin) xMin = b.xMin;\n if (b.xMax > xMax) xMax = b.xMax;\n if (b.yMin < yMin) yMin = b.yMin;\n if (b.yMax > yMax) yMax = b.yMax;\n }\n\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n }\n\n if (xMin === xMax) xMax = xMin + 1;\n if (yMin === yMax) yMax = yMin + 1;\n\n return { xMin, xMax, yMin, yMax };\n};\n\nconst normalizeDomain = (\n minCandidate: number,\n maxCandidate: number\n): { readonly min: number; readonly max: number } => {\n let min = minCandidate;\n let max = maxCandidate;\n\n if (!Number.isFinite(min) || !Number.isFinite(max)) {\n min = 0;\n max = 1;\n }\n\n if (min === max) {\n max = min + 1;\n } else if (min > max) {\n const t = min;\n min = max;\n max = t;\n }\n\n return { min, max };\n};\n\ntype CartesianHitTestMatch = Readonly<{\n kind: 'cartesian';\n match: NearestPointMatch;\n}>;\n\ntype PieHitTestMatch = Readonly<{\n kind: 'pie';\n seriesIndex: number;\n dataIndex: number;\n sliceValue: number;\n}>;\n\ntype CandlestickHitTestMatch = Readonly<{\n kind: 'candlestick';\n seriesIndex: number;\n dataIndex: number;\n point: OHLCDataPoint;\n}>;\n\ntype HitTestMatch = CartesianHitTestMatch | PieHitTestMatch | CandlestickHitTestMatch;\n\nconst parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (typeof value !== 'string') return null;\n\n const s = value.trim();\n if (s.length === 0) return null;\n\n if (s.endsWith('%')) {\n const pct = Number.parseFloat(s.slice(0, -1));\n if (!Number.isFinite(pct)) return null;\n return (pct / 100) * basis;\n }\n\n // Be permissive: allow numeric strings like \"120\" even though the public type primarily documents percent strings.\n const n = Number.parseFloat(s);\n return Number.isFinite(n) ? n : null;\n};\n\nconst resolvePieCenterPlotCss = (\n center: PieCenter | undefined,\n plotWidthCss: number,\n plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n const xRaw = center?.[0] ?? '50%';\n const yRaw = center?.[1] ?? '50%';\n\n const x = parseNumberOrPercent(xRaw, plotWidthCss);\n const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n return {\n x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n };\n};\n\nconst isPieRadiusTuple = (radius: PieRadius): radius is readonly [inner: number | string, outer: number | string] =>\n Array.isArray(radius);\n\nconst resolvePieRadiiCss = (\n radius: PieRadius | undefined,\n maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n // Default similar to common chart libs (mirrors `createPieRenderer.ts` and coordinator helpers).\n if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n if (isPieRadiusTuple(radius)) {\n const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n }\n\n const outer = parseNumberOrPercent(radius, maxRadiusCss);\n const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\nexport async function createChartGPU(\n container: HTMLElement,\n options: ChartGPUOptions\n): Promise<ChartGPUInstance> {\n // Check WebGPU support before creating canvas or any resources\n const supportCheck = await checkWebGPUSupport();\n if (!supportCheck.supported) {\n const reason = supportCheck.reason || 'Unknown reason';\n throw new Error(\n `ChartGPU: WebGPU is not available.\\n` +\n `Reason: ${reason}\\n` +\n `Browser support: Chrome/Edge 113+, Safari 18+, Firefox not yet supported.\\n` +\n `Resources:\\n` +\n ` - MDN WebGPU API: https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API\\n` +\n ` - Browser compatibility: https://caniuse.com/webgpu\\n` +\n ` - WebGPU specification: https://www.w3.org/TR/webgpu/\\n` +\n ` - Check your system: https://webgpureport.org/`\n );\n }\n\n const canvas = document.createElement('canvas');\n\n // Ensure the canvas participates in layout and can size via the container.\n canvas.style.display = 'block';\n canvas.style.width = '100%';\n canvas.style.height = '100%';\n\n // Append before awaiting so it appears immediately and has measurable size.\n container.appendChild(canvas);\n\n let disposed = false;\n let gpuContext: GPUContext | null = null;\n let coordinator: RenderCoordinator | null = null;\n let coordinatorTargetFormat: GPUTextureFormat | null = null;\n let unsubscribeCoordinatorInteractionXChange: (() => void) | null = null;\n\n let dataZoomSliderHost: HTMLDivElement | null = null;\n let dataZoomSlider: DataZoomSlider | null = null;\n\n let currentOptions: ChartGPUOptions = options;\n let resolvedOptions: ResolvedChartGPUOptions = resolveOptionsForChart(currentOptions);\n\n // Chart-owned runtime series store for hit-testing only (cartesian only).\n // - `runtimeRawDataByIndex[i]` is a mutable array used to reflect streaming appends.\n // - `runtimeRawBoundsByIndex[i]` is incrementally updated to keep scale/bounds derivation cheap.\n let runtimeRawDataByIndex: Array<DataPoint[] | OHLCDataPoint[]> = new Array(resolvedOptions.series.length).fill(null).map(() => []);\n let runtimeRawBoundsByIndex: Array<Bounds | null> = new Array(resolvedOptions.series.length).fill(null);\n let runtimeHitTestSeriesCache: ResolvedChartGPUOptions['series'] | null = null;\n let runtimeHitTestSeriesVersion = 0;\n\n const initRuntimeHitTestStoreFromResolvedOptions = (): void => {\n runtimeRawDataByIndex = new Array(resolvedOptions.series.length).fill(null).map(() => []);\n runtimeRawBoundsByIndex = new Array(resolvedOptions.series.length).fill(null);\n runtimeHitTestSeriesCache = null;\n runtimeHitTestSeriesVersion++;\n\n for (let i = 0; i < resolvedOptions.series.length; i++) {\n const s = resolvedOptions.series[i]!;\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n const raw = ((s as unknown as { rawData?: ReadonlyArray<OHLCDataPoint> }).rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>;\n runtimeRawDataByIndex[i] = raw.length === 0 ? [] : raw.slice();\n runtimeRawBoundsByIndex[i] = ((s as unknown as { rawBounds?: Bounds | null }).rawBounds ?? null);\n } else {\n const raw = ((s as unknown as { rawData?: CartesianSeriesData }).rawData ?? s.data) as CartesianSeriesData;\n runtimeRawDataByIndex[i] = cartesianDataToDataPointArray(raw);\n runtimeRawBoundsByIndex[i] =\n ((s as unknown as { rawBounds?: Bounds | null }).rawBounds ?? null) ?? (computeRawBoundsFromCartesianData(raw) as Bounds | null);\n }\n }\n };\n\n const getRuntimeHitTestSeries = (): ResolvedChartGPUOptions['series'] => {\n if (runtimeHitTestSeriesCache) return runtimeHitTestSeriesCache;\n // Replace cartesian series `data` with chart-owned runtime data (pie series are unchanged).\n runtimeHitTestSeriesCache = resolvedOptions.series.map((s, i) => {\n if (s.type === 'pie') return s;\n if (s.type === 'candlestick') {\n return { ...s, data: runtimeRawDataByIndex[i] ?? (s.data as ReadonlyArray<OHLCDataPoint>) };\n }\n return { ...s, data: runtimeRawDataByIndex[i] ?? (s.data as ReadonlyArray<DataPoint>) };\n }) as ResolvedChartGPUOptions['series'];\n return runtimeHitTestSeriesCache;\n };\n\n initRuntimeHitTestStoreFromResolvedOptions();\n\n // Cache global bounds and interaction scales; avoids O(N) data scans per pointer move.\n let cachedGlobalBounds: Bounds = computeGlobalBounds(resolvedOptions.series, runtimeRawBoundsByIndex);\n let interactionScalesCache: InteractionScalesCache | null = null;\n\n const listeners: ListenerRegistry = {\n click: new Set<ChartGPUEventCallback>(),\n mouseover: new Set<ChartGPUEventCallback>(),\n mouseout: new Set<ChartGPUEventCallback>(),\n crosshairMove: new Set<ChartGPUCrosshairMoveCallback>(),\n };\n\n let tapCandidate: TapCandidate | null = null;\n let suppressNextLostPointerCaptureId: number | null = null;\n\n let hovered: HitTestMatch | null = null;\n\n // Prevent spamming console.warn for repeated misuse.\n const warnedPieAppendSeries = new Set<number>();\n\n let scheduledRaf: number | null = null;\n let lastConfigured: { width: number; height: number; format: GPUTextureFormat } | null = null;\n let isDirty = true;\n\n // Performance tracking state\n const frameTimestamps = new Float64Array(FRAME_BUFFER_SIZE);\n let frameTimestampIndex = 0;\n let frameTimestampCount = 0;\n let totalFrames = 0;\n let totalDroppedFrames = 0;\n let consecutiveDroppedFrames = 0;\n let lastDropTimestamp = 0;\n const startTime = performance.now();\n let lastFrameTime = 0;\n let lastCPUTime = 0;\n const performanceUpdateCallbacks = new Set<(metrics: Readonly<PerformanceMetrics>) => void>();\n\n const hasHoverListeners = (): boolean => listeners.mouseover.size > 0 || listeners.mouseout.size > 0;\n const hasClickListeners = (): boolean => listeners.click.size > 0;\n\n const cancelPendingFrame = (): void => {\n if (scheduledRaf === null) return;\n cancelAnimationFrame(scheduledRaf);\n scheduledRaf = null;\n };\n\n const requestRender = (): void => {\n if (disposed) return;\n isDirty = true;\n if (scheduledRaf !== null) return;\n\n scheduledRaf = requestAnimationFrame(() => {\n scheduledRaf = null;\n if (disposed) return;\n\n // Record frame timestamp BEFORE rendering\n const frameStartTime = performance.now();\n frameTimestamps[frameTimestampIndex] = frameStartTime;\n frameTimestampIndex = (frameTimestampIndex + 1) % FRAME_BUFFER_SIZE;\n if (frameTimestampCount < FRAME_BUFFER_SIZE) {\n frameTimestampCount++;\n }\n totalFrames++;\n\n // Frame drop detection (only after first frame)\n if (lastFrameTime > 0) {\n const deltaTime = frameStartTime - lastFrameTime;\n if (deltaTime > EXPECTED_FRAME_TIME_MS * FRAME_DROP_THRESHOLD_MULTIPLIER) {\n totalDroppedFrames++;\n consecutiveDroppedFrames++;\n lastDropTimestamp = frameStartTime;\n } else {\n // Reset consecutive counter on successful frame\n consecutiveDroppedFrames = 0;\n }\n }\n lastFrameTime = frameStartTime;\n\n // Requirement: on RAF tick, call resize() first.\n resizeInternal(false);\n \n if (isDirty) {\n isDirty = false;\n coordinator?.render();\n }\n\n const frameEndTime = performance.now();\n lastCPUTime = frameEndTime - frameStartTime;\n\n // Calculate and emit performance metrics\n const metrics = calculatePerformanceMetrics();\n for (const callback of performanceUpdateCallbacks) {\n try {\n callback(metrics);\n } catch (error) {\n console.error('Error in performance update callback:', error);\n }\n }\n });\n };\n\n const unbindCoordinatorInteractionXChange = (): void => {\n if (!unsubscribeCoordinatorInteractionXChange) return;\n try {\n unsubscribeCoordinatorInteractionXChange();\n } finally {\n unsubscribeCoordinatorInteractionXChange = null;\n }\n };\n\n const disposeDataZoomSlider = (): void => {\n dataZoomSlider?.dispose();\n dataZoomSlider = null;\n };\n\n const disposeDataZoomSliderHost = (): void => {\n dataZoomSliderHost?.remove();\n dataZoomSliderHost = null;\n };\n\n const disposeDataZoomUi = (): void => {\n disposeDataZoomSlider();\n disposeDataZoomSliderHost();\n };\n\n const DATA_ZOOM_SLIDER_HEIGHT_CSS_PX = 32;\n const DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX = 8;\n const DATA_ZOOM_SLIDER_RESERVE_CSS_PX = DATA_ZOOM_SLIDER_HEIGHT_CSS_PX + DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX;\n\n const ensureDataZoomSliderHost = (): HTMLDivElement => {\n if (dataZoomSliderHost) return dataZoomSliderHost;\n\n // Ensure the host's absolute positioning is anchored to the chart container.\n // If the container is already positioned, avoid overwriting user styles.\n try {\n const pos = window.getComputedStyle(container).position;\n if (pos === 'static') container.style.position = 'relative';\n } catch {\n // best-effort\n }\n\n const host = document.createElement('div');\n host.style.position = 'absolute';\n host.style.left = '0';\n host.style.right = '0';\n host.style.bottom = '0';\n host.style.height = `${DATA_ZOOM_SLIDER_RESERVE_CSS_PX}px`;\n host.style.paddingTop = `${DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX}px`;\n host.style.boxSizing = 'border-box';\n host.style.pointerEvents = 'auto';\n host.style.zIndex = '5';\n container.appendChild(host);\n dataZoomSliderHost = host;\n return host;\n };\n\n const computeZoomInOutAnchorRatio = (range: ZoomRange, center: number): number => {\n const span = range.end - range.start;\n if (!Number.isFinite(span) || span === 0) return 0.5;\n return clamp((center - range.start) / span, 0, 1);\n };\n\n const createCoordinatorZoomStateLike = (): ZoomState => {\n const getRange: ZoomState['getRange'] = () => coordinator?.getZoomRange() ?? { start: 0, end: 100 };\n const setRange: ZoomState['setRange'] = (start, end) => {\n coordinator?.setZoomRange(start, end);\n };\n const zoomIn: ZoomState['zoomIn'] = (center, factor) => {\n if (!Number.isFinite(center) || !Number.isFinite(factor) || factor <= 1) return;\n const r = coordinator?.getZoomRange();\n if (!r) return;\n const c = clamp(center, 0, 100);\n const ratio = computeZoomInOutAnchorRatio(r, c);\n const span = r.end - r.start;\n const nextSpan = span / factor;\n const nextStart = c - ratio * nextSpan;\n coordinator?.setZoomRange(nextStart, nextStart + nextSpan);\n };\n const zoomOut: ZoomState['zoomOut'] = (center, factor) => {\n if (!Number.isFinite(center) || !Number.isFinite(factor) || factor <= 1) return;\n const r = coordinator?.getZoomRange();\n if (!r) return;\n const c = clamp(center, 0, 100);\n const ratio = computeZoomInOutAnchorRatio(r, c);\n const span = r.end - r.start;\n const nextSpan = span * factor;\n const nextStart = c - ratio * nextSpan;\n coordinator?.setZoomRange(nextStart, nextStart + nextSpan);\n };\n const pan: ZoomState['pan'] = (delta) => {\n if (!Number.isFinite(delta)) return;\n const r = coordinator?.getZoomRange();\n if (!r) return;\n coordinator?.setZoomRange(r.start + delta, r.end + delta);\n };\n const onChange: ZoomState['onChange'] = (callback) => coordinator?.onZoomRangeChange(callback) ?? (() => {});\n\n return { getRange, setRange, zoomIn, zoomOut, pan, onChange };\n };\n\n const syncDataZoomUi = (): void => {\n const shouldHaveSlider = hasSliderDataZoom(currentOptions);\n if (!shouldHaveSlider) {\n disposeDataZoomUi();\n return;\n }\n\n // Slider requires a coordinator-backed zoom state.\n if (!coordinator) return;\n if (!coordinator.getZoomRange()) return;\n\n const host = ensureDataZoomSliderHost();\n if (!dataZoomSlider) {\n dataZoomSlider = createDataZoomSlider(host, createCoordinatorZoomStateLike(), {\n height: DATA_ZOOM_SLIDER_HEIGHT_CSS_PX,\n marginTop: 0, // host provides vertical spacing\n });\n }\n dataZoomSlider.update(resolvedOptions.theme);\n };\n\n const bindCoordinatorInteractionXChange = (): void => {\n unbindCoordinatorInteractionXChange();\n if (disposed) return;\n if (!coordinator) return;\n\n unsubscribeCoordinatorInteractionXChange = coordinator.onInteractionXChange((x, source) => {\n emit('crosshairMove', { x, source });\n });\n };\n\n const recreateCoordinator = (): void => {\n if (disposed) return;\n if (!gpuContext || !gpuContext.initialized) return;\n\n const prevZoomRange = coordinator?.getZoomRange() ?? null;\n\n unbindCoordinatorInteractionXChange();\n // Coordinator recreation invalidates zoom subscriptions; recreate the slider if present.\n disposeDataZoomSlider();\n coordinator?.dispose();\n coordinator = createRenderCoordinator(gpuContext, resolvedOptions, { onRequestRender: requestRender });\n coordinatorTargetFormat = gpuContext.preferredFormat;\n bindCoordinatorInteractionXChange();\n\n if (prevZoomRange) coordinator.setZoomRange(prevZoomRange.start, prevZoomRange.end);\n syncDataZoomUi();\n };\n\n const resizeInternal = (shouldRequestRenderAfterChanges: boolean): void => {\n if (disposed) return;\n\n const rect = canvas.getBoundingClientRect();\n const dpr = window.devicePixelRatio || 1;\n\n const maxDimension = gpuContext?.device?.limits.maxTextureDimension2D ?? 8192;\n const width = Math.min(maxDimension, Math.max(1, Math.round(rect.width * dpr)));\n const height = Math.min(maxDimension, Math.max(1, Math.round(rect.height * dpr)));\n\n const sizeChanged = canvas.width !== width || canvas.height !== height;\n if (sizeChanged) {\n canvas.width = width;\n canvas.height = height;\n }\n\n const device = gpuContext?.device;\n const canvasContext = gpuContext?.canvasContext;\n const preferredFormat = gpuContext?.preferredFormat;\n\n let didConfigure = false;\n if (device && canvasContext && preferredFormat) {\n const shouldConfigure =\n sizeChanged ||\n !lastConfigured ||\n lastConfigured.width !== canvas.width ||\n lastConfigured.height !== canvas.height ||\n lastConfigured.format !== preferredFormat;\n\n if (shouldConfigure) {\n canvasContext.configure({\n device,\n format: preferredFormat,\n alphaMode: 'opaque',\n });\n lastConfigured = { width: canvas.width, height: canvas.height, format: preferredFormat };\n didConfigure = true;\n\n // Requirement: if the target format changes, recreate coordinator/pipelines.\n if (coordinator && coordinatorTargetFormat !== preferredFormat) {\n recreateCoordinator();\n }\n }\n }\n\n if (shouldRequestRenderAfterChanges && (sizeChanged || didConfigure)) {\n // Requirement: resize() requests a render after size/config changes.\n requestRender();\n }\n };\n\n const resize = (): void => resizeInternal(true);\n\n const getNearestPointFromPointerEvent = (\n e: PointerEvent\n ): { readonly match: HitTestMatch | null; readonly isInGrid: boolean } => {\n const rect = canvas.getBoundingClientRect();\n if (!(rect.width > 0) || !(rect.height > 0)) return { match: null, isInGrid: false };\n\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n const plotLeftCss = resolvedOptions.grid.left;\n const plotTopCss = resolvedOptions.grid.top;\n const plotWidthCss = rect.width - resolvedOptions.grid.left - resolvedOptions.grid.right;\n const plotHeightCss = rect.height - resolvedOptions.grid.top - resolvedOptions.grid.bottom;\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return { match: null, isInGrid: false };\n\n const gridX = x - plotLeftCss;\n const gridY = y - plotTopCss;\n\n const isInGrid =\n gridX >= 0 &&\n gridX <= plotWidthCss &&\n gridY >= 0 &&\n gridY <= plotHeightCss;\n\n if (!isInGrid) return { match: null, isInGrid: false };\n\n const xMin = resolvedOptions.xAxis.min ?? cachedGlobalBounds.xMin;\n const xMax = resolvedOptions.xAxis.max ?? cachedGlobalBounds.xMax;\n const yMin = resolvedOptions.yAxis.min ?? cachedGlobalBounds.yMin;\n const yMax = resolvedOptions.yAxis.max ?? cachedGlobalBounds.yMax;\n\n // Make hit-testing zoom-aware (mirror coordinator percent->domain mapping).\n const baseXDomain = normalizeDomain(xMin, xMax);\n const zoomRange = coordinator?.getZoomRange() ?? null;\n const xDomain = (() => {\n if (!zoomRange) return baseXDomain;\n const span = baseXDomain.max - baseXDomain.min;\n if (!Number.isFinite(span) || span === 0) return baseXDomain;\n const start = zoomRange.start;\n const end = zoomRange.end;\n const zMin = baseXDomain.min + (start / 100) * span;\n const zMax = baseXDomain.min + (end / 100) * span;\n return normalizeDomain(zMin, zMax);\n })();\n const yDomain = normalizeDomain(yMin, yMax);\n\n // Cache hit-testing scales for identical (rect, grid, axis domain) inputs.\n const canReuseScales =\n interactionScalesCache !== null &&\n interactionScalesCache.rectWidthCss === rect.width &&\n interactionScalesCache.rectHeightCss === rect.height &&\n interactionScalesCache.plotWidthCss === plotWidthCss &&\n interactionScalesCache.plotHeightCss === plotHeightCss &&\n interactionScalesCache.xDomainMin === xDomain.min &&\n interactionScalesCache.xDomainMax === xDomain.max &&\n interactionScalesCache.yDomainMin === yDomain.min &&\n interactionScalesCache.yDomainMax === yDomain.max;\n\n if (!canReuseScales) {\n // IMPORTANT: grid-local CSS px ranges (0..plotWidth/Height), for interaction hit-testing.\n const xScale = createLinearScale().domain(xDomain.min, xDomain.max).range(0, plotWidthCss);\n const yScale = createLinearScale().domain(yDomain.min, yDomain.max).range(plotHeightCss, 0);\n interactionScalesCache = {\n rectWidthCss: rect.width,\n rectHeightCss: rect.height,\n plotWidthCss,\n plotHeightCss,\n xDomainMin: xDomain.min,\n xDomainMax: xDomain.max,\n yDomainMin: yDomain.min,\n yDomainMax: yDomain.max,\n xScale,\n yScale,\n };\n }\n\n // At this point, the cache must exist (either reused or created above).\n const scales = interactionScalesCache!;\n\n // Story 4.14: pie slice hit-testing (grid-local CSS px).\n const pieMatch = (() => {\n const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n if (!(maxRadiusCss > 0)) return null;\n\n // Prefer later series indices (deterministic and mirrors the coordinator tooltip logic).\n for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n const s = resolvedOptions.series[i];\n if (s.type !== 'pie') continue;\n\n // Skip invisible series.\n if (s.visible === false) continue;\n\n const pieSeries = s as ResolvedPieSeriesConfig;\n const center = resolvePieCenterPlotCss(pieSeries.center, plotWidthCss, plotHeightCss);\n const radii = resolvePieRadiiCss(pieSeries.radius, maxRadiusCss);\n const m = findPieSlice(gridX, gridY, { seriesIndex: i, series: pieSeries }, center, radii);\n if (!m) continue;\n\n const v = m.slice.value;\n return {\n kind: 'pie' as const,\n seriesIndex: m.seriesIndex,\n dataIndex: m.dataIndex,\n sliceValue: typeof v === 'number' && Number.isFinite(v) ? v : 0,\n };\n }\n return null;\n })();\n\n if (pieMatch) return { match: pieMatch, isInGrid: true };\n\n // Candlestick body hit-testing (grid-local CSS px), prefer later series indices.\n for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n const s = resolvedOptions.series[i];\n if (s?.type !== 'candlestick') continue;\n\n // Skip invisible series.\n if (s.visible === false) continue;\n\n const seriesCfg = s as ResolvedCandlestickSeriesConfig;\n const barWidthRange = computeCandlestickBodyWidthRange(seriesCfg, seriesCfg.data, scales.xScale, plotWidthCss);\n const m = findCandlestick([seriesCfg], gridX, gridY, scales.xScale, scales.yScale, barWidthRange);\n if (!m) continue;\n\n return {\n match: { kind: 'candlestick', seriesIndex: i, dataIndex: m.dataIndex, point: m.point },\n isInGrid: true,\n };\n }\n\n const cartesianMatch = findNearestPoint(\n getRuntimeHitTestSeries(),\n gridX,\n gridY,\n scales.xScale,\n scales.yScale\n );\n\n return {\n match: cartesianMatch ? ({ kind: 'cartesian', match: cartesianMatch } as const) : null,\n isInGrid: true,\n };\n };\n\n const calculateExactFPS = (): ExactFPS => {\n if (frameTimestampCount < 2) {\n return 0 as ExactFPS;\n }\n\n const startIndex = (frameTimestampIndex - frameTimestampCount + FRAME_BUFFER_SIZE) % FRAME_BUFFER_SIZE;\n \n let totalDelta = 0;\n for (let i = 1; i < frameTimestampCount; i++) {\n const prevIndex = (startIndex + i - 1) % FRAME_BUFFER_SIZE;\n const currIndex = (startIndex + i) % FRAME_BUFFER_SIZE;\n const delta = frameTimestamps[currIndex] - frameTimestamps[prevIndex];\n totalDelta += delta;\n }\n\n const avgFrameTime = totalDelta / (frameTimestampCount - 1);\n const fps = avgFrameTime > 0 ? 1000 / avgFrameTime : 0;\n \n return fps as ExactFPS;\n };\n\n const calculateFrameTimeStats = (): FrameTimeStats => {\n if (frameTimestampCount < 2) {\n return {\n min: 0 as Milliseconds,\n max: 0 as Milliseconds,\n avg: 0 as Milliseconds,\n p50: 0 as Milliseconds,\n p95: 0 as Milliseconds,\n p99: 0 as Milliseconds,\n };\n }\n\n const startIndex = (frameTimestampIndex - frameTimestampCount + FRAME_BUFFER_SIZE) % FRAME_BUFFER_SIZE;\n \n const deltas = new Array<number>(frameTimestampCount - 1);\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n let sum = 0;\n \n for (let i = 1; i < frameTimestampCount; i++) {\n const prevIndex = (startIndex + i - 1) % FRAME_BUFFER_SIZE;\n const currIndex = (startIndex + i) % FRAME_BUFFER_SIZE;\n const delta = frameTimestamps[currIndex] - frameTimestamps[prevIndex];\n deltas[i - 1] = delta;\n \n if (delta < min) min = delta;\n if (delta > max) max = delta;\n sum += delta;\n }\n\n const avg = sum / deltas.length;\n\n // Sort for percentile calculations\n deltas.sort((a, b) => a - b);\n\n const p50Index = Math.floor(deltas.length * 0.50);\n const p95Index = Math.floor(deltas.length * 0.95);\n const p99Index = Math.floor(deltas.length * 0.99);\n\n return {\n min: min as Milliseconds,\n max: max as Milliseconds,\n avg: avg as Milliseconds,\n p50: deltas[p50Index] as Milliseconds,\n p95: deltas[p95Index] as Milliseconds,\n p99: deltas[p99Index] as Milliseconds,\n };\n };\n\n const calculatePerformanceMetrics = (): PerformanceMetrics => {\n const fps = calculateExactFPS();\n const frameTimeStats = calculateFrameTimeStats();\n \n const gpuTiming: GPUTimingStats = {\n enabled: false, // GPU timing not yet implemented for main thread\n cpuTime: lastCPUTime as Milliseconds,\n gpuTime: 0 as Milliseconds,\n };\n \n const memory: MemoryStats = {\n used: 0 as Bytes,\n peak: 0 as Bytes,\n allocated: 0 as Bytes,\n };\n \n const frameDrops: FrameDropStats = {\n totalDrops: totalDroppedFrames,\n consecutiveDrops: consecutiveDroppedFrames,\n lastDropTimestamp: lastDropTimestamp as Milliseconds,\n };\n \n const elapsedTime = performance.now() - startTime;\n \n return {\n fps,\n frameTimeStats,\n gpuTiming,\n memory,\n frameDrops,\n totalFrames,\n elapsedTime: elapsedTime as Milliseconds,\n };\n };\n\n const buildPayload = (match: HitTestMatch | null, event: PointerEvent): ChartGPUEventPayload => {\n if (!match) {\n return { seriesIndex: null, dataIndex: null, value: null, seriesName: null, event };\n }\n\n const seriesIndex = match.kind === 'cartesian' ? match.match.seriesIndex : match.seriesIndex;\n const dataIndex = match.kind === 'cartesian' ? match.match.dataIndex : match.dataIndex;\n\n const series = resolvedOptions.series[seriesIndex];\n const seriesNameRaw = series?.name ?? null;\n const seriesName = seriesNameRaw && seriesNameRaw.trim().length > 0 ? seriesNameRaw : null;\n\n if (match.kind === 'pie') {\n // Pie series are non-cartesian; expose slice value in y so consumers can read a numeric.\n return {\n seriesIndex,\n dataIndex,\n value: [0, match.sliceValue],\n seriesName,\n event,\n };\n }\n\n if (match.kind === 'candlestick') {\n const timestamp = getOHLCTimestamp(match.point);\n const close = getOHLCClose(match.point);\n return {\n seriesIndex,\n dataIndex,\n value: [timestamp, close],\n seriesName,\n event,\n };\n }\n\n const { x, y } = getPointXY(match.match.point);\n return {\n seriesIndex,\n dataIndex,\n value: [x, y],\n seriesName,\n event,\n };\n };\n\n const emit = (\n eventName: ChartGPUEventName,\n payload: ChartGPUEventPayload | ChartGPUCrosshairMovePayload\n ): void => {\n if (disposed) return;\n for (const cb of listeners[eventName]) (cb as (p: typeof payload) => void)(payload);\n };\n\n const setHovered = (next: HitTestMatch | null, event: PointerEvent): void => {\n const prev = hovered;\n hovered = next;\n\n if (prev === null && next === null) return;\n\n if (prev === null && next !== null) {\n emit('mouseover', buildPayload(next, event));\n return;\n }\n\n if (prev !== null && next === null) {\n emit('mouseout', buildPayload(prev, event));\n return;\n }\n\n if (prev === null || next === null) return;\n\n const prevSeriesIndex = prev.kind === 'cartesian' ? prev.match.seriesIndex : prev.seriesIndex;\n const prevDataIndex = prev.kind === 'cartesian' ? prev.match.dataIndex : prev.dataIndex;\n const nextSeriesIndex = next.kind === 'cartesian' ? next.match.seriesIndex : next.seriesIndex;\n const nextDataIndex = next.kind === 'cartesian' ? next.match.dataIndex : next.dataIndex;\n\n const samePoint = prevSeriesIndex === nextSeriesIndex && prevDataIndex === nextDataIndex;\n if (samePoint) return;\n\n emit('mouseout', buildPayload(prev, event));\n emit('mouseover', buildPayload(next, event));\n };\n\n const clearTapCandidateIfMatches = (e: PointerEvent): void => {\n if (!tapCandidate) return;\n if (!e.isPrimary) return;\n if (e.pointerId !== tapCandidate.pointerId) return;\n tapCandidate = null;\n };\n\n const onPointerMove = (e: PointerEvent): void => {\n if (disposed) return;\n if (!hasHoverListeners()) return;\n const { match, isInGrid } = getNearestPointFromPointerEvent(e);\n if (!isInGrid) {\n setHovered(null, e);\n return;\n }\n setHovered(match, e);\n };\n\n const onPointerLeave = (e: PointerEvent): void => {\n if (disposed) return;\n if (!hasHoverListeners() && !tapCandidate) return;\n clearTapCandidateIfMatches(e);\n setHovered(null, e);\n };\n\n const onPointerCancel = (e: PointerEvent): void => {\n if (disposed) return;\n if (!hasHoverListeners() && !tapCandidate) return;\n clearTapCandidateIfMatches(e);\n setHovered(null, e);\n };\n\n const onLostPointerCapture = (e: PointerEvent): void => {\n if (disposed) return;\n if (!hasHoverListeners() && !tapCandidate && suppressNextLostPointerCaptureId !== e.pointerId) return;\n if (suppressNextLostPointerCaptureId === e.pointerId) {\n suppressNextLostPointerCaptureId = null;\n return;\n }\n clearTapCandidateIfMatches(e);\n setHovered(null, e);\n };\n\n const onPointerDown = (e: PointerEvent): void => {\n if (disposed) return;\n if (!hasClickListeners()) return;\n if (!e.isPrimary) return;\n\n // For mouse, only allow left button.\n if (e.pointerType === 'mouse' && e.button !== 0) return;\n\n tapCandidate = {\n pointerId: e.pointerId,\n startClientX: e.clientX,\n startClientY: e.clientY,\n startTimeMs: e.timeStamp,\n };\n\n // Optional pointer capture improves reliability for touch/pen.\n try {\n canvas.setPointerCapture(e.pointerId);\n } catch {\n // best-effort\n }\n };\n\n const onPointerUp = (e: PointerEvent): void => {\n if (disposed) return;\n if (!hasClickListeners()) return;\n if (!e.isPrimary) return;\n if (!tapCandidate || e.pointerId !== tapCandidate.pointerId) return;\n\n const dt = e.timeStamp - tapCandidate.startTimeMs;\n const dx = e.clientX - tapCandidate.startClientX;\n const dy = e.clientY - tapCandidate.startClientY;\n const distSq = dx * dx + dy * dy;\n\n tapCandidate = null;\n\n // Release capture if we have it; suppress the resulting lostpointercapture.\n try {\n if (canvas.hasPointerCapture(e.pointerId)) {\n suppressNextLostPointerCaptureId = e.pointerId;\n canvas.releasePointerCapture(e.pointerId);\n }\n } catch {\n // best-effort\n }\n\n const maxDist = DEFAULT_TAP_MAX_DISTANCE_CSS_PX;\n const isTap = dt <= DEFAULT_TAP_MAX_TIME_MS && distSq <= maxDist * maxDist;\n if (!isTap) return;\n\n const { match } = getNearestPointFromPointerEvent(e);\n emit('click', buildPayload(match, e));\n };\n\n canvas.addEventListener('pointermove', onPointerMove, { passive: true });\n canvas.addEventListener('pointerleave', onPointerLeave, { passive: true });\n canvas.addEventListener('pointercancel', onPointerCancel, { passive: true });\n canvas.addEventListener('lostpointercapture', onLostPointerCapture, { passive: true });\n canvas.addEventListener('pointerdown', onPointerDown, { passive: true });\n canvas.addEventListener('pointerup', onPointerUp, { passive: true });\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n\n try {\n // Requirement: dispose order: cancel RAF, coordinator.dispose(), gpuContext.destroy(), remove canvas.\n cancelPendingFrame();\n disposeDataZoomUi();\n unbindCoordinatorInteractionXChange();\n coordinator?.dispose();\n coordinator = null;\n coordinatorTargetFormat = null;\n gpuContext?.destroy();\n } finally {\n tapCandidate = null;\n suppressNextLostPointerCaptureId = null;\n hovered = null;\n interactionScalesCache = null;\n\n canvas.removeEventListener('pointermove', onPointerMove);\n canvas.removeEventListener('pointerleave', onPointerLeave);\n canvas.removeEventListener('pointercancel', onPointerCancel);\n canvas.removeEventListener('lostpointercapture', onLostPointerCapture);\n canvas.removeEventListener('pointerdown', onPointerDown);\n canvas.removeEventListener('pointerup', onPointerUp);\n\n listeners.click.clear();\n listeners.mouseover.clear();\n listeners.mouseout.clear();\n listeners.crosshairMove.clear();\n\n gpuContext = null;\n canvas.remove();\n }\n };\n\n const instance: ChartGPUInstance = {\n get options() {\n return currentOptions;\n },\n get disposed() {\n return disposed;\n },\n setOption(nextOptions) {\n if (disposed) return;\n currentOptions = nextOptions;\n resolvedOptions = resolveOptionsForChart(nextOptions);\n coordinator?.setOptions(resolvedOptions);\n initRuntimeHitTestStoreFromResolvedOptions();\n cachedGlobalBounds = computeGlobalBounds(resolvedOptions.series, runtimeRawBoundsByIndex);\n interactionScalesCache = null;\n syncDataZoomUi();\n\n // Requirement: setOption triggers a render (and thus series parsing/extent/scales update inside render).\n requestRender();\n },\n appendData(seriesIndex, newPoints) {\n if (disposed) return;\n if (!Number.isFinite(seriesIndex)) return;\n if (seriesIndex < 0 || seriesIndex >= resolvedOptions.series.length) return;\n if (!newPoints || newPoints.length === 0) return;\n\n const s = resolvedOptions.series[seriesIndex]!;\n if (s.type === 'pie') {\n // Pie series are non-cartesian and currently not supported by streaming append.\n if (!warnedPieAppendSeries.has(seriesIndex)) {\n warnedPieAppendSeries.add(seriesIndex);\n console.warn(\n `ChartGPU.appendData(${seriesIndex}, ...): pie series are not supported by streaming append. Use setOption(...) to replace pie data.`\n );\n }\n return;\n }\n\n // Forward to coordinator (GPU buffers + render-state updates), then keep ChartGPU's\n // hit-testing runtime store in sync.\n coordinator?.appendData(seriesIndex, newPoints);\n\n if (s.type === 'candlestick') {\n // Handle candlestick series with OHLC data points.\n const owned = (runtimeRawDataByIndex[seriesIndex] ?? []) as OHLCDataPoint[];\n owned.push(...(newPoints as OHLCDataPoint[]));\n runtimeRawDataByIndex[seriesIndex] = owned;\n\n runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithOHLCDataPoints(\n runtimeRawBoundsByIndex[seriesIndex],\n newPoints as OHLCDataPoint[]\n );\n } else {\n // Handle other cartesian series (line, area, bar, scatter).\n const owned = (runtimeRawDataByIndex[seriesIndex] ?? []) as DataPoint[];\n owned.push(...(newPoints as DataPoint[]));\n runtimeRawDataByIndex[seriesIndex] = owned;\n\n runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithDataPoints(\n runtimeRawBoundsByIndex[seriesIndex],\n newPoints as DataPoint[]\n );\n }\n\n cachedGlobalBounds = computeGlobalBounds(resolvedOptions.series, runtimeRawBoundsByIndex);\n\n runtimeHitTestSeriesCache = null;\n runtimeHitTestSeriesVersion++;\n interactionScalesCache = null;\n\n // Ensure a render is scheduled (coalesced) like setOption does.\n requestRender();\n },\n resize,\n dispose,\n on(eventName, callback) {\n if (disposed) return;\n listeners[eventName].add(callback as AnyChartGPUEventCallback);\n },\n off(eventName, callback) {\n listeners[eventName].delete(callback as AnyChartGPUEventCallback);\n },\n getInteractionX() {\n if (disposed) return null;\n return coordinator?.getInteractionX() ?? null;\n },\n setInteractionX(x, source) {\n if (disposed) return;\n coordinator?.setInteractionX(x, source);\n },\n setCrosshairX(x, source) {\n if (disposed) return;\n coordinator?.setInteractionX(x, source);\n },\n onInteractionXChange(callback) {\n if (disposed) return () => {};\n return coordinator?.onInteractionXChange(callback) ?? (() => {});\n },\n getZoomRange() {\n if (disposed) return null;\n return coordinator?.getZoomRange() ?? null;\n },\n setZoomRange(start, end) {\n if (disposed) return;\n coordinator?.setZoomRange(start, end);\n },\n getPerformanceMetrics() {\n if (disposed) return null;\n return calculatePerformanceMetrics();\n },\n getPerformanceCapabilities() {\n if (disposed) return null;\n return {\n gpuTimingSupported: false, // Not yet implemented for main thread\n highResTimerSupported: typeof performance !== 'undefined' && typeof performance.now === 'function',\n performanceMetricsSupported: true,\n };\n },\n onPerformanceUpdate(callback) {\n if (disposed) return () => {};\n performanceUpdateCallbacks.add(callback);\n return () => {\n performanceUpdateCallbacks.delete(callback);\n };\n },\n hitTest(e) {\n const rect = canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n // Default result for cases where rect is invalid or disposed\n if (disposed || !(rect.width > 0) || !(rect.height > 0)) {\n return {\n isInGrid: false,\n canvasX,\n canvasY,\n gridX: 0,\n gridY: 0,\n match: null,\n };\n }\n\n const plotLeftCss = resolvedOptions.grid.left;\n const plotTopCss = resolvedOptions.grid.top;\n const plotWidthCss = rect.width - resolvedOptions.grid.left - resolvedOptions.grid.right;\n const plotHeightCss = rect.height - resolvedOptions.grid.top - resolvedOptions.grid.bottom;\n\n const gridX = canvasX - plotLeftCss;\n const gridY = canvasY - plotTopCss;\n\n // If plot dimensions are invalid, return coords but no match\n if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) {\n return {\n isInGrid: false,\n canvasX,\n canvasY,\n gridX,\n gridY,\n match: null,\n };\n }\n\n const isInGrid =\n gridX >= 0 &&\n gridX <= plotWidthCss &&\n gridY >= 0 &&\n gridY <= plotHeightCss;\n\n // If outside grid, return early\n if (!isInGrid) {\n return {\n isInGrid: false,\n canvasX,\n canvasY,\n gridX,\n gridY,\n match: null,\n };\n }\n\n // Compute domain and scales for hit-testing\n const xMin = resolvedOptions.xAxis.min ?? cachedGlobalBounds.xMin;\n const xMax = resolvedOptions.xAxis.max ?? cachedGlobalBounds.xMax;\n const yMin = resolvedOptions.yAxis.min ?? cachedGlobalBounds.yMin;\n const yMax = resolvedOptions.yAxis.max ?? cachedGlobalBounds.yMax;\n\n const baseXDomain = normalizeDomain(xMin, xMax);\n const zoomRange = coordinator?.getZoomRange() ?? null;\n const xDomain = (() => {\n if (!zoomRange) return baseXDomain;\n const span = baseXDomain.max - baseXDomain.min;\n if (!Number.isFinite(span) || span === 0) return baseXDomain;\n const start = zoomRange.start;\n const end = zoomRange.end;\n const zMin = baseXDomain.min + (start / 100) * span;\n const zMax = baseXDomain.min + (end / 100) * span;\n return normalizeDomain(zMin, zMax);\n })();\n const yDomain = normalizeDomain(yMin, yMax);\n\n // Reuse or rebuild interaction scales cache\n const canReuseScales =\n interactionScalesCache !== null &&\n interactionScalesCache.rectWidthCss === rect.width &&\n interactionScalesCache.rectHeightCss === rect.height &&\n interactionScalesCache.plotWidthCss === plotWidthCss &&\n interactionScalesCache.plotHeightCss === plotHeightCss &&\n interactionScalesCache.xDomainMin === xDomain.min &&\n interactionScalesCache.xDomainMax === xDomain.max &&\n interactionScalesCache.yDomainMin === yDomain.min &&\n interactionScalesCache.yDomainMax === yDomain.max;\n\n if (!canReuseScales) {\n const xScale = createLinearScale().domain(xDomain.min, xDomain.max).range(0, plotWidthCss);\n const yScale = createLinearScale().domain(yDomain.min, yDomain.max).range(plotHeightCss, 0);\n interactionScalesCache = {\n rectWidthCss: rect.width,\n rectHeightCss: rect.height,\n plotWidthCss,\n plotHeightCss,\n xDomainMin: xDomain.min,\n xDomainMax: xDomain.max,\n yDomainMin: yDomain.min,\n yDomainMax: yDomain.max,\n xScale,\n yScale,\n };\n }\n\n const scales = interactionScalesCache!;\n\n // Pie slice hit-testing\n const pieMatch = (() => {\n const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n if (!(maxRadiusCss > 0)) return null;\n\n for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n const s = resolvedOptions.series[i];\n if (s.type !== 'pie') continue;\n const pieSeries = s as ResolvedPieSeriesConfig;\n const center = resolvePieCenterPlotCss(pieSeries.center, plotWidthCss, plotHeightCss);\n const radii = resolvePieRadiiCss(pieSeries.radius, maxRadiusCss);\n const m = findPieSlice(gridX, gridY, { seriesIndex: i, series: pieSeries }, center, radii);\n if (!m) continue;\n\n const v = m.slice.value;\n return {\n kind: 'pie' as const,\n seriesIndex: m.seriesIndex,\n dataIndex: m.dataIndex,\n sliceValue: typeof v === 'number' && Number.isFinite(v) ? v : 0,\n };\n }\n return null;\n })();\n\n if (pieMatch) {\n return {\n isInGrid: true,\n canvasX,\n canvasY,\n gridX,\n gridY,\n match: {\n kind: 'pie',\n seriesIndex: pieMatch.seriesIndex,\n dataIndex: pieMatch.dataIndex,\n value: [0, pieMatch.sliceValue],\n },\n };\n }\n\n // Candlestick body hit-testing\n for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n const s = resolvedOptions.series[i];\n if (s?.type !== 'candlestick') continue;\n\n const seriesCfg = s as ResolvedCandlestickSeriesConfig;\n const barWidthRange = computeCandlestickBodyWidthRange(seriesCfg, seriesCfg.data, scales.xScale, plotWidthCss);\n const m = findCandlestick([seriesCfg], gridX, gridY, scales.xScale, scales.yScale, barWidthRange);\n if (!m) continue;\n\n const timestamp = getOHLCTimestamp(m.point);\n const close = getOHLCClose(m.point);\n\n return {\n isInGrid: true,\n canvasX,\n canvasY,\n gridX,\n gridY,\n match: {\n kind: 'candlestick',\n seriesIndex: i,\n dataIndex: m.dataIndex,\n value: [timestamp, close],\n },\n };\n }\n\n // Cartesian nearest-point hit-testing\n const cartesianMatch = findNearestPoint(\n getRuntimeHitTestSeries(),\n gridX,\n gridY,\n scales.xScale,\n scales.yScale\n );\n\n if (cartesianMatch) {\n const { x, y } = getPointXY(cartesianMatch.point);\n return {\n isInGrid: true,\n canvasX,\n canvasY,\n gridX,\n gridY,\n match: {\n kind: 'cartesian',\n seriesIndex: cartesianMatch.seriesIndex,\n dataIndex: cartesianMatch.dataIndex,\n value: [x, y],\n },\n };\n }\n\n // Inside grid but no match\n return {\n isInGrid: true,\n canvasX,\n canvasY,\n gridX,\n gridY,\n match: null,\n };\n },\n };\n\n try {\n // Establish initial canvas backing size before WebGPU initialization.\n resizeInternal(false);\n\n // Try to create GPU context; wrap errors with detailed WebGPU unavailability message\n try {\n gpuContext = await GPUContext.create(canvas);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `ChartGPU: WebGPU is not available.\\n` +\n `Reason: ${errorMessage}\\n` +\n `Browser support: Chrome/Edge 113+, Safari 18+, Firefox not yet supported.\\n` +\n `Resources:\\n` +\n ` - MDN WebGPU API: https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API\\n` +\n ` - Browser compatibility: https://caniuse.com/webgpu\\n` +\n ` - WebGPU specification: https://www.w3.org/TR/webgpu/\\n` +\n ` - Check your system: https://webgpureport.org/`\n );\n }\n\n gpuContext.device?.lost.then((info) => {\n if (disposed) return;\n if (info.reason !== 'destroyed') {\n console.warn('WebGPU device lost:', info);\n }\n // Requirement: device loss routes through the same dispose path.\n dispose();\n });\n\n // Ensure canvas configuration matches the final measured size/format.\n resizeInternal(false);\n\n // Requirement: after GPUContext is initialized, create RenderCoordinator with resolved options.\n recreateCoordinator();\n\n // Mount data-zoom UI (if configured).\n syncDataZoomUi();\n\n // Kick an initial render.\n requestRender();\n return instance;\n } catch (error) {\n instance.dispose();\n throw error;\n }\n}\n\nexport const ChartGPU = {\n create: createChartGPU,\n};\n\n","import type { ChartGPU, ChartGPUCrosshairMovePayload } from '../ChartGPU';\n\nexport type DisconnectCharts = () => void;\n\n/**\n * Connects multiple charts so pointer movement in one chart drives crosshair/tooltip x\n * in the other charts (domain x sync). Returns a `disconnect()` function.\n *\n * Notes:\n * - Syncs interaction only (crosshair + tooltip x), not zoom/options.\n * - Uses a per-connection loop guard to prevent feedback.\n */\nexport function connectCharts(charts: ChartGPU[]): DisconnectCharts {\n const connectionToken = Symbol('ChartGPU.connectCharts');\n\n let disconnected = false;\n const unsubscribeFns: Array<() => void> = [];\n\n const broadcast = (sourceChart: ChartGPU, x: number | null): void => {\n for (const chart of charts) {\n if (chart === sourceChart) continue;\n if (chart.disposed) continue;\n chart.setCrosshairX(x, connectionToken);\n }\n };\n\n for (const chart of charts) {\n if (chart.disposed) continue;\n\n const onCrosshairMove = (payload: ChartGPUCrosshairMovePayload): void => {\n if (disconnected) return;\n if (payload.source === connectionToken) return;\n if (chart.disposed) return;\n broadcast(chart, payload.x);\n };\n\n chart.on('crosshairMove', onCrosshairMove);\n const unsub = (): void => chart.off('crosshairMove', onCrosshairMove);\n unsubscribeFns.push(unsub);\n }\n\n return () => {\n if (disconnected) return;\n disconnected = true;\n\n for (const unsub of unsubscribeFns) unsub();\n unsubscribeFns.length = 0;\n\n // Clear any “stuck” remote interactions.\n for (const chart of charts) {\n if (chart.disposed) continue;\n chart.setCrosshairX(null, connectionToken);\n }\n };\n}\n\n","/**\n * Hit testing for chart annotations\n *\n * Detects which annotation (if any) the user clicked or hovered over.\n * Uses canvas-space coordinates and configurable hit tolerances.\n */\n\nimport type { AnnotationConfig, DataPoint } from '../config/types.js';\nimport type { ChartGPUInstance } from '../ChartGPU.js';\n\nexport interface AnnotationHitTestResult {\n readonly annotationIndex: number;\n readonly annotation: AnnotationConfig;\n readonly hitType: 'line' | 'text' | 'point' | 'label';\n readonly distanceCssPx: number;\n}\n\nexport interface AnnotationHitTesterOptions {\n readonly lineTolerance?: number; // Default: 20px\n readonly textTolerance?: number; // Default: 8px\n readonly pointTolerance?: number; // Default: 16px\n readonly labelTolerance?: number; // Default: 2px\n readonly spatialGridThreshold?: number; // Default: 20 annotations\n}\n\nexport interface AnnotationHitTester {\n hitTest(canvasX: number, canvasY: number): AnnotationHitTestResult | null;\n updateTextBounds(textBounds: Map<number, DOMRect>): void;\n invalidateCache(): void;\n dispose(): void;\n}\n\ninterface CachedAnnotationBounds {\n canvasX?: number;\n canvasY?: number;\n width?: number;\n height?: number;\n}\n\n/**\n * Creates an annotation hit tester for detecting pointer interactions\n */\nexport function createAnnotationHitTester(\n chart: ChartGPUInstance,\n canvas: HTMLCanvasElement,\n options: AnnotationHitTesterOptions = {}\n): AnnotationHitTester {\n const lineTolerance = options.lineTolerance ?? 20;\n const textTolerance = options.textTolerance ?? 8;\n const pointTolerance = options.pointTolerance ?? 16;\n // labelTolerance reserved for future use\n // spatialGridThreshold reserved for future optimization when >20 annotations\n\n // Cache for annotation bounds in canvas-space\n let boundsCache = new Map<number, CachedAnnotationBounds>();\n let textBoundsCache = new Map<number, DOMRect>();\n let cacheValid = false;\n\n // Type guards for data points\n const isTupleDataPoint = (p: any): p is [number, number] => Array.isArray(p);\n const isTupleOHLCDataPoint = (p: any): p is [number, number, number, number, number] => Array.isArray(p);\n const getPointX = (p: any): number => (isTupleDataPoint(p) ? p[0] : p.x);\n const getPointY = (p: any): number => (isTupleDataPoint(p) ? p[1] : p.y);\n const getOHLCTimestamp = (p: any): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\n const getOHLCHigh = (p: any): number => (isTupleOHLCDataPoint(p) ? p[2] : p.high);\n const getOHLCLow = (p: any): number => (isTupleOHLCDataPoint(p) ? p[3] : p.low);\n\n /**\n * Compute the actual X domain from series data (with zoom applied)\n */\n function computeXDomain(): { min: number; max: number } {\n const opts = chart.options;\n let xMin = opts.xAxis?.min;\n let xMax = opts.xAxis?.max;\n\n // If not explicitly set, derive from series data\n if (xMin === undefined || xMax === undefined) {\n const series = opts.series ?? [];\n let dataXMin = Number.POSITIVE_INFINITY;\n let dataXMax = Number.NEGATIVE_INFINITY;\n\n for (const s of series) {\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n const data = s.data;\n for (const p of data) {\n const timestamp = getOHLCTimestamp(p);\n if (timestamp < dataXMin) dataXMin = timestamp;\n if (timestamp > dataXMax) dataXMax = timestamp;\n }\n } else {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = s.data as ReadonlyArray<DataPoint>;\n for (const p of data) {\n const x = getPointX(p);\n if (x < dataXMin) dataXMin = x;\n if (x > dataXMax) dataXMax = x;\n }\n }\n }\n\n if (xMin === undefined) xMin = Number.isFinite(dataXMin) ? dataXMin : 0;\n if (xMax === undefined) xMax = Number.isFinite(dataXMax) ? dataXMax : 100;\n }\n\n // Apply zoom if present\n const zoomRange = chart.getZoomRange();\n if (zoomRange) {\n const span = xMax - xMin;\n const zoomMin = xMin + (zoomRange.start / 100) * span;\n const zoomMax = xMin + (zoomRange.end / 100) * span;\n return { min: zoomMin, max: zoomMax };\n }\n\n return { min: xMin, max: xMax };\n }\n\n /**\n * Compute the actual Y domain from series data\n */\n function computeYDomain(): { min: number; max: number } {\n const opts = chart.options;\n let yMin = opts.yAxis?.min;\n let yMax = opts.yAxis?.max;\n\n // If not explicitly set, derive from series data\n if (yMin === undefined || yMax === undefined) {\n const series = opts.series ?? [];\n let dataYMin = Number.POSITIVE_INFINITY;\n let dataYMax = Number.NEGATIVE_INFINITY;\n\n for (const s of series) {\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n const data = s.data;\n for (const p of data) {\n const high = getOHLCHigh(p);\n const low = getOHLCLow(p);\n if (high > dataYMax) dataYMax = high;\n if (low < dataYMin) dataYMin = low;\n }\n } else {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = s.data as ReadonlyArray<DataPoint>;\n for (const p of data) {\n const y = getPointY(p);\n if (y < dataYMin) dataYMin = y;\n if (y > dataYMax) dataYMax = y;\n }\n }\n }\n\n if (yMin === undefined) yMin = Number.isFinite(dataYMin) ? dataYMin : 0;\n if (yMax === undefined) yMax = Number.isFinite(dataYMax) ? dataYMax : 100;\n }\n\n return { min: yMin, max: yMax };\n }\n\n /**\n * Convert data-space coordinates to canvas-space CSS pixels\n */\n function dataToCanvas(x: number | undefined, y: number | undefined): { x: number; y: number } {\n const chartOptions = chart.options;\n const rect = canvas.getBoundingClientRect();\n\n const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n const canvasWidth = rect.width;\n const canvasHeight = rect.height;\n\n const plotLeft = grid.left ?? 60;\n const plotRight = canvasWidth - (grid.right ?? 20);\n const plotTop = grid.top ?? 40;\n const plotBottom = canvasHeight - (grid.bottom ?? 40);\n const plotWidth = plotRight - plotLeft;\n const plotHeight = plotBottom - plotTop;\n\n // Get scales from chart\n const xAxis = chartOptions.xAxis;\n const yAxis = chartOptions.yAxis;\n\n let canvasX = 0;\n let canvasY = 0;\n\n // Convert X coordinate\n if (x !== undefined && xAxis) {\n if (xAxis.type === 'category' && Array.isArray((xAxis as any).data)) {\n // Category scale: find index and map to plot space\n const data = (xAxis as any).data as string[];\n const index = data.indexOf(String(x));\n if (index >= 0) {\n const fraction = index / (data.length - 1 || 1);\n canvasX = plotLeft + fraction * plotWidth;\n }\n } else {\n // Linear scale - compute actual domain from data\n const domain = computeXDomain();\n const min = domain.min;\n const max = domain.max;\n const fraction = (x - min) / (max - min || 1);\n canvasX = plotLeft + fraction * plotWidth;\n }\n }\n\n // Convert Y coordinate (inverted: canvas top = max Y value)\n if (y !== undefined && yAxis) {\n // Compute actual domain from data\n const domain = computeYDomain();\n const min = domain.min;\n const max = domain.max;\n const fraction = (y - min) / (max - min || 1);\n canvasY = plotBottom - fraction * plotHeight; // Inverted Y\n }\n\n return { x: canvasX, y: canvasY };\n }\n\n /**\n * Convert plot-space coordinates (0-1 fractions) to canvas-space CSS pixels\n */\n function plotToCanvas(x: number, y: number): { x: number; y: number } {\n const chartOptions = chart.options;\n const rect = canvas.getBoundingClientRect();\n\n const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n const canvasWidth = rect.width;\n const canvasHeight = rect.height;\n\n const plotLeft = grid.left ?? 60;\n const plotRight = canvasWidth - (grid.right ?? 20);\n const plotTop = grid.top ?? 40;\n const plotBottom = canvasHeight - (grid.bottom ?? 40);\n const plotWidth = plotRight - plotLeft;\n const plotHeight = plotBottom - plotTop;\n\n return {\n x: plotLeft + x * plotWidth,\n y: plotTop + y * plotHeight,\n };\n }\n\n /**\n * Update cached bounds for all annotations\n */\n function updateCache(annotations: readonly AnnotationConfig[]): void {\n boundsCache.clear();\n\n annotations.forEach((annotation, index) => {\n const bounds: CachedAnnotationBounds = {};\n\n if (annotation.type === 'lineX' && annotation.x !== undefined) {\n const { x } = dataToCanvas(annotation.x, undefined);\n bounds.canvasX = x;\n } else if (annotation.type === 'lineY' && annotation.y !== undefined) {\n const { y } = dataToCanvas(undefined, annotation.y);\n bounds.canvasY = y;\n } else if (annotation.type === 'point' && annotation.x !== undefined && annotation.y !== undefined) {\n const { x, y } = dataToCanvas(annotation.x, annotation.y);\n bounds.canvasX = x;\n bounds.canvasY = y;\n } else if (annotation.type === 'text') {\n const pos = annotation.position;\n if (pos.space === 'plot') {\n const { x, y } = plotToCanvas(pos.x, pos.y);\n bounds.canvasX = x;\n bounds.canvasY = y;\n } else if (pos.space === 'data') {\n const { x, y } = dataToCanvas(pos.x, pos.y);\n bounds.canvasX = x;\n bounds.canvasY = y;\n }\n }\n\n boundsCache.set(index, bounds);\n });\n\n cacheValid = true;\n }\n\n /**\n * Calculate distance from pointer to a line (vertical or horizontal)\n */\n function distanceToLine(\n pointerX: number,\n pointerY: number,\n lineX?: number,\n lineY?: number\n ): number {\n if (lineX !== undefined) {\n // Vertical line: distance is horizontal difference\n return Math.abs(pointerX - lineX);\n } else if (lineY !== undefined) {\n // Horizontal line: distance is vertical difference\n return Math.abs(pointerY - lineY);\n }\n return Infinity;\n }\n\n /**\n * Calculate distance from pointer to a point\n */\n function distanceToPoint(\n pointerX: number,\n pointerY: number,\n pointX: number,\n pointY: number\n ): number {\n const dx = pointerX - pointX;\n const dy = pointerY - pointY;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Check if pointer is inside a rectangle (with tolerance padding)\n */\n function isInsideRect(\n pointerX: number,\n pointerY: number,\n rect: DOMRect,\n tolerance: number\n ): boolean {\n return (\n pointerX >= rect.left - tolerance &&\n pointerX <= rect.right + tolerance &&\n pointerY >= rect.top - tolerance &&\n pointerY <= rect.bottom + tolerance\n );\n }\n\n /**\n * Perform hit test at the given canvas position\n */\n function hitTest(canvasX: number, canvasY: number): AnnotationHitTestResult | null {\n const annotations = chart.options.annotations ?? [];\n\n if (annotations.length === 0) {\n return null;\n }\n\n // Update cache if invalid\n if (!cacheValid) {\n updateCache(annotations);\n }\n\n let closestHit: AnnotationHitTestResult | null = null;\n let closestDistance = Infinity;\n\n // Priority order: Labels > Points > Text > Lines\n // Test in reverse priority order (lines first) so higher priority overwrites\n\n // 1. Test lines (lowest priority)\n for (let i = 0; i < annotations.length; i++) {\n const annotation = annotations[i];\n const bounds = boundsCache.get(i);\n\n if (!bounds) {\n continue;\n }\n\n if (annotation.type === 'lineX' && bounds.canvasX !== undefined) {\n const distance = distanceToLine(canvasX, canvasY, bounds.canvasX, undefined);\n if (distance <= lineTolerance && distance < closestDistance) {\n closestDistance = distance;\n closestHit = {\n annotationIndex: i,\n annotation,\n hitType: 'line',\n distanceCssPx: distance,\n };\n }\n } else if (annotation.type === 'lineY' && bounds.canvasY !== undefined) {\n const distance = distanceToLine(canvasX, canvasY, undefined, bounds.canvasY);\n if (distance <= lineTolerance && distance < closestDistance) {\n closestDistance = distance;\n closestHit = {\n annotationIndex: i,\n annotation,\n hitType: 'line',\n distanceCssPx: distance,\n };\n }\n }\n }\n\n // 2. Test text (medium priority)\n for (let i = 0; i < annotations.length; i++) {\n const annotation = annotations[i];\n const textRect = textBoundsCache.get(i);\n\n if (annotation.type === 'text' && textRect) {\n if (isInsideRect(canvasX, canvasY, textRect, textTolerance)) {\n const centerX = textRect.left + textRect.width / 2;\n const centerY = textRect.top + textRect.height / 2;\n const distance = distanceToPoint(canvasX, canvasY, centerX, centerY);\n\n if (distance < closestDistance) {\n closestDistance = distance;\n closestHit = {\n annotationIndex: i,\n annotation,\n hitType: 'text',\n distanceCssPx: distance,\n };\n }\n }\n }\n }\n\n // 3. Test points (high priority)\n for (let i = 0; i < annotations.length; i++) {\n const annotation = annotations[i];\n const bounds = boundsCache.get(i);\n\n if (bounds && annotation.type === 'point' && bounds.canvasX !== undefined && bounds.canvasY !== undefined) {\n const distance = distanceToPoint(canvasX, canvasY, bounds.canvasX, bounds.canvasY);\n if (distance <= pointTolerance && distance < closestDistance) {\n closestDistance = distance;\n closestHit = {\n annotationIndex: i,\n annotation,\n hitType: 'point',\n distanceCssPx: distance,\n };\n }\n }\n }\n\n // 4. Test labels (highest priority) - TODO: implement once label bounds are available\n\n return closestHit;\n }\n\n /**\n * Update text bounds from DOM measurements\n */\n function updateTextBounds(textBounds: Map<number, DOMRect>): void {\n textBoundsCache = new Map(textBounds);\n }\n\n /**\n * Invalidate cache (call on zoom, pan, or resize)\n */\n function invalidateCache(): void {\n cacheValid = false;\n }\n\n /**\n * Dispose of resources\n */\n function dispose(): void {\n boundsCache.clear();\n textBoundsCache.clear();\n }\n\n return {\n hitTest,\n updateTextBounds,\n invalidateCache,\n dispose,\n };\n}\n","/**\n * Drag handler for repositioning annotations\n *\n * Handles dragging annotations to reposition them:\n * - lineX: constrained to horizontal movement\n * - lineY: constrained to vertical movement\n * - text: free 2D movement (data or plot space)\n * - point: free 2D movement (data space)\n *\n * Uses optimistic updates during drag for 60 FPS performance.\n */\n\nimport type { AnnotationConfig, DataPoint } from '../config/types.js';\nimport type { ChartGPUInstance } from '../ChartGPU.js';\n\nexport interface AnnotationDragCallbacks {\n onDragMove: (index: number, updates: Partial<AnnotationConfig>) => void;\n onDragEnd: (index: number, updates: Partial<AnnotationConfig>) => void;\n onDragCancel: () => void;\n}\n\nexport interface AnnotationDragHandler {\n startDrag(\n annotationIndex: number,\n annotation: AnnotationConfig,\n startPointerX: number,\n startPointerY: number\n ): void;\n isDragging(): boolean;\n dispose(): void;\n}\n\ninterface DragState {\n annotationIndex: number;\n annotation: AnnotationConfig;\n startPointerX: number;\n startPointerY: number;\n pointerId: number | null;\n}\n\n/**\n * Creates a drag handler for repositioning annotations\n */\nexport function createAnnotationDragHandler(\n chart: ChartGPUInstance,\n canvas: HTMLCanvasElement,\n callbacks: AnnotationDragCallbacks\n): AnnotationDragHandler {\n let dragState: DragState | null = null;\n\n // Type guards for data points\n const isTupleDataPoint = (p: any): p is [number, number] => Array.isArray(p);\n const isTupleOHLCDataPoint = (p: any): p is [number, number, number, number, number] => Array.isArray(p);\n const getPointX = (p: any): number => (isTupleDataPoint(p) ? p[0] : p.x);\n const getPointY = (p: any): number => (isTupleDataPoint(p) ? p[1] : p.y);\n const getOHLCTimestamp = (p: any): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\n const getOHLCHigh = (p: any): number => (isTupleOHLCDataPoint(p) ? p[2] : p.high);\n const getOHLCLow = (p: any): number => (isTupleOHLCDataPoint(p) ? p[3] : p.low);\n\n /**\n * Compute the actual X domain from series data (with zoom applied)\n */\n function computeXDomain(): { min: number; max: number } {\n const opts = chart.options;\n let xMin = opts.xAxis?.min;\n let xMax = opts.xAxis?.max;\n\n if (xMin === undefined || xMax === undefined) {\n const series = opts.series ?? [];\n let dataXMin = Number.POSITIVE_INFINITY;\n let dataXMax = Number.NEGATIVE_INFINITY;\n\n for (const s of series) {\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n const data = s.data;\n for (const p of data) {\n const timestamp = getOHLCTimestamp(p);\n if (timestamp < dataXMin) dataXMin = timestamp;\n if (timestamp > dataXMax) dataXMax = timestamp;\n }\n } else {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = s.data as ReadonlyArray<DataPoint>;\n for (const p of data) {\n const x = getPointX(p);\n if (x < dataXMin) dataXMin = x;\n if (x > dataXMax) dataXMax = x;\n }\n }\n }\n\n if (xMin === undefined) xMin = Number.isFinite(dataXMin) ? dataXMin : 0;\n if (xMax === undefined) xMax = Number.isFinite(dataXMax) ? dataXMax : 100;\n }\n\n const zoomRange = chart.getZoomRange();\n if (zoomRange) {\n const span = xMax - xMin;\n const zoomMin = xMin + (zoomRange.start / 100) * span;\n const zoomMax = xMin + (zoomRange.end / 100) * span;\n return { min: zoomMin, max: zoomMax };\n }\n\n return { min: xMin, max: xMax };\n }\n\n /**\n * Compute the actual Y domain from series data\n */\n function computeYDomain(): { min: number; max: number } {\n const opts = chart.options;\n let yMin = opts.yAxis?.min;\n let yMax = opts.yAxis?.max;\n\n if (yMin === undefined || yMax === undefined) {\n const series = opts.series ?? [];\n let dataYMin = Number.POSITIVE_INFINITY;\n let dataYMax = Number.NEGATIVE_INFINITY;\n\n for (const s of series) {\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n const data = s.data;\n for (const p of data) {\n const high = getOHLCHigh(p);\n const low = getOHLCLow(p);\n if (high > dataYMax) dataYMax = high;\n if (low < dataYMin) dataYMin = low;\n }\n } else {\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = s.data as ReadonlyArray<DataPoint>;\n for (const p of data) {\n const y = getPointY(p);\n if (y < dataYMin) dataYMin = y;\n if (y > dataYMax) dataYMax = y;\n }\n }\n }\n\n if (yMin === undefined) yMin = Number.isFinite(dataYMin) ? dataYMin : 0;\n if (yMax === undefined) yMax = Number.isFinite(dataYMax) ? dataYMax : 100;\n }\n\n return { min: yMin, max: yMax };\n }\n\n /**\n * Convert canvas-space CSS pixels to data-space coordinates\n */\n function canvasToData(canvasX: number, canvasY: number): { x: number; y: number } {\n const chartOptions = chart.options;\n const rect = canvas.getBoundingClientRect();\n\n const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n const canvasWidth = rect.width;\n const canvasHeight = rect.height;\n\n const plotLeft = grid.left ?? 60;\n const plotRight = canvasWidth - (grid.right ?? 20);\n const plotTop = grid.top ?? 40;\n const plotBottom = canvasHeight - (grid.bottom ?? 40);\n const plotWidth = plotRight - plotLeft;\n const plotHeight = plotBottom - plotTop;\n\n const xAxis = chartOptions.xAxis;\n const yAxis = chartOptions.yAxis;\n\n let dataX = 0;\n let dataY = 0;\n\n // Convert X coordinate\n if (xAxis) {\n const xFraction = (canvasX - plotLeft) / plotWidth;\n if (xAxis.type === 'category' && Array.isArray((xAxis as any).data)) {\n // Category scale: map fraction to category index\n const data = (xAxis as any).data as any[];\n const index = Math.round(xFraction * (data.length - 1 || 1));\n dataX = data[Math.max(0, Math.min(index, data.length - 1))] as number;\n } else {\n // Linear scale - compute actual domain from data\n const domain = computeXDomain();\n dataX = domain.min + xFraction * (domain.max - domain.min);\n }\n }\n\n // Convert Y coordinate (inverted: canvas top = max Y value)\n if (yAxis) {\n const yFraction = (plotBottom - canvasY) / plotHeight;\n // Compute actual domain from data\n const domain = computeYDomain();\n dataY = domain.min + yFraction * (domain.max - domain.min);\n }\n\n return { x: dataX, y: dataY };\n }\n\n /**\n * Convert canvas-space CSS pixels to plot-space coordinates (0-1 fractions)\n */\n function canvasToPlot(canvasX: number, canvasY: number): { x: number; y: number } {\n const chartOptions = chart.options;\n const rect = canvas.getBoundingClientRect();\n\n const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n const canvasWidth = rect.width;\n const canvasHeight = rect.height;\n\n const plotLeft = grid.left ?? 60;\n const plotRight = canvasWidth - (grid.right ?? 20);\n const plotTop = grid.top ?? 40;\n const plotBottom = canvasHeight - (grid.bottom ?? 40);\n const plotWidth = plotRight - plotLeft;\n const plotHeight = plotBottom - plotTop;\n\n const x = (canvasX - plotLeft) / plotWidth;\n const y = (canvasY - plotTop) / plotHeight;\n\n // Clamp to [0, 1]\n return {\n x: Math.max(0, Math.min(1, x)),\n y: Math.max(0, Math.min(1, y)),\n };\n }\n\n /**\n * Handle pointer move during drag\n */\n function onPointerMove(e: PointerEvent): void {\n if (!dragState) {\n return;\n }\n\n e.preventDefault();\n\n const rect = canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n const annotation = dragState.annotation;\n const updates: any = {}; // Use 'any' to bypass TypeScript union narrowing issues\n\n if (annotation.type === 'lineX') {\n // Constrain to horizontal movement only\n const { x } = canvasToData(canvasX, 0);\n updates.x = x;\n } else if (annotation.type === 'lineY') {\n // Constrain to vertical movement only\n const { y } = canvasToData(0, canvasY);\n updates.y = y;\n } else if (annotation.type === 'text') {\n // Free 2D movement (respect original space)\n const space = annotation.position.space;\n if (space === 'plot') {\n const { x, y } = canvasToPlot(canvasX, canvasY);\n updates.position = { space, x, y };\n } else {\n // data space\n const { x, y } = canvasToData(canvasX, canvasY);\n updates.position = { space, x, y };\n }\n } else if (annotation.type === 'point') {\n // Free 2D movement in data space\n const { x, y } = canvasToData(canvasX, canvasY);\n updates.x = x;\n updates.y = y;\n }\n\n // Optimistic update (no history push)\n callbacks.onDragMove(dragState.annotationIndex, updates);\n }\n\n /**\n * Handle pointer up (drag end)\n */\n function onPointerUp(e: PointerEvent): void {\n if (!dragState) return;\n\n const rect = canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n const annotation = dragState.annotation;\n const updates: any = {}; // Use 'any' to bypass TypeScript union narrowing issues\n\n if (annotation.type === 'lineX') {\n const { x } = canvasToData(canvasX, 0);\n updates.x = x;\n } else if (annotation.type === 'lineY') {\n const { y } = canvasToData(0, canvasY);\n updates.y = y;\n } else if (annotation.type === 'text') {\n const space = annotation.position.space;\n if (space === 'plot') {\n const { x, y } = canvasToPlot(canvasX, canvasY);\n updates.position = { space, x, y };\n } else {\n const { x, y } = canvasToData(canvasX, canvasY);\n updates.position = { space, x, y };\n }\n } else if (annotation.type === 'point') {\n const { x, y } = canvasToData(canvasX, canvasY);\n updates.x = x;\n updates.y = y;\n }\n\n // Push single history entry with final position\n callbacks.onDragEnd(dragState.annotationIndex, updates);\n\n cleanup();\n }\n\n /**\n * Handle pointer cancel (drag cancelled)\n */\n function onPointerCancel(): void {\n if (!dragState) return;\n\n // Revert to original position\n callbacks.onDragCancel();\n\n cleanup();\n }\n\n /**\n * Handle keyboard events during drag\n */\n function onKeyDown(e: KeyboardEvent): void {\n if (!dragState) return;\n\n if (e.key === 'Escape') {\n e.preventDefault();\n onPointerCancel();\n }\n }\n\n /**\n * Cleanup drag state and event listeners\n */\n function cleanup(): void {\n if (!dragState) return;\n\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n window.removeEventListener('pointercancel', onPointerCancel);\n document.removeEventListener('keydown', onKeyDown);\n\n if (dragState.pointerId !== null) {\n try {\n canvas.releasePointerCapture(dragState.pointerId);\n } catch (err) {\n // Ignore errors (pointer may already be released)\n }\n }\n\n document.body.style.cursor = '';\n dragState = null;\n }\n\n /**\n * Start dragging an annotation\n */\n function startDrag(\n annotationIndex: number,\n annotation: AnnotationConfig,\n startPointerX: number,\n startPointerY: number\n ): void {\n // Cancel any existing drag\n if (dragState) {\n cleanup();\n }\n\n dragState = {\n annotationIndex,\n annotation,\n startPointerX,\n startPointerY,\n pointerId: null,\n };\n\n // Set cursor based on annotation type\n if (annotation.type === 'lineX') {\n document.body.style.cursor = 'ew-resize';\n } else if (annotation.type === 'lineY') {\n document.body.style.cursor = 'ns-resize';\n } else {\n document.body.style.cursor = 'grabbing';\n }\n\n // Attach window-level listeners for smooth dragging outside canvas\n window.addEventListener('pointermove', onPointerMove, { passive: false });\n window.addEventListener('pointerup', onPointerUp, { passive: true });\n window.addEventListener('pointercancel', onPointerCancel, { passive: true });\n document.addEventListener('keydown', onKeyDown, { passive: false });\n\n // Visual feedback: reduce opacity\n callbacks.onDragMove(annotationIndex, {\n style: { ...annotation.style, opacity: 0.7 },\n });\n }\n\n /**\n * Check if currently dragging\n */\n function isDragging(): boolean {\n return dragState !== null;\n }\n\n /**\n * Dispose of resources\n */\n function dispose(): void {\n cleanup();\n }\n\n return {\n startDrag,\n isDragging,\n dispose,\n };\n}\n","/**\n * Configuration dialog for creating and editing annotations\n *\n * Provides a modal dialog for setting annotation properties:\n * - Label, color, line style, line width (for lines)\n * - Text content, color, font size (for text annotations)\n * - Label, color, marker size (for point annotations)\n */\n\nimport type { AnnotationConfig } from '../config/types.js';\n\nexport interface AnnotationConfigDialogOptions {\n readonly palette?: readonly string[];\n readonly zIndex?: number;\n}\n\nexport interface AnnotationConfigDialog {\n showCreate(\n annotationType: 'lineX' | 'lineY' | 'text' | 'point',\n defaults: Partial<AnnotationConfig>,\n onSave: (config: AnnotationConfig) => void,\n onCancel: () => void\n ): void;\n\n showEdit(\n annotation: AnnotationConfig,\n onSave: (updates: Partial<AnnotationConfig>) => void,\n onCancel: () => void\n ): void;\n\n hide(): void;\n dispose(): void;\n}\n\nconst HIGH_CONTRAST_PALETTE = [\n '#ef4444', // Red (critical)\n '#f97316', // Orange (warning)\n '#eab308', // Yellow (caution)\n '#22c55e', // Green (success)\n '#06b6d4', // Cyan (info)\n '#3b82f6', // Blue (primary)\n '#8b5cf6', // Purple (accent)\n '#ec4899', // Pink (highlight)\n '#ffffff', // White (high contrast)\n '#94a3b8', // Gray (neutral)\n '#64748b', // Dark gray (subtle)\n '#1e293b', // Near-black (background)\n] as const;\n\n/**\n * Creates a configuration dialog for annotations\n */\nexport function createAnnotationConfigDialog(\n container: HTMLElement,\n options: AnnotationConfigDialogOptions = {}\n): AnnotationConfigDialog {\n const palette = options.palette ?? HIGH_CONTRAST_PALETTE;\n const zIndex = options.zIndex ?? 1000;\n\n let overlay: HTMLDivElement | null = null;\n let dialog: HTMLDivElement | null = null;\n let currentOnSave: ((config: any) => void) | null = null;\n let currentOnCancel: (() => void) | null = null;\n let mode: 'create' | 'edit' = 'create';\n\n /**\n * Create the modal overlay\n */\n function createOverlay(): HTMLDivElement {\n const div = document.createElement('div');\n div.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n z-index: ${zIndex + 1};\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n div.addEventListener('click', (e) => {\n if (e.target === div) {\n handleCancel();\n }\n });\n return div;\n }\n\n /**\n * Create the dialog box\n */\n function createDialog(): HTMLDivElement {\n const div = document.createElement('div');\n div.style.cssText = `\n width: 320px;\n background: #1a1a2e;\n border: 1px solid #333;\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.7);\n padding: 20px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n color: #e0e0e0;\n `;\n return div;\n }\n\n /**\n * Create a form field container\n */\n function createField(label: string, input: HTMLElement): HTMLDivElement {\n const field = document.createElement('div');\n field.style.cssText = `\n margin-bottom: 16px;\n `;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n labelEl.style.cssText = `\n display: block;\n margin-bottom: 8px;\n font-size: 13px;\n font-weight: 500;\n color: #b0b0b0;\n `;\n\n field.appendChild(labelEl);\n field.appendChild(input);\n return field;\n }\n\n /**\n * Create a text input\n */\n function createTextInput(placeholder: string, maxLength: number, defaultValue = ''): HTMLInputElement {\n const input = document.createElement('input');\n input.type = 'text';\n input.placeholder = placeholder;\n input.maxLength = maxLength;\n input.value = defaultValue;\n input.style.cssText = `\n width: 100%;\n padding: 8px 12px;\n background: #2a2a3e;\n border: 1px solid #444;\n border-radius: 4px;\n color: #e0e0e0;\n font-size: 14px;\n box-sizing: border-box;\n `;\n input.addEventListener('focus', () => {\n input.style.borderColor = '#3b82f6';\n });\n input.addEventListener('blur', () => {\n input.style.borderColor = '#444';\n });\n return input;\n }\n\n /**\n * Create a textarea\n */\n function createTextArea(placeholder: string, maxLength: number, defaultValue = ''): HTMLTextAreaElement {\n const textarea = document.createElement('textarea');\n textarea.placeholder = placeholder;\n textarea.maxLength = maxLength;\n textarea.value = defaultValue;\n textarea.rows = 3;\n textarea.style.cssText = `\n width: 100%;\n padding: 8px 12px;\n background: #2a2a3e;\n border: 1px solid #444;\n border-radius: 4px;\n color: #e0e0e0;\n font-size: 14px;\n box-sizing: border-box;\n resize: vertical;\n font-family: inherit;\n `;\n textarea.addEventListener('focus', () => {\n textarea.style.borderColor = '#3b82f6';\n });\n textarea.addEventListener('blur', () => {\n textarea.style.borderColor = '#444';\n });\n return textarea;\n }\n\n /**\n * Create a color picker grid\n */\n function createColorPicker(selectedColor: string): { container: HTMLDivElement; getValue: () => string } {\n const container = document.createElement('div');\n container.style.cssText = `\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n `;\n\n let currentColor = selectedColor;\n\n palette.forEach((color) => {\n // Button wrapper for swatch\n const swatch = document.createElement('button');\n swatch.type = 'button';\n swatch.dataset.color = color; // Store color for reliable comparison\n swatch.style.cssText = `\n position: relative;\n width: 100%;\n aspect-ratio: 1;\n background: ${color};\n border: none;\n border-radius: 4px;\n cursor: pointer;\n transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;\n box-shadow: ${color === currentColor ? 'inset 0 0 0 2px #ffffff, inset 0 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.3)' : 'inset 0 0 0 1px rgba(255, 255, 255, 0.1)'};\n transform: ${color === currentColor ? 'scale(1.05)' : 'scale(1)'};\n `;\n\n // Create checkmark SVG for selected state\n const checkmark = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n checkmark.setAttribute('viewBox', '0 0 24 24');\n checkmark.setAttribute('fill', 'none');\n checkmark.style.cssText = `\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 60%;\n height: 60%;\n pointer-events: none;\n opacity: ${color === currentColor ? '1' : '0'};\n transition: opacity 0.15s ease-out;\n `;\n\n // Checkmark path with dual stroke for maximum contrast\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute('d', 'M20 6L9 17l-5-5');\n path.setAttribute('stroke', '#ffffff');\n path.setAttribute('stroke-width', '3');\n path.setAttribute('stroke-linecap', 'round');\n path.setAttribute('stroke-linejoin', 'round');\n path.style.cssText = `\n filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 1px rgba(0, 0, 0, 0.9));\n `;\n\n checkmark.appendChild(path);\n swatch.appendChild(checkmark);\n\n // Click handler\n swatch.addEventListener('click', () => {\n currentColor = color;\n // Update all swatches\n Array.from(container.children).forEach((child) => {\n const btn = child as HTMLButtonElement;\n const btnColor = btn.dataset.color; // Use data attribute for reliable comparison\n const isSelected = btnColor === color;\n\n // Update box-shadow for border effect\n btn.style.boxShadow = isSelected\n ? 'inset 0 0 0 2px #ffffff, inset 0 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.3)'\n : 'inset 0 0 0 1px rgba(255, 255, 255, 0.1)';\n\n // Update scale\n btn.style.transform = isSelected ? 'scale(1.05)' : 'scale(1)';\n\n // Update checkmark visibility\n const svg = btn.querySelector('svg');\n if (svg) {\n svg.style.opacity = isSelected ? '1' : '0';\n }\n });\n });\n\n // Hover effects\n swatch.addEventListener('mouseenter', () => {\n if (color !== currentColor) {\n swatch.style.transform = 'scale(1.1)';\n swatch.style.boxShadow = 'inset 0 0 0 2px rgba(255, 255, 255, 0.2), 0 4px 12px rgba(0, 0, 0, 0.4)';\n }\n });\n\n swatch.addEventListener('mouseleave', () => {\n if (color !== currentColor) {\n swatch.style.transform = 'scale(1)';\n swatch.style.boxShadow = 'inset 0 0 0 1px rgba(255, 255, 255, 0.1)';\n }\n });\n\n container.appendChild(swatch);\n });\n\n return {\n container,\n getValue: () => currentColor,\n };\n }\n\n /**\n * Create a dropdown select\n */\n function createDropdown(\n options: Array<{ label: string; value: string }>,\n defaultValue: string\n ): { container: HTMLSelectElement; getValue: () => string } {\n const select = document.createElement('select');\n select.style.cssText = `\n width: 100%;\n padding: 8px 12px;\n background: #2a2a3e;\n border: 1px solid #444;\n border-radius: 4px;\n color: #e0e0e0;\n font-size: 14px;\n cursor: pointer;\n `;\n\n options.forEach((opt) => {\n const option = document.createElement('option');\n option.value = opt.value;\n option.textContent = opt.label;\n if (opt.value === defaultValue) {\n option.selected = true;\n }\n select.appendChild(option);\n });\n\n return {\n container: select,\n getValue: () => select.value,\n };\n }\n\n /**\n * Create a slider with numeric value display\n */\n function createSlider(\n min: number,\n max: number,\n step: number,\n defaultValue: number,\n unit = ''\n ): { container: HTMLDivElement; getValue: () => number } {\n const container = document.createElement('div');\n container.style.cssText = `\n display: flex;\n align-items: center;\n gap: 12px;\n `;\n\n const slider = document.createElement('input');\n slider.type = 'range';\n slider.min = String(min);\n slider.max = String(max);\n slider.step = String(step);\n slider.value = String(defaultValue);\n slider.style.cssText = `\n flex: 1;\n cursor: pointer;\n `;\n\n const valueDisplay = document.createElement('span');\n valueDisplay.textContent = `${defaultValue}${unit}`;\n valueDisplay.style.cssText = `\n min-width: 40px;\n text-align: right;\n font-size: 13px;\n color: #b0b0b0;\n `;\n\n slider.addEventListener('input', () => {\n valueDisplay.textContent = `${slider.value}${unit}`;\n });\n\n container.appendChild(slider);\n container.appendChild(valueDisplay);\n\n return {\n container,\n getValue: () => parseFloat(slider.value),\n };\n }\n\n /**\n * Create action buttons\n */\n function createButtons(saveLabel: string, onSaveClick: () => void, onCancelClick: () => void): HTMLDivElement {\n const container = document.createElement('div');\n container.style.cssText = `\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n margin-top: 24px;\n `;\n\n const cancelBtn = document.createElement('button');\n cancelBtn.type = 'button';\n cancelBtn.textContent = 'Cancel';\n cancelBtn.style.cssText = `\n padding: 8px 16px;\n background: transparent;\n border: 1px solid #444;\n border-radius: 4px;\n color: #888;\n font-size: 14px;\n cursor: pointer;\n transition: background 0.15s;\n `;\n cancelBtn.addEventListener('mouseenter', () => {\n cancelBtn.style.background = '#2a2a3e';\n });\n cancelBtn.addEventListener('mouseleave', () => {\n cancelBtn.style.background = 'transparent';\n });\n cancelBtn.addEventListener('click', onCancelClick);\n\n const saveBtn = document.createElement('button');\n saveBtn.type = 'button';\n saveBtn.textContent = saveLabel;\n saveBtn.style.cssText = `\n padding: 8px 16px;\n background: #2a2a3e;\n border: 1px solid #444;\n border-radius: 4px;\n color: #e0e0e0;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n `;\n saveBtn.addEventListener('mouseenter', () => {\n saveBtn.style.background = '#3a3a4e';\n });\n saveBtn.addEventListener('mouseleave', () => {\n saveBtn.style.background = '#2a2a3e';\n });\n saveBtn.addEventListener('click', onSaveClick);\n\n container.appendChild(cancelBtn);\n container.appendChild(saveBtn);\n\n return container;\n }\n\n /**\n * Build form for line annotations (lineX/lineY)\n */\n function buildLineForm(defaults: Partial<AnnotationConfig>): HTMLDivElement {\n const form = document.createElement('div');\n\n // Extract label text from label object (if it exists)\n const defaultLabelText = (defaults as any).label?.text ?? '';\n const labelInput = createTextInput('Line label', 100, defaultLabelText);\n const colorPicker = createColorPicker(defaults.style?.color ?? palette[0]);\n const lineStyleDropdown = createDropdown(\n [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n defaults.style?.lineDash ? (defaults.style.lineDash.length === 4 ? 'dashed' : 'dotted') : 'solid'\n );\n const lineWidthSlider = createSlider(1, 8, 1, defaults.style?.lineWidth ?? 2, 'px');\n\n form.appendChild(createField('Label (optional)', labelInput));\n form.appendChild(createField('Color', colorPicker.container));\n form.appendChild(createField('Line Style', lineStyleDropdown.container));\n form.appendChild(createField('Line Width', lineWidthSlider.container));\n\n const buttons = createButtons(\n mode === 'create' ? 'Create' : 'Save',\n () => {\n const lineDashMap: Record<string, number[] | undefined> = {\n solid: undefined,\n dashed: [4, 4],\n dotted: [2, 2],\n };\n\n const labelText = labelInput.value.trim();\n const config: Partial<AnnotationConfig> = {\n ...defaults,\n label: labelText\n ? {\n ...(defaults as any).label,\n text: labelText,\n }\n : undefined,\n style: {\n ...defaults.style,\n color: colorPicker.getValue(),\n lineWidth: lineWidthSlider.getValue(),\n lineDash: lineDashMap[lineStyleDropdown.getValue()],\n },\n };\n\n handleSave(config);\n },\n () => handleCancel()\n );\n\n form.appendChild(buttons);\n\n return form;\n }\n\n /**\n * Build form for text annotations\n */\n function buildTextForm(defaults: Partial<AnnotationConfig>): HTMLDivElement {\n const form = document.createElement('div');\n\n // Extract text from text annotation\n const defaultText = (defaults as any).text ?? '';\n const textArea = createTextArea('Text content', 500, defaultText);\n const colorPicker = createColorPicker(defaults.style?.color ?? palette[0]);\n\n form.appendChild(createField('Text', textArea));\n form.appendChild(createField('Color', colorPicker.container));\n\n const buttons = createButtons(\n mode === 'create' ? 'Create' : 'Save',\n () => {\n const text = textArea.value.trim();\n if (!text) {\n textArea.style.borderColor = '#ef4444';\n textArea.focus();\n return;\n }\n\n const config: Partial<AnnotationConfig> = {\n ...defaults,\n text,\n style: {\n ...defaults.style,\n color: colorPicker.getValue(),\n },\n } as any; // Use 'any' to bypass type narrowing issues\n\n handleSave(config);\n },\n () => handleCancel()\n );\n\n form.appendChild(buttons);\n\n return form;\n }\n\n /**\n * Build form for point annotations\n */\n function buildPointForm(defaults: Partial<AnnotationConfig>): HTMLDivElement {\n const form = document.createElement('div');\n\n // Extract label text from label object (if it exists)\n const defaultLabelText = (defaults as any).label?.text ?? '';\n const labelInput = createTextInput('Point label', 100, defaultLabelText);\n const colorPicker = createColorPicker(defaults.style?.color ?? palette[0]);\n\n // For point annotations, marker style might be in marker.style or just style\n const defaultMarkerSize = (defaults as any).marker?.size ?? (defaults as any).marker?.style?.markerSize ?? 8;\n const markerSizeSlider = createSlider(4, 16, 1, defaultMarkerSize, 'px');\n\n form.appendChild(createField('Label (optional)', labelInput));\n form.appendChild(createField('Color', colorPicker.container));\n form.appendChild(createField('Marker Size', markerSizeSlider.container));\n\n const buttons = createButtons(\n mode === 'create' ? 'Create' : 'Save',\n () => {\n const labelText = labelInput.value.trim();\n const config: Partial<AnnotationConfig> = {\n ...defaults,\n label: labelText\n ? {\n ...(defaults as any).label,\n text: labelText,\n }\n : undefined,\n marker: {\n ...(defaults as any).marker,\n size: markerSizeSlider.getValue(),\n style: {\n ...(defaults as any).marker?.style,\n color: colorPicker.getValue(),\n },\n },\n };\n\n handleSave(config);\n },\n () => handleCancel()\n );\n\n form.appendChild(buttons);\n\n return form;\n }\n\n /**\n * Handle save action\n */\n function handleSave(config: any): void {\n if (currentOnSave) {\n currentOnSave(config);\n }\n hide();\n }\n\n /**\n * Handle cancel action\n */\n function handleCancel(): void {\n if (currentOnCancel) {\n currentOnCancel();\n }\n hide();\n }\n\n /**\n * Handle keyboard events\n */\n function handleKeyDown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n }\n\n /**\n * Show dialog for creating a new annotation\n */\n function showCreate(\n type: 'lineX' | 'lineY' | 'text' | 'point',\n defaults: Partial<AnnotationConfig>,\n onSave: (config: AnnotationConfig) => void,\n onCancel: () => void\n ): void {\n mode = 'create';\n currentOnSave = onSave;\n currentOnCancel = onCancel;\n\n overlay = createOverlay();\n dialog = createDialog();\n\n const title = document.createElement('h3');\n title.textContent = `Add ${type === 'lineX' ? 'Vertical Line' : type === 'lineY' ? 'Horizontal Line' : type === 'text' ? 'Text Note' : 'Point Marker'}`;\n title.style.cssText = `\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #ffffff;\n `;\n dialog.appendChild(title);\n\n let form: HTMLDivElement;\n if (type === 'lineX' || type === 'lineY') {\n form = buildLineForm(defaults);\n } else if (type === 'text') {\n form = buildTextForm(defaults);\n } else {\n form = buildPointForm(defaults);\n }\n\n dialog.appendChild(form);\n overlay.appendChild(dialog);\n container.appendChild(overlay);\n\n document.addEventListener('keydown', handleKeyDown);\n\n // Focus first input\n const firstInput = dialog.querySelector('input, textarea') as HTMLElement;\n if (firstInput) {\n setTimeout(() => firstInput.focus(), 50);\n }\n }\n\n /**\n * Show dialog for editing an existing annotation\n */\n function showEdit(\n annotation: AnnotationConfig,\n onSave: (updates: Partial<AnnotationConfig>) => void,\n onCancel: () => void\n ): void {\n mode = 'edit';\n currentOnSave = onSave;\n currentOnCancel = onCancel;\n\n overlay = createOverlay();\n dialog = createDialog();\n\n const title = document.createElement('h3');\n title.textContent = 'Edit Annotation';\n title.style.cssText = `\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #ffffff;\n `;\n dialog.appendChild(title);\n\n let form: HTMLDivElement;\n if (annotation.type === 'lineX' || annotation.type === 'lineY') {\n form = buildLineForm(annotation);\n } else if (annotation.type === 'text') {\n form = buildTextForm(annotation);\n } else {\n form = buildPointForm(annotation);\n }\n\n dialog.appendChild(form);\n overlay.appendChild(dialog);\n container.appendChild(overlay);\n\n document.addEventListener('keydown', handleKeyDown);\n\n // Focus first input\n const firstInput = dialog.querySelector('input, textarea') as HTMLElement;\n if (firstInput) {\n setTimeout(() => firstInput.focus(), 50);\n }\n }\n\n /**\n * Hide the dialog\n */\n function hide(): void {\n if (overlay && overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n overlay = null;\n dialog = null;\n currentOnSave = null;\n currentOnCancel = null;\n\n document.removeEventListener('keydown', handleKeyDown);\n }\n\n /**\n * Dispose of resources\n */\n function dispose(): void {\n hide();\n }\n\n return {\n showCreate,\n showEdit,\n hide,\n dispose,\n };\n}\n","/**\n * Annotation authoring helper for ChartGPU instances.\n *\n * Provides right-click context menu for adding vertical lines and text annotations,\n * with undo/redo, JSON export, drag-to-reposition, and editing capabilities.\n */\n\nimport type { ChartGPUInstance, ChartGPUHitTestResult } from '../ChartGPU';\nimport type { AnnotationConfig, DataPoint, DataPointTuple, OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\nimport { defaultGrid } from '../config/defaults';\nimport { createAnnotationHitTester } from './createAnnotationHitTester';\nimport { createAnnotationDragHandler } from './createAnnotationDragHandler';\nimport { createAnnotationConfigDialog } from '../components/createAnnotationConfigDialog';\n\n// Type guards and helpers\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\nconst isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getPointX = (p: DataPoint): number => (isTupleDataPoint(p) ? p[0] : p.x);\nconst getPointY = (p: DataPoint): number => (isTupleDataPoint(p) ? p[1] : p.y);\nconst getOHLCTimestamp = (p: OHLCDataPoint): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\n\n/**\n * Configuration options for annotation authoring.\n */\nexport interface AnnotationAuthoringOptions {\n /**\n * Z-index for the context menu (default: 1000).\n */\n readonly menuZIndex?: number;\n /**\n * Enable right-click context menu (default: true).\n */\n readonly enableContextMenu?: boolean;\n}\n\n/**\n * Annotation authoring instance returned by `createAnnotationAuthoring`.\n * \n * Provides programmatic control over annotations and manages UI lifecycle.\n */\nexport interface AnnotationAuthoringInstance {\n /**\n * Programmatically add a vertical line annotation.\n * \n * @param x - X-coordinate in data domain units\n */\n addVerticalLine(x: number): void;\n /**\n * Programmatically add a text annotation.\n * \n * @param x - X-coordinate (domain units for 'data' space, fraction [0-1] for 'plot' space)\n * @param y - Y-coordinate (domain units for 'data' space, fraction [0-1] for 'plot' space)\n * @param text - Annotation text content\n * @param space - Coordinate space: 'data' (default) or 'plot'\n */\n addTextNote(x: number, y: number, text: string, space?: 'data' | 'plot'): void;\n /**\n * Undo the last annotation change.\n * \n * @returns `true` if undo was successful, `false` if nothing to undo\n */\n undo(): boolean;\n /**\n * Redo a previously undone change.\n * \n * @returns `true` if redo was successful, `false` if nothing to redo\n */\n redo(): boolean;\n /**\n * Export current annotations as JSON string.\n * \n * @returns JSON string representation of annotations array\n */\n exportJSON(): string;\n /**\n * Get the current annotations array.\n * \n * @returns Readonly copy of current annotations\n */\n getAnnotations(): readonly AnnotationConfig[];\n /**\n * Clean up event listeners and DOM elements.\n * \n * Safe to call multiple times. After disposal, the instance should not be used.\n */\n dispose(): void;\n}\n\ninterface HistoryEntry {\n readonly annotations: readonly AnnotationConfig[];\n}\n\n/**\n * Creates an annotation authoring helper for a chart instance.\n * \n * Features:\n * - Right-click context menu for adding vertical lines and text annotations\n * - Optional toolbar with undo/redo/export buttons\n * - Undo/redo history (50 entries max)\n * - JSON export with clipboard integration\n * - Automatic coordinate conversion (data-space and plot-space)\n * - Event listener cleanup on dispose\n * \n * Annotations are persisted by calling `chart.setOption({ ...options, annotations })`,\n * so they integrate seamlessly with the chart's option system.\n * \n * @param container - The chart container element (must contain the chart canvas)\n * @param chart - The ChartGPU instance\n * @param options - Optional configuration for menu/toolbar z-index and visibility\n * @returns Annotation authoring instance with programmatic API and dispose method\n * @throws Error if canvas is not found\n * \n * @example\n * ```ts\n * const chart = await ChartGPU.create(container, options);\n * const authoring = createAnnotationAuthoring(container, chart, {\n * showToolbar: true,\n * enableContextMenu: true,\n * });\n * \n * // Programmatic API\n * authoring.addVerticalLine(Date.now());\n * authoring.addTextNote(x, y, 'Peak', 'data');\n * authoring.undo();\n * authoring.redo();\n * const json = authoring.exportJSON();\n * \n * // Cleanup\n * authoring.dispose();\n * chart.dispose();\n * ```\n */\nexport function createAnnotationAuthoring(\n container: HTMLElement,\n chart: ChartGPUInstance,\n options: AnnotationAuthoringOptions = {}\n): AnnotationAuthoringInstance {\n const {\n menuZIndex = 1000,\n enableContextMenu = true,\n } = options;\n\n // Find the canvas element\n const canvas = container.querySelector('canvas');\n if (!canvas) {\n throw new Error('createAnnotationAuthoring: canvas element not found in container');\n }\n\n // History management\n let history: HistoryEntry[] = [{ annotations: chart.options.annotations ?? [] }];\n let historyIndex = 0;\n let disposed = false;\n\n // Create hit tester, drag handler, and config dialog\n const hitTester = createAnnotationHitTester(chart, canvas, {\n lineTolerance: 20,\n textTolerance: 8,\n pointTolerance: 16,\n });\n\n const configDialog = createAnnotationConfigDialog(container, {\n zIndex: menuZIndex,\n });\n\n const dragHandler = createAnnotationDragHandler(chart, canvas, {\n onDragMove: (index, updates) => {\n // Optimistic update without history\n const current = getCurrentAnnotations();\n const next = current.map((a, i) => (i === index ? { ...a, ...updates } as AnnotationConfig : a));\n applyAnnotations(next);\n },\n onDragEnd: (index, updates) => {\n // Final position with history push\n const current = getCurrentAnnotations();\n const next = current.map((a, i) => (i === index ? { ...a, ...updates } as AnnotationConfig : a));\n applyAnnotations(next);\n pushHistory(next);\n },\n onDragCancel: () => {\n // Revert to last history state (no push)\n const entry = history[historyIndex];\n if (entry) {\n applyAnnotations(entry.annotations);\n }\n },\n });\n\n // Get current annotations\n const getCurrentAnnotations = (): readonly AnnotationConfig[] => {\n return chart.options.annotations ?? [];\n };\n\n // Push a new history entry\n const pushHistory = (annotations: readonly AnnotationConfig[]): void => {\n // Truncate any redo history\n history = history.slice(0, historyIndex + 1);\n history.push({ annotations: [...annotations] });\n historyIndex = history.length - 1;\n\n // Limit history size to 50 entries\n if (history.length > 50) {\n history.shift();\n historyIndex--;\n }\n };\n\n // Apply annotations to chart\n const applyAnnotations = (annotations: readonly AnnotationConfig[]): void => {\n chart.setOption({\n ...chart.options,\n annotations: [...annotations],\n });\n // Invalidate hit tester cache so it picks up the new/modified annotations\n hitTester.invalidateCache();\n };\n\n // Context menu DOM\n let contextMenu: HTMLDivElement | null = null;\n\n const createContextMenu = (): HTMLDivElement => {\n const menu = document.createElement('div');\n menu.style.position = 'fixed';\n menu.style.display = 'none';\n menu.style.backgroundColor = '#1a1a2e';\n menu.style.border = '1px solid #333';\n menu.style.borderRadius = '8px';\n menu.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.5)';\n menu.style.zIndex = String(menuZIndex);\n menu.style.minWidth = '180px';\n menu.style.padding = '6px 0';\n menu.style.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif';\n menu.style.fontSize = '14px';\n menu.style.color = '#e0e0e0';\n\n document.body.appendChild(menu);\n return menu;\n };\n\n const createMenuItem = (text: string, onClick: () => void): HTMLDivElement => {\n const item = document.createElement('div');\n item.textContent = text;\n item.style.padding = '8px 16px';\n item.style.cursor = 'pointer';\n item.style.transition = 'background-color 0.15s';\n item.style.userSelect = 'none';\n\n item.addEventListener('mouseenter', () => {\n item.style.backgroundColor = '#2a2a3e';\n });\n item.addEventListener('mouseleave', () => {\n item.style.backgroundColor = 'transparent';\n });\n item.addEventListener('click', () => {\n onClick();\n hideContextMenu();\n });\n\n return item;\n };\n\n const createMenuSeparator = (): HTMLDivElement => {\n const separator = document.createElement('div');\n separator.style.height = '1px';\n separator.style.backgroundColor = '#333';\n separator.style.margin = '6px 0';\n return separator;\n };\n\n const populateContextMenuForAnnotation = (\n menu: HTMLDivElement,\n annotationIndex: number,\n annotation: AnnotationConfig\n ): void => {\n // Clear existing items\n menu.innerHTML = '';\n\n // Edit and delete for the annotation\n menu.appendChild(createMenuItem('Edit annotation...', () => handleEditAnnotation(annotationIndex, annotation)));\n menu.appendChild(createMenuItem('Delete annotation', () => handleDeleteAnnotation(annotationIndex)));\n menu.appendChild(createMenuSeparator());\n\n // Add new annotations\n menu.appendChild(createMenuItem('Add vertical line here', () => handleAddVerticalLine()));\n menu.appendChild(createMenuItem('Add horizontal line here', () => handleAddHorizontalLine()));\n menu.appendChild(createMenuItem('Add text note here', () => handleAddTextNote()));\n };\n\n const populateContextMenuForEmptySpace = (menu: HTMLDivElement): void => {\n // Clear existing items\n menu.innerHTML = '';\n\n // Add new annotations\n menu.appendChild(createMenuItem('Add vertical line here', () => handleAddVerticalLine()));\n menu.appendChild(createMenuItem('Add horizontal line here', () => handleAddHorizontalLine()));\n menu.appendChild(createMenuItem('Add text note here', () => handleAddTextNote()));\n };\n\n // Toolbar removed - UI decluttering\n\n // Show context menu\n let lastHitTestResult: ChartGPUHitTestResult | null = null;\n\n const showContextMenu = (e: MouseEvent): void => {\n if (!contextMenu) return;\n\n lastHitTestResult = chart.hitTest(e);\n\n // Perform annotation hit test\n const rect = canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n const annotationHit = hitTester.hitTest(canvasX, canvasY);\n\n if (annotationHit) {\n // Right-clicked on an annotation - show edit/delete menu\n populateContextMenuForAnnotation(contextMenu, annotationHit.annotationIndex, annotationHit.annotation);\n } else {\n // Right-clicked on empty space - show add menu\n populateContextMenuForEmptySpace(contextMenu);\n }\n\n contextMenu.style.display = 'block';\n contextMenu.style.left = `${e.clientX}px`;\n contextMenu.style.top = `${e.clientY}px`;\n\n // Adjust position if menu goes off-screen (check both viewport bounds)\n requestAnimationFrame(() => {\n if (!contextMenu || contextMenu.style.display !== 'block') return;\n\n const menuRect = contextMenu.getBoundingClientRect();\n let adjustedX = e.clientX;\n let adjustedY = e.clientY;\n\n // Adjust horizontal position if menu extends beyond right edge\n if (menuRect.right > window.innerWidth) {\n adjustedX = Math.max(0, e.clientX - menuRect.width);\n }\n\n // Adjust vertical position if menu extends beyond bottom edge\n if (menuRect.bottom > window.innerHeight) {\n adjustedY = Math.max(0, e.clientY - menuRect.height);\n }\n\n // Apply adjustments if needed\n if (adjustedX !== e.clientX || adjustedY !== e.clientY) {\n contextMenu.style.left = `${adjustedX}px`;\n contextMenu.style.top = `${adjustedY}px`;\n }\n });\n };\n\n const hideContextMenu = (): void => {\n if (!contextMenu) return;\n contextMenu.style.display = 'none';\n lastHitTestResult = null;\n };\n\n // Compute visible x-domain for freeform vertical lines\n const computeVisibleXDomain = (): { min: number; max: number } => {\n const opts = chart.options;\n \n // Get base domain\n let xMin = opts.xAxis?.min;\n let xMax = opts.xAxis?.max;\n\n // If not explicitly set, derive from series data\n if (xMin === undefined || xMax === undefined) {\n const series = opts.series ?? [];\n let dataXMin = Number.POSITIVE_INFINITY;\n let dataXMax = Number.NEGATIVE_INFINITY;\n\n for (const s of series) {\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n // Candlestick uses timestamp (first element)\n const data = s.data;\n for (const p of data) {\n const timestamp = getOHLCTimestamp(p);\n if (timestamp < dataXMin) dataXMin = timestamp;\n if (timestamp > dataXMax) dataXMax = timestamp;\n }\n } else {\n // Cartesian series\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = s.data as ReadonlyArray<DataPoint>;\n for (const p of data) {\n const x = getPointX(p);\n if (x < dataXMin) dataXMin = x;\n if (x > dataXMax) dataXMax = x;\n }\n }\n }\n\n if (xMin === undefined) xMin = Number.isFinite(dataXMin) ? dataXMin : 0;\n if (xMax === undefined) xMax = Number.isFinite(dataXMax) ? dataXMax : 100;\n }\n\n // Apply zoom if present\n const zoomRange = chart.getZoomRange();\n if (zoomRange) {\n const span = xMax - xMin;\n const zoomMin = xMin + (zoomRange.start / 100) * span;\n const zoomMax = xMin + (zoomRange.end / 100) * span;\n return { min: zoomMin, max: zoomMax };\n }\n\n return { min: xMin, max: xMax };\n };\n\n // Compute visible y-domain for horizontal lines\n const computeVisibleYDomain = (): { min: number; max: number } => {\n const opts = chart.options;\n\n // Get base domain\n let yMin = opts.yAxis?.min;\n let yMax = opts.yAxis?.max;\n\n // If not explicitly set, derive from series data\n if (yMin === undefined || yMax === undefined) {\n const series = opts.series ?? [];\n let dataYMin = Number.POSITIVE_INFINITY;\n let dataYMax = Number.NEGATIVE_INFINITY;\n\n for (const s of series) {\n if (s.type === 'pie') continue;\n\n if (s.type === 'candlestick') {\n // Candlestick uses low/high\n const data = s.data;\n for (const p of data) {\n const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n if (low < dataYMin) dataYMin = low;\n if (high > dataYMax) dataYMax = high;\n }\n } else {\n // Cartesian series\n // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n const data = s.data as ReadonlyArray<DataPoint>;\n for (const p of data) {\n const y = getPointY(p);\n if (y < dataYMin) dataYMin = y;\n if (y > dataYMax) dataYMax = y;\n }\n }\n }\n\n if (yMin === undefined) yMin = Number.isFinite(dataYMin) ? dataYMin : 0;\n if (yMax === undefined) yMax = Number.isFinite(dataYMax) ? dataYMax : 100;\n }\n\n return { min: yMin, max: yMax };\n };\n\n // Convert grid-space coordinates to data-space x\n const gridXToDataX = (gridX: number): number => {\n const rect = canvas.getBoundingClientRect();\n const grid = chart.options.grid ?? defaultGrid;\n const plotWidthCss = rect.width - (grid.left ?? defaultGrid.left) - (grid.right ?? defaultGrid.right);\n \n const xDomain = computeVisibleXDomain();\n const t = plotWidthCss > 0 ? gridX / plotWidthCss : 0;\n return xDomain.min + t * (xDomain.max - xDomain.min);\n };\n\n // Convert grid-space coordinates to plot-space [0-1]\n const gridToPlotSpace = (gridX: number, gridY: number): { x: number; y: number } => {\n const rect = canvas.getBoundingClientRect();\n const grid = chart.options.grid ?? defaultGrid;\n const plotWidthCss = rect.width - (grid.left ?? defaultGrid.left) - (grid.right ?? defaultGrid.right);\n const plotHeightCss = rect.height - (grid.top ?? defaultGrid.top) - (grid.bottom ?? defaultGrid.bottom);\n \n const px = plotWidthCss > 0 ? gridX / plotWidthCss : 0;\n const py = plotHeightCss > 0 ? gridY / plotHeightCss : 0;\n return { x: px, y: py };\n };\n\n // Handle \"Add vertical line here\"\n const handleAddVerticalLine = (): void => {\n if (!lastHitTestResult) return;\n\n const { match, isInGrid, gridX } = lastHitTestResult;\n\n let x: number;\n if (match) {\n // Use matched data point x\n x = match.value[0];\n } else if (isInGrid) {\n // Compute x from grid position\n x = gridXToDataX(gridX);\n } else {\n return; // Outside grid, do nothing\n }\n\n // Show configuration dialog\n configDialog.showCreate(\n 'lineX',\n {\n type: 'lineX',\n x,\n layer: 'aboveSeries',\n style: {\n color: '#ffa500',\n lineWidth: 2,\n },\n },\n (config) => {\n const current = getCurrentAnnotations();\n const next = [...current, config as AnnotationConfig];\n applyAnnotations(next);\n pushHistory(next);\n },\n () => {\n // Cancelled - do nothing\n }\n );\n };\n\n // Handle \"Add horizontal line here\"\n const handleAddHorizontalLine = (): void => {\n if (!lastHitTestResult) return;\n\n const { match, isInGrid, gridY } = lastHitTestResult;\n\n let y: number;\n if (match) {\n // Use matched data point y\n y = match.value[1];\n } else if (isInGrid) {\n // Compute y from grid position using actual visible Y domain\n const rect = canvas.getBoundingClientRect();\n const grid = chart.options.grid ?? defaultGrid;\n const plotHeightCss = rect.height - (grid.top ?? defaultGrid.top) - (grid.bottom ?? defaultGrid.bottom);\n\n // Get actual visible Y domain (not hardcoded defaults!)\n const yDomain = computeVisibleYDomain();\n\n // Invert Y (canvas top = max Y value)\n const t = plotHeightCss > 0 ? 1 - gridY / plotHeightCss : 0.5;\n y = yDomain.min + t * (yDomain.max - yDomain.min);\n } else {\n return; // Outside grid, do nothing\n }\n\n // Show configuration dialog\n configDialog.showCreate(\n 'lineY',\n {\n type: 'lineY',\n y,\n layer: 'aboveSeries',\n style: {\n color: '#ffa500',\n lineWidth: 2,\n },\n },\n (config) => {\n const current = getCurrentAnnotations();\n const next = [...current, config as AnnotationConfig];\n applyAnnotations(next);\n pushHistory(next);\n },\n () => {\n // Cancelled - do nothing\n }\n );\n };\n\n // Handle \"Add text note here\"\n const handleAddTextNote = (): void => {\n if (!lastHitTestResult) return;\n\n const { match, isInGrid, gridX, gridY } = lastHitTestResult;\n\n let space: 'data' | 'plot';\n let x: number;\n let y: number;\n\n if (match) {\n // Use data-space position\n space = 'data';\n x = match.value[0];\n y = match.value[1];\n } else if (isInGrid) {\n // Use plot-space position\n const plotPos = gridToPlotSpace(gridX, gridY);\n space = 'plot';\n x = plotPos.x;\n y = plotPos.y;\n } else {\n return; // Outside grid, do nothing\n }\n\n // Show configuration dialog\n configDialog.showCreate(\n 'text',\n {\n type: 'text',\n position: { space, x, y },\n text: 'Note',\n layer: 'aboveSeries',\n style: {\n color: '#00d4ff',\n },\n },\n (config) => {\n const current = getCurrentAnnotations();\n const next = [...current, config as AnnotationConfig];\n applyAnnotations(next);\n pushHistory(next);\n },\n () => {\n // Cancelled - do nothing\n }\n );\n };\n\n // Handle \"Edit annotation...\"\n const handleEditAnnotation = (index: number, annotation: AnnotationConfig): void => {\n configDialog.showEdit(\n annotation,\n (updates) => {\n const current = getCurrentAnnotations();\n const next = current.map((a, i) => (i === index ? { ...a, ...updates } as AnnotationConfig : a));\n applyAnnotations(next);\n pushHistory(next);\n },\n () => {\n // Cancelled - do nothing\n }\n );\n };\n\n // Handle \"Delete annotation\"\n const handleDeleteAnnotation = (index: number): void => {\n const current = getCurrentAnnotations();\n const next = current.filter((_, i) => i !== index);\n applyAnnotations(next);\n pushHistory(next);\n };\n\n // Pointer down event handler for drag\n const onPointerDown = (e: PointerEvent): void => {\n if (disposed || e.button === 2) return; // Ignore right-click\n\n const rect = canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n const annotationHit = hitTester.hitTest(canvasX, canvasY);\n\n if (annotationHit) {\n e.preventDefault();\n // Don't set pointer capture here - let drag handler manage window-level events\n\n dragHandler.startDrag(\n annotationHit.annotationIndex,\n annotationHit.annotation,\n e.clientX,\n e.clientY\n );\n }\n };\n\n // Context menu event handler\n const onContextMenu = (e: MouseEvent): void => {\n if (disposed || !enableContextMenu) return;\n e.preventDefault();\n e.stopPropagation();\n showContextMenu(e);\n };\n\n // Click outside to close context menu\n const onDocumentClick = (e: MouseEvent): void => {\n if (disposed) return;\n if (contextMenu && !contextMenu.contains(e.target as Node)) {\n hideContextMenu();\n }\n };\n\n // Escape to close context menu\n const onDocumentKeyDown = (e: KeyboardEvent): void => {\n if (disposed) return;\n if (e.key === 'Escape' && contextMenu && contextMenu.style.display === 'block') {\n hideContextMenu();\n }\n };\n\n // Scroll/resize to close context menu (prevents menu from floating at wrong position)\n const onWindowScrollOrResize = (): void => {\n if (disposed) return;\n if (contextMenu && contextMenu.style.display === 'block') {\n hideContextMenu();\n }\n };\n\n // Public API\n const addVerticalLine = (x: number): void => {\n const current = getCurrentAnnotations();\n const newAnnotation: AnnotationConfig = {\n type: 'lineX',\n x,\n layer: 'aboveSeries',\n style: {\n color: '#ffa500',\n lineWidth: 2,\n opacity: 0.9,\n },\n };\n const next = [...current, newAnnotation];\n applyAnnotations(next);\n pushHistory(next);\n };\n\n const addTextNote = (x: number, y: number, text: string, space: 'data' | 'plot' = 'data'): void => {\n const current = getCurrentAnnotations();\n const newAnnotation: AnnotationConfig = {\n type: 'text',\n position: { space, x, y },\n text,\n layer: 'aboveSeries',\n style: {\n color: '#00d4ff',\n opacity: 1,\n },\n };\n const next = [...current, newAnnotation];\n applyAnnotations(next);\n pushHistory(next);\n };\n\n const undo = (): boolean => {\n if (historyIndex <= 0) return false;\n historyIndex--;\n const entry = history[historyIndex];\n if (!entry) return false;\n applyAnnotations(entry.annotations);\n return true;\n };\n\n const redo = (): boolean => {\n if (historyIndex >= history.length - 1) return false;\n historyIndex++;\n const entry = history[historyIndex];\n if (!entry) return false;\n applyAnnotations(entry.annotations);\n return true;\n };\n\n const exportJSON = (): string => {\n const annotations = getCurrentAnnotations();\n return JSON.stringify(annotations, null, 2);\n };\n\n const getAnnotations = (): readonly AnnotationConfig[] => {\n return getCurrentAnnotations();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n\n canvas.removeEventListener('pointerdown', onPointerDown);\n canvas.removeEventListener('contextmenu', onContextMenu);\n document.removeEventListener('click', onDocumentClick);\n document.removeEventListener('keydown', onDocumentKeyDown);\n window.removeEventListener('scroll', onWindowScrollOrResize, true);\n window.removeEventListener('resize', onWindowScrollOrResize);\n\n contextMenu?.remove();\n contextMenu = null;\n\n hitTester.dispose();\n dragHandler.dispose();\n configDialog.dispose();\n\n history = [];\n };\n\n // Initialize\n if (enableContextMenu) {\n contextMenu = createContextMenu();\n canvas.addEventListener('contextmenu', onContextMenu);\n document.addEventListener('click', onDocumentClick);\n document.addEventListener('keydown', onDocumentKeyDown);\n // Capture phase for scroll to handle all scrollable ancestors\n window.addEventListener('scroll', onWindowScrollOrResize, true);\n window.addEventListener('resize', onWindowScrollOrResize);\n }\n\n // Attach pointer event for dragging (always enabled)\n canvas.addEventListener('pointerdown', onPointerDown);\n\n return {\n addVerticalLine,\n addTextNote,\n undo,\n redo,\n exportJSON,\n getAnnotations,\n dispose,\n };\n}\n","/**\n * RenderScheduler - 60fps render loop management\n * \n * Manages a requestAnimationFrame-based render loop that runs at 60fps,\n * providing delta time tracking and frame scheduling control.\n * \n * This module provides both functional and class-based APIs for maximum flexibility.\n * The functional API is preferred for better type safety and immutability.\n */\n\n/**\n * Callback function type for render frames.\n * Receives delta time in milliseconds since the last frame.\n */\nexport type RenderCallback = (deltaTime: number) => void;\n\nimport type { ExactFPS, Milliseconds, FrameTimeStats, FrameDropStats } from '../config/types';\n\n/**\n * Represents the state of a render scheduler.\n * All properties are readonly to ensure immutability.\n */\nexport interface RenderSchedulerState {\n readonly id: symbol;\n readonly running: boolean;\n}\n\n/**\n * Circular buffer for frame timestamps (120 frames = 2 seconds at 60fps).\n * Uses Float64Array for high-precision timestamps from performance.now().\n */\nconst FRAME_BUFFER_SIZE = 120;\n\n/**\n * Expected frame time at 60fps (16.67ms).\n * Used for frame drop detection.\n */\nconst EXPECTED_FRAME_TIME_MS = 1000 / 60;\n\n/**\n * Frame drop threshold multiplier (1.5x expected frame time).\n * Frame times exceeding this are counted as drops.\n */\nconst FRAME_DROP_THRESHOLD_MULTIPLIER = 1.5;\n\n/**\n * Internal mutable state for the render scheduler.\n * Stored separately from the public state interface.\n */\ninterface RenderSchedulerInternalState {\n rafId: number | null;\n callback: RenderCallback | null;\n lastFrameTime: number;\n dirty: boolean;\n frameHandler: ((time: number) => void) | null;\n \n // Performance tracking\n frameTimestamps: Float64Array;\n frameTimestampIndex: number;\n frameTimestampCount: number;\n totalFrames: number;\n totalDroppedFrames: number;\n consecutiveDroppedFrames: number;\n lastDropTimestamp: number;\n startTime: number;\n}\n\n/**\n * Map to store internal mutable state for each scheduler state instance.\n * Keyed by the state's unique ID symbol.\n */\nconst internalStateMap = new Map<symbol, RenderSchedulerInternalState>();\n\n/**\n * Creates a new RenderScheduler state with initial values.\n * \n * @returns A new RenderSchedulerState instance\n */\nexport function createRenderScheduler(): RenderSchedulerState {\n const id = Symbol('RenderScheduler');\n const state: RenderSchedulerState = {\n id,\n running: false,\n };\n\n // Initialize internal mutable state\n internalStateMap.set(id, {\n rafId: null,\n callback: null,\n lastFrameTime: 0,\n dirty: false,\n frameHandler: null,\n \n // Performance tracking\n frameTimestamps: new Float64Array(FRAME_BUFFER_SIZE),\n frameTimestampIndex: 0,\n frameTimestampCount: 0,\n totalFrames: 0,\n totalDroppedFrames: 0,\n consecutiveDroppedFrames: 0,\n lastDropTimestamp: 0,\n startTime: performance.now(),\n });\n\n return state;\n}\n\n/**\n * Starts the render loop.\n * \n * Begins a requestAnimationFrame loop that calls the provided callback\n * every frame with the delta time in milliseconds since the last frame.\n * Returns a new state object with running set to true.\n * \n * @param state - The scheduler state to start\n * @param callback - Function to call each frame with delta time\n * @returns A new RenderSchedulerState with running set to true\n * @throws {Error} If callback is not provided\n * @throws {Error} If scheduler is already running\n * @throws {Error} If state is invalid\n */\nexport function startRenderScheduler(\n state: RenderSchedulerState,\n callback: RenderCallback\n): RenderSchedulerState {\n if (!callback) {\n throw new Error('Render callback is required');\n }\n\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n throw new Error('Invalid scheduler state. Use createRenderScheduler() to create a new state.');\n }\n\n if (state.running) {\n throw new Error('RenderScheduler is already running. Call stopRenderScheduler() before starting again.');\n }\n\n // Update internal state\n internalState.callback = callback;\n internalState.lastFrameTime = performance.now();\n internalState.dirty = true;\n\n const schedulerId = state.id;\n const frameHandler = (currentTime: number) => {\n // Look up internal state - may be null if scheduler was destroyed\n const currentInternalState = internalStateMap.get(schedulerId);\n if (!currentInternalState || !currentInternalState.callback) {\n // Scheduler was stopped or destroyed, exit gracefully\n return;\n }\n\n // Clear rafId at the start - we are no longer scheduled (now idle)\n currentInternalState.rafId = null;\n\n // Record frame timestamp in circular buffer BEFORE rendering\n // Use performance.now() exclusively for exact FPS measurement\n const timestamp = performance.now();\n currentInternalState.frameTimestamps[currentInternalState.frameTimestampIndex] = timestamp;\n currentInternalState.frameTimestampIndex = (currentInternalState.frameTimestampIndex + 1) % FRAME_BUFFER_SIZE;\n if (currentInternalState.frameTimestampCount < FRAME_BUFFER_SIZE) {\n currentInternalState.frameTimestampCount++;\n }\n currentInternalState.totalFrames++;\n\n // Calculate deltaTime with capping to prevent animation jumps after idle\n let deltaTime = currentTime - currentInternalState.lastFrameTime;\n // Cap deltaTime to 100ms (1/10th second) to prevent huge jumps\n const MAX_DELTA_TIME = 100;\n if (deltaTime > MAX_DELTA_TIME) {\n deltaTime = MAX_DELTA_TIME;\n }\n\n // Frame drop detection (only after first frame)\n if (currentInternalState.lastFrameTime > 0 && deltaTime > EXPECTED_FRAME_TIME_MS * FRAME_DROP_THRESHOLD_MULTIPLIER) {\n currentInternalState.totalDroppedFrames++;\n currentInternalState.consecutiveDroppedFrames++;\n currentInternalState.lastDropTimestamp = timestamp;\n } else if (currentInternalState.lastFrameTime > 0) {\n // Reset consecutive counter on successful frame\n currentInternalState.consecutiveDroppedFrames = 0;\n }\n\n currentInternalState.lastFrameTime = currentTime;\n\n // Only render if dirty\n if (currentInternalState.dirty) {\n // Reset dirty flag BEFORE calling callback\n currentInternalState.dirty = false;\n\n // Call the render callback with delta time\n currentInternalState.callback(deltaTime);\n\n // After callback returns, check if dirty was set again (callback-triggered renders for animations)\n // Re-check internal state in case it was destroyed during callback execution\n const nextInternalState = internalStateMap.get(schedulerId);\n if (nextInternalState && nextInternalState.callback && nextInternalState.dirty) {\n // Schedule another frame since callback requested a render\n nextInternalState.rafId = requestAnimationFrame(frameHandler);\n }\n }\n // If not dirty, we remain idle (rafId stays null, no frame scheduled)\n };\n\n // Store frameHandler in internal state so requestRender() can access it\n internalState.frameHandler = frameHandler;\n\n // Start the first frame\n internalState.rafId = requestAnimationFrame(frameHandler);\n\n // Return new state with running set to true\n return {\n id: state.id,\n running: true,\n };\n}\n\n/**\n * Stops the render loop.\n * \n * Cancels any pending requestAnimationFrame calls and stops the loop.\n * Returns a new state object with running set to false.\n * The scheduler can be restarted by calling startRenderScheduler() again.\n * \n * @param state - The scheduler state to stop\n * @returns A new RenderSchedulerState with running set to false\n * @throws {Error} If state is invalid\n */\nexport function stopRenderScheduler(state: RenderSchedulerState): RenderSchedulerState {\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n throw new Error('Invalid scheduler state. Use createRenderScheduler() to create a new state.');\n }\n\n internalState.callback = null;\n internalState.frameHandler = null;\n\n if (internalState.rafId !== null) {\n cancelAnimationFrame(internalState.rafId);\n internalState.rafId = null;\n }\n\n // Return new state with running set to false\n return {\n id: state.id,\n running: false,\n };\n}\n\n/**\n * Marks the current frame as dirty and schedules a render if idle.\n * \n * This function implements render-on-demand: it schedules a frame when the\n * scheduler is idle. Multiple calls coalesce into a single frame.\n * \n * @param state - The scheduler state\n * @throws {Error} If state is invalid\n */\nexport function requestRender(state: RenderSchedulerState): void {\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n throw new Error('Invalid scheduler state. Use createRenderScheduler() to create a new state.');\n }\n\n // Mark as dirty\n internalState.dirty = true;\n\n // If not running, return early\n if (internalState.callback === null) {\n return;\n }\n\n // If already scheduled, return early (coalescing)\n if (internalState.rafId !== null) {\n return;\n }\n\n // Idle - schedule a frame\n // Reset lastFrameTime to current time to ensure reasonable deltaTime after idle\n internalState.lastFrameTime = performance.now();\n \n // Schedule RAF using the stored frameHandler\n if (internalState.frameHandler) {\n internalState.rafId = requestAnimationFrame(internalState.frameHandler);\n }\n}\n\n/**\n * Calculates exact FPS from frame timestamp deltas.\n * \n * Uses the circular buffer of performance.now() timestamps to calculate\n * frame-perfect FPS. Algorithm:\n * 1. Sum all frame time deltas in the buffer\n * 2. Divide by (count - 1) to get average frame time\n * 3. Convert to FPS: 1000ms / avg_frame_time\n * \n * Returns 0 if insufficient data (< 2 frames).\n * \n * @param state - The scheduler state\n * @returns Exact FPS measurement\n */\nexport function getCurrentFPS(state: RenderSchedulerState): ExactFPS {\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n return 0 as ExactFPS;\n }\n\n const count = internalState.frameTimestampCount;\n if (count < 2) {\n return 0 as ExactFPS; // Need at least 2 frames to calculate FPS\n }\n\n // Calculate sum of deltas between consecutive timestamps\n const timestamps = internalState.frameTimestamps;\n const bufferSize = FRAME_BUFFER_SIZE;\n const startIndex = (internalState.frameTimestampIndex - count + bufferSize) % bufferSize;\n \n let totalDelta = 0;\n for (let i = 1; i < count; i++) {\n const prevIndex = (startIndex + i - 1) % bufferSize;\n const currIndex = (startIndex + i) % bufferSize;\n const delta = timestamps[currIndex] - timestamps[prevIndex];\n totalDelta += delta;\n }\n\n const avgFrameTime = totalDelta / (count - 1);\n const fps = avgFrameTime > 0 ? 1000 / avgFrameTime : 0;\n \n return fps as ExactFPS;\n}\n\n/**\n * Calculates frame time statistics from the circular buffer.\n * \n * Computes min, max, avg, and percentiles (p50, p95, p99) for frame times.\n * Returns zero stats if insufficient data.\n * \n * @param state - The scheduler state\n * @returns Frame time statistics\n */\nexport function getFrameStats(state: RenderSchedulerState): FrameTimeStats {\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n return {\n min: 0 as Milliseconds,\n max: 0 as Milliseconds,\n avg: 0 as Milliseconds,\n p50: 0 as Milliseconds,\n p95: 0 as Milliseconds,\n p99: 0 as Milliseconds,\n };\n }\n\n const count = internalState.frameTimestampCount;\n if (count < 2) {\n return {\n min: 0 as Milliseconds,\n max: 0 as Milliseconds,\n avg: 0 as Milliseconds,\n p50: 0 as Milliseconds,\n p95: 0 as Milliseconds,\n p99: 0 as Milliseconds,\n };\n }\n\n // Extract deltas from circular buffer\n const timestamps = internalState.frameTimestamps;\n const bufferSize = FRAME_BUFFER_SIZE;\n const startIndex = (internalState.frameTimestampIndex - count + bufferSize) % bufferSize;\n \n const deltas = new Array<number>(count - 1);\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n let sum = 0;\n \n for (let i = 1; i < count; i++) {\n const prevIndex = (startIndex + i - 1) % bufferSize;\n const currIndex = (startIndex + i) % bufferSize;\n const delta = timestamps[currIndex] - timestamps[prevIndex];\n deltas[i - 1] = delta;\n \n if (delta < min) min = delta;\n if (delta > max) max = delta;\n sum += delta;\n }\n\n const avg = sum / deltas.length;\n\n // Sort for percentile calculations\n deltas.sort((a, b) => a - b);\n\n const p50Index = Math.floor(deltas.length * 0.50);\n const p95Index = Math.floor(deltas.length * 0.95);\n const p99Index = Math.floor(deltas.length * 0.99);\n\n return {\n min: min as Milliseconds,\n max: max as Milliseconds,\n avg: avg as Milliseconds,\n p50: deltas[p50Index] as Milliseconds,\n p95: deltas[p95Index] as Milliseconds,\n p99: deltas[p99Index] as Milliseconds,\n };\n}\n\n/**\n * Gets frame drop statistics for the scheduler.\n * \n * @param state - The scheduler state\n * @returns Frame drop statistics\n */\nexport function getFrameDropStats(state: RenderSchedulerState): FrameDropStats {\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n return {\n totalDrops: 0,\n consecutiveDrops: 0,\n lastDropTimestamp: 0 as Milliseconds,\n };\n }\n\n return {\n totalDrops: internalState.totalDroppedFrames,\n consecutiveDrops: internalState.consecutiveDroppedFrames,\n lastDropTimestamp: internalState.lastDropTimestamp as Milliseconds,\n };\n}\n\n/**\n * Gets total frames rendered and elapsed time.\n * \n * @param state - The scheduler state\n * @returns Object with totalFrames and elapsedTime\n */\nexport function getTotalFrames(state: RenderSchedulerState): { totalFrames: number; elapsedTime: Milliseconds } {\n const internalState = internalStateMap.get(state.id);\n if (!internalState) {\n return { totalFrames: 0, elapsedTime: 0 as Milliseconds };\n }\n\n const elapsedTime = performance.now() - internalState.startTime;\n return {\n totalFrames: internalState.totalFrames,\n elapsedTime: elapsedTime as Milliseconds,\n };\n}\n\n/**\n * Destroys the render scheduler and cleans up resources.\n * Stops the loop if running and removes internal state from the map.\n * Returns a new state object with reset values.\n * After calling this, the scheduler must be recreated before use.\n * \n * **Important:** Always call this function when done with a scheduler to prevent memory leaks.\n * The internal state map will retain entries until explicitly destroyed.\n * \n * @param state - The scheduler state to destroy\n * @returns A new RenderSchedulerState with reset values\n */\nexport function destroyRenderScheduler(state: RenderSchedulerState): RenderSchedulerState {\n const internalState = internalStateMap.get(state.id);\n \n if (internalState) {\n // Stop the loop if running\n if (internalState.rafId !== null) {\n cancelAnimationFrame(internalState.rafId);\n internalState.rafId = null;\n }\n \n // Clear callback and frameHandler to prevent further execution\n internalState.callback = null;\n internalState.frameHandler = null;\n \n // Clean up internal state from map to prevent memory leak\n internalStateMap.delete(state.id);\n }\n\n // Return new state with reset values\n return createRenderScheduler();\n}\n\n/**\n * Convenience function that creates a scheduler and starts it in one step.\n * \n * @param callback - Function to call each frame with delta time\n * @returns A RenderSchedulerState with the loop running\n * @throws {Error} If callback is not provided\n * \n * @example\n * ```typescript\n * const scheduler = createRenderSchedulerAsync((deltaTime) => {\n * renderFrame(deltaTime);\n * });\n * ```\n */\nexport function createRenderSchedulerAsync(callback: RenderCallback): RenderSchedulerState {\n const state = createRenderScheduler();\n return startRenderScheduler(state, callback);\n}\n\n/**\n * RenderScheduler class wrapper for backward compatibility.\n * \n * This class provides a class-based API that internally uses the functional implementation.\n * Use the functional API directly for better type safety and immutability.\n */\nexport class RenderScheduler {\n private _state: RenderSchedulerState;\n\n /**\n * Checks if the scheduler is currently running.\n */\n get running(): boolean {\n return this._state.running;\n }\n\n /**\n * Creates a new RenderScheduler instance.\n */\n constructor() {\n this._state = createRenderScheduler();\n }\n\n /**\n * Starts the render loop.\n * \n * @param callback - Function to call each frame with delta time\n * @throws {Error} If callback is not provided or scheduler already running\n */\n start(callback: RenderCallback): void {\n this._state = startRenderScheduler(this._state, callback);\n }\n\n /**\n * Stops the render loop.\n */\n stop(): void {\n this._state = stopRenderScheduler(this._state);\n }\n\n /**\n * Marks the current frame as dirty, indicating it needs to be rendered.\n */\n requestRender(): void {\n requestRender(this._state);\n }\n\n /**\n * Destroys the render scheduler and cleans up resources.\n * After calling destroy(), the scheduler must be recreated before use.\n */\n destroy(): void {\n this._state = destroyRenderScheduler(this._state);\n }\n}\n","/**\n * ChartGPU - A GPU-accelerated charting library built with WebGPU\n */\n\nexport const version = '1.0.0';\n\n// Chart API (Phase 1)\nimport { ChartGPU as ChartGPUNamespace } from './ChartGPU';\n\n// Export ChartGPU namespace\nexport const ChartGPU = ChartGPUNamespace;\n\nexport { createChartGPU as createChart } from './ChartGPU';\nexport type { ChartGPUInstance } from './ChartGPU';\nexport type {\n ChartGPUEventName,\n ChartGPUEventPayload,\n ChartGPUCrosshairMovePayload,\n ChartGPUEventCallback,\n ChartGPUCrosshairMoveCallback,\n ChartGPUHitTestMatch,\n ChartGPUHitTestResult,\n} from './ChartGPU';\nexport type {\n AnnotationConfig,\n AnnotationConfigBase,\n AnnotationLabel,\n AnnotationLabelAnchor,\n AnnotationLabelBackground,\n AnnotationLabelPadding,\n AnnotationLayer,\n AnnotationLineX,\n AnnotationLineY,\n AnnotationPoint,\n AnnotationPointMarker,\n AnnotationPosition,\n AnnotationStyle,\n AnnotationText,\n AreaStyleConfig,\n AnimationConfig,\n AxisConfig,\n AxisType,\n BarItemStyleConfig,\n CandlestickItemStyleConfig,\n CandlestickSeriesConfig,\n CandlestickStyle,\n ChartGPUOptions,\n DataZoomConfig,\n DataPoint,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineStyleConfig,\n AreaSeriesConfig,\n LineSeriesConfig,\n BarSeriesConfig,\n PerformanceMetrics,\n OHLCDataPoint,\n PieCenter,\n PieDataItem,\n PieItemStyleConfig,\n PieRadius,\n PieSeriesConfig,\n ScatterSeriesConfig,\n ScatterSymbol,\n ScatterPointTuple,\n SeriesConfig,\n SeriesSampling,\n SeriesType,\n TooltipConfig,\n TooltipParams,\n} from './config/types';\n\n// Options defaults + resolution\nexport { candlestickDefaults, defaultOptions } from './config/defaults';\nexport { OptionResolver, resolveOptions } from './config/OptionResolver';\nexport type {\n ResolvedCandlestickSeriesConfig,\n ResolvedChartGPUOptions,\n ResolvedAreaSeriesConfig,\n ResolvedAreaStyleConfig,\n ResolvedGridConfig,\n ResolvedLineSeriesConfig,\n ResolvedLineStyleConfig,\n ResolvedPieDataItem,\n ResolvedPieSeriesConfig,\n ResolvedSeriesConfig,\n} from './config/OptionResolver';\n\n// Themes\nexport type { ThemeConfig } from './themes/types';\nexport { darkTheme, lightTheme, getTheme } from './themes';\nexport type { ThemeName } from './themes';\n\n// Scales - Pure utilities\nexport { createLinearScale, createCategoryScale } from './utils/scales';\nexport type { LinearScale, CategoryScale } from './utils/scales';\n\n// Chart sync (interaction)\nexport { connectCharts } from './interaction/createChartSync';\n\n// Annotation authoring (interaction)\nexport { createAnnotationAuthoring } from './interaction/createAnnotationAuthoring';\nexport type { AnnotationAuthoringInstance, AnnotationAuthoringOptions } from './interaction/createAnnotationAuthoring';\n\n// Core exports - Functional API (preferred)\nexport type {\n GPUContextState,\n GPUContextOptions,\n SupportedCanvas,\n} from './core/GPUContext';\nexport {\n createGPUContext,\n createGPUContextAsync,\n initializeGPUContext,\n getCanvasTexture,\n clearScreen,\n destroyGPUContext,\n} from './core/GPUContext';\n\n// Class-based API (for backward compatibility)\nexport { GPUContext } from './core/GPUContext';\n\n// Render scheduler - Functional API (preferred)\nexport type { RenderSchedulerState, RenderCallback } from './core/RenderScheduler';\nexport {\n createRenderScheduler,\n createRenderSchedulerAsync,\n startRenderScheduler,\n stopRenderScheduler,\n requestRender,\n destroyRenderScheduler,\n} from './core/RenderScheduler';\n\n// Class-based API (for backward compatibility)\nexport { RenderScheduler } from './core/RenderScheduler';\n"],"names":["isHTMLCanvasElement","canvas","getCanvasDimensions","width","height","createGPUContext","options","dprRaw","dpr","alphaMode","powerPreference","initializeGPUContext","context","sanitizedDevicePixelRatio","device","adapter","event","canvasContext","preferredFormat","webgpuContext","error","targetWidth","targetHeight","maxDim","finalWidth","finalHeight","_b","_a","destroyError","getCanvasTexture","clearScreen","r","g","b","a","texture","encoder","destroyGPUContext","createGPUContextAsync","GPUContext","isTupleDataPoint","point","packDataPoints","points","MAX_POINTS","buffer","f32","i","x","y","MIN_BUFFER_BYTES","roundUpToMultipleOf4","bytes","nextPow2","n","computeGrownCapacityBytes","currentCapacityBytes","requiredBytes","required","grown","fnv1aUpdate","hash","words","h","hashFloat32ArrayBits","data","u32","createDataStore","series","disposed","p","packDataPointsWithXOffset","xOffset","assertNotDisposed","getSeriesEntry","index","entry","packed","pointCount","hash32","targetBytes","existing","capacityBytes","maxBufferSize","grownCapacityBytes","newPoints","prevPointCount","nextPointCount","appendPacked","appendBytes","nextData","fullPacked","byteOffset","appendWords","nextHash32","lttbIndicesForInterleavedXY","targetPoints","lastIndex","indices","bucketSize","out","lastX","lastY","bucket","rangeStart","rangeEndExclusive","nextRangeStart","nextRangeEndExclusive","avgX","avgY","sumX","sumY","avgCount","ax","ay","maxArea","maxIndex","bx","by","area2","absArea2","lttbIndicesForDataPoints","pLast","pa","pb","lttbSample","threshold","idx","isXYArraysData","isInterleavedXYData","getPointCount","getX","getY","getSize","computeRawBoundsFromCartesianData","xMin","xMax","yMin","yMax","count","clampTargetPoints","packToFloat32Array","sampleByBucketsFromCartesian","mode","size","getPointSize","x0","y0","size0","xLast","yLast","sizeLast","chosen","sumSize","sizeCount","bestY","bestIndex","sampleSeriesDataPoints","sampling","samplingThreshold","isTupleOHLCDataPoint","ohlcSample","isTuple","dataAsTuples","firstCandle","lastCandle","timestamp","open","close","high","low","candle","candleLow","candleHigh","dataAsObjects","getCanvasCssWidth","getCanvasCssHeight","clampInt","v","lo","hi","monotonicXCache","monotonicTimestampCache","isMonotonicNonDecreasingFiniteX","cacheKey","cached","prevX","isMonotonicNonDecreasingFiniteTimestamp","prevTimestamp","lowerBoundX","xTarget","mid","upperBoundX","lowerBoundTimestampTuple","timestampTarget","upperBoundTimestampTuple","lowerBoundTimestampObject","upperBoundTimestampObject","sliceCartesianData","start","end","s","e","TypedArrayConstructor","xSliced","ySliced","result","sizeSliced","sliceVisibleRangeByX","findVisibleRangeIndicesByX","sliceVisibleRangeByOHLC","canBinarySearch","clamp01","clamp255","parseHexNibble","hex","parseHexByte","parseHexColorToRgba01","color","c","parseRgbNumberOrPercent","token","parseAlphaNumberOrPercent","parseRgbFuncToRgba01","m","fn","parts","parseCssColorToRgba01","rgb","parseCssColorToGPUColor","fallback","rgba","finiteOrUndefined","assertUnreachable","value","getPointXY","computePlotScissorDevicePx","gridArea","canvasWidth","canvasHeight","devicePixelRatio","plotLeftDevice","plotRightDevice","plotTopDevice","plotBottomDevice","scissorX","scissorY","scissorR","scissorB","scissorW","scissorH","clipXToCanvasCssPx","xClip","canvasCssWidth","clipYToCanvasCssPx","yClip","canvasCssHeight","MS_PER_DAY","MS_PER_MONTH_APPROX","MS_PER_YEAR_APPROX","MONTH_SHORT_EN","parseNumberOrPercent","basis","pct","isPieRadiusTuple","radius","resolvePieRadiiCss","maxRadiusCss","inner","outer","innerCss","outerCss","pad2","formatTimeTickValue","timestampMs","visibleRangeMs","d","yyyy","mm","dd","hh","min","DEFAULT_MAX_TICK_FRACTION_DIGITS","computeMaxFractionDigitsFromStep","tickStep","cap","stepAbs","scaled","rounded","err","tol","createTickFormatter","maximumFractionDigits","formatTickValue","nf","normalized","formatted","getAxisTitleFontSize","baseFontSize","DEFAULT_TICK_LENGTH_CSS_PX","LABEL_PADDING_CSS_PX","DEFAULT_TICK_COUNT","styleAxisLabelSpan","span","isTitle","theme","renderAxisLabels","axisLabelOverlay","overlayContainer","gpuContext","currentOptions","xScale","yScale","xTickValues","plotClipRect","visibleXRangeMs","offsetX","offsetY","plotLeftCss","plotRightCss","plotTopCss","plotBottomCss","xTickLengthCssPx","xLabelY","isTimeXAxis","xFormatter","xDomainMin","xDomainMax","xTickCount","xTickStep","xCss","anchor","label","yTickCount","yTickLengthCssPx","yDomainMin","yDomainMax","yTickStep","yFormatter","yLabelX","ySpans","t","yCss","axisNameFontSize","xAxisName","xCenter","xTickLabelsBottom","bottomLimitCss","z","xTitleY","yAxisName","_c","maxTickLabelWidth","max","yCenter","yTitleX","toCssRgba","opacity01","base","formatNumber","decimals","templateRegex","renderTemplate","template","values","_m","key","mapAnchor","renderAnnotationLabels","annotationOverlay","canvasCssWidthForAnnotations","canvasCssHeightForAnnotations","plotWidthCss","plotHeightCss","annotations","labelCfg","anchorXCss","anchorYCss","dx","dy","text","defaultTemplate","trimmed","fontSize","bg","bgColor","padding","borderRadius","labelData","l","DEFAULT_MAX_DISTANCE_PX","DEFAULT_BAR_GAP","DEFAULT_BAR_CATEGORY_GAP","DEFAULT_SCATTER_RADIUS_CSS_PX","isPointInBar","barBounds","parsePercent","normalizeStackId","stack","getPointSizeCssPx","toScatterTuple","safeCallSymbolSize","getScatterRadiusCssPx","seriesCfg","perPoint","seriesSymbolSize","computeBarClusterSlots","seriesConfigs","stackIdToClusterIndex","clusterIndexBySeries","stackIdBySeries","clusterCount","stackId","computeBarCategoryStep","xs","minStep","computeCategoryWidthPx","categoryStep","p0","p1","w","sx","px","minDx","computeSharedBarLayout","barWidth","barGap","barCategoryGap","computeBarLayoutPx","clusterSlots","categoryWidthPx","layout","categoryInnerWidthPx","denom","maxBarWidthPx","barWidthPx","rawBarWidth","gapPx","clusterWidthPx","computeBaselineForBarsFromData","inferPlotHeightPxForBarHitTesting","maxY","py","computeBaselineDomainAndPx","plotHeightPx","yDomainA","yDomainB","baselineDomain","baselinePx","bucketStackedXKey","xCenterPx","xDomain","findNearestPoint","maxDistance","md","maxDistSq","bestSeriesIndex","bestDataIndex","bestPoint","bestDistSq","barSeriesConfigs","barSeriesIndexByBar","cfg","layoutPx","stackSumsByStackId","bestBarHit","originalSeriesIndex","clusterIndex","yDomain","left","right","baseDomain","topDomain","sumsForX","xKey","sums","basePx","topPx","bounds","seriesData","cartesianSeriesConfigs","cartesianSeriesIndexMap","scatterCfg","startIdx","sy","distSq","allowedSq","allowed","DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX","DEFAULT_HIGHLIGHT_SIZE_CSS_PX","prepareOverlays","renderers","hasCartesianSeries","effectivePointer","interactionScales","seriesForRender","withAlpha","crosshairOptions","match","xGridCss","yGridCss","centerCssX","centerCssY","plotScissor","seriesColor","resolveAnnotationRgba","opacity","defaultColor","o","processAnnotations","plotBounds","linesBelow","linesAbove","markersBelow","markersAbove","labels","layer","targetLines","targetMarkers","styleColor","styleOpacity","lineWidth","lineDash","_d","markerSize","_e","markerColor","_g","_f","_h","markerOpacity","_j","_i","_k","fillRgba","_l","_n","shouldRenderArea","prepareSeries","dataStore","appendedGpuThisFrame","gpuSeriesKindByIndex","zoomState","visibleXDomain","introPhase","introProgress01","defaultBaseline","introP","baseline","k","zoomRange","areaLike","rawData","visible","animated","radiiCss","_exhaustive","visibleSeriesForRender","visibleBarSeriesConfigs","encodeScatterDensityCompute","renderSeries","annotationRenderers","prepResult","mainPass","referenceLineBelowCount","markerBelowCount","originalIndex","renderAboveSeriesAnnotations","overlayPass","referenceLineAboveCount","markerAboveCount","firstLine","firstMarker","gridWgsl","DEFAULT_VERTEX_ENTRY","DEFAULT_FRAGMENT_ENTRY","isPowerOfTwo","alignTo","alignment","getStageModule","stage","createShaderModule","code","createRenderPipeline","config","vertexStage","vertexEntryPoint","fragment","fragmentStage","fragmentEntryPoint","targets","formats","format","primitive","multisample","createUniformBuffer","alignedSize","maxSize","writeUniformBuffer","src","DEFAULT_TARGET_FORMAT","DEFAULT_AXIS_RGBA","createIdentityMat4Buffer","isFiniteGridArea","normalizeDomain","minCandidate","maxCandidate","generateAxisVertices","axisConfig","scale","orientation","tickCountOverride","top","bottom","plotLeft","plotRight","plotTop","plotBottom","plotLeftClip","plotRightClip","plotTopClip","plotBottomClip","tickLengthCssPx","tickCountRaw","tickCount","tickLengthDevicePx","tickDeltaClipX","tickDeltaClipY","domainMinRaw","domainMaxRaw","domain","domainMin","domainMax","totalSegments","vertices","y1","x1","createAxisRenderer","targetFormat","bindGroupLayout","vsUniformBuffer","fsUniformBufferLine","fsUniformBufferTick","bindGroupLine","bindGroupTick","pipeline","vertexBuffer","vertexCount","axisLineColor","axisTickColor","requiredSize","bufferSize","axisLineColorString","axisTickColorString","axisLineRgba","axisTickRgba","lineColorBuffer","tickColorBuffer","passEncoder","DEFAULT_HORIZONTAL_LINES","DEFAULT_VERTICAL_LINES","DEFAULT_GRID_COLOR","DEFAULT_GRID_RGBA","generateGridVertices","horizontal","vertical","plotWidth","plotHeight","totalLines","yDevice","xClipLeft","xClipRight","yClipTop","yClipBottom","createGridRenderer","fsUniformBuffer","bindGroup","lineCountOrOptions","isOptionsObject","lineCount","colorString","transformBuffer","colorBuffer","areaWgsl","parseSeriesColorToRgba01","computeDataBounds","computeClipAffineFromScale","v0","v1","writeTransformMat4F32","createAreaVertices","createAreaRenderer","vsUniformScratchBuffer","vsUniformScratchF32","fsUniformScratchF32","writeVsUniforms","seriesConfig","baselineValue","lineWgsl","createLineRenderer","currentVertexBuffer","currentVertexCount","dataBuffer","dataArray","bxAdjusted","barWgsl","INSTANCE_STRIDE_BYTES","INSTANCE_STRIDE_FLOATS","computePlotSizeCssPx","computePlotClipRect","computeCategoryWidthClip","fallbackCategoryCount","clipWidth","createBarRenderer","instanceBuffer","instanceCount","cpuInstanceStagingBuffer","cpuInstanceStagingF32","categoryXScratch","ensureCpuInstanceCapacityFloats","requiredFloats","nextFloats","computeBaselineForBarsFromAxis","plotSize","plotClipWidth","clipPerCssX","dataLength","categoryWidthClip","categoryInnerWidthClip","maxBarWidthClip","barWidthClip","gapClip","clusterWidthClip","baselineClip","fallbackBaselineDomain","maxBars","outFloats","seriesIndex","xClipCenter","baseClip","bClip","tClip","grownBytes","scatterWgsl","createScatterRenderer","lastCanvasWidth","lastCanvasHeight","lastViewportPx","lastScissor","viewportW","viewportH","hasValidDpr","getSeriesSizeCssPx","sizeCss","radiusCss","radiusDevicePx","scatterDensityBinningWgsl","scatterDensityColormapWgsl","lerp","lerpRgba","parseColorStop","css","getNamedStops","name","buildLutRGBA8","colormap","stops","seg","localT","colormapKey","normalizationToU32","createScatterDensityRenderer","computeBindGroupLayout","renderBindGroupLayout","computeUniformBuffer","computeUniformScratch","computeUniformF32","computeUniformU32","renderUniformBuffer","renderUniformScratch","renderUniformU32","binningModule","binPointsPipeline","reduceMaxPipeline","renderPipeline","binsBuffer","maxBuffer","binsCapacityU32","lutTexture","lutView","lastColormapKey","computeBindGroup","renderBindGroup","lastPointBuffer","lastPointCount","lastVisibleStart","lastVisibleEnd","lastBinSizePx","lastBinCountX","lastBinCountY","lastPlotScissor","lastNormalizationU32","computeDirty","hasPrepared","zeroBinsStaging","ensureLut","ensureBins","binCountX","binCountY","requiredU32","ensureBindGroups","pointBuffer","visibleStartIndex","visibleEndIndex","rawBounds","binSizeCss","binSizePx","normU32","rb","binTotal","visibleCount","pass","wg","groupsPoints","groupsBins","pieWgsl","TAU","wrapToTau","thetaRad","parseColor","cssColor","fallbackCssColor","parsed","fb","resolveCenterPlotCss","center","xRaw","yRaw","isRadiusTuple","resolveRadiiCss","IDENTITY_MAT4_F32","createPieRenderer","viewportWDevicePx","viewportHDevicePx","centerPlotCss","centerCanvasCssX","centerCanvasCssY","centerClipX","centerClipY","innerPx","outerPx","total","validCount","item","startDeg","current","accumulated","emitted","isLast","startRad","endRad","candlestickWgsl","DEFAULT_WICK_WIDTH_CSS_PX","getOHLC","computeCategoryStep","timestamps","createCandlestickRenderer","hollowMode","hollowInstanceBuffer","hollowInstanceCount","cpuHollowStagingBuffer","cpuHollowStagingF32","ensureCpuHollowCapacityFloats","backgroundColor","bodyWidthClip","minWidthClip","maxWidthClip","wickWidthCssPx","wickWidthClip","upColor","downColor","upBorderColor","downBorderColor","hollowF32","hollowOutFloats","openClip","closeClip","lowClip","highClip","isUp","borderColor","borderWidthClip","insetBodyWidthClip","fillColor","hollowRequiredBytes","crosshairWgsl","align4","SMALL_FULL_WRITE_MAX_BYTES","MAX_DIFF_RANGES_BEFORE_FULL_WRITE","MAX_CHANGED_WORDS_BEFORE_FULL_WRITE","toU32View","createStreamBuffer","clamped","limit","capacityWords","createSlot","slots","currentIndex","writeFull","slotIndex","newWords","usedWords","slot","mirror","usedBytes","writeRangesByDiff","ranges","rangeCount","changedWords","byteSize","nextVertexCount","nextIndex","DEFAULT_CROSSHAIR_RGBA","MAX_THICKNESS_DEVICE_PX","DASH_ON_DEVICE_PX","DASH_OFF_DEVICE_PX","MAX_VERTICES","computeThicknessOffsetsDevicePx","lineWidthCssPx","widthDevicePx","thickness","devicePxToClipX","xDevicePx","canvasWidthDevicePx","devicePxToClipY","yDevicePx","canvasHeightDevicePx","appendSegmentVerticesClip","generateDashedSegmentsAxisAligned","a0","a1","on","period","approxSegments","segments","s0","s1","generateCrosshairVertices","xCssPx","yCssPx","xDevice","thicknessOffsets","floats","dashSegmentsY","dashSegmentsX","projectedVertexCount","useDashed","addVerticalSolid","addHorizontalSolid","xd","ya","yb","yd","xa","xb","createCrosshairRenderer","stream","renderOptions","scissor","highlightWgsl","DEFAULT_RGBA","isFiniteScissor","brighten","factor","f","luminance","createHighlightRenderer","uniformBuffer","sizeCssPx","baseRadiusDevicePx","seriesRgba","ringRgba","outlineRgba","buf","referenceLineWgsl","MAX_DASH_VALUES","normalizeDash","cleaned","dashCount","dashTotal","createReferenceLineRenderer","sampleCountRaw","sampleCount","instanceCapacity","lines","plotWidthDevice","plotHeightDevice","uniforms","nextCapacity","line","dash","firstInstance","requestedCount","first","available","annotationMarkerWgsl","createAnnotationMarkerRenderer","instances","strokeWidthCss","strokeRgba","fr","fg","fa","sr","sg","sb","sa","DEFAULT_TAP_MAX_DISTANCE_CSS_PX","DEFAULT_TAP_MAX_TIME_MS","createEventManager","initialGridArea","listeners","tapCandidate","suppressNextLostPointerCaptureId","toPayload","rect","gridX","gridY","isInGrid","emit","eventName","payload","cb","clearTapCandidateIfMatches","onPointerMove","onPointerLeave","onPointerCancel","onLostPointerCapture","onPointerDown","onPointerUp","dt","maxDist","callback","nextGridArea","clamp","normalizeWheelDelta","basisCssPx","raw","normalizeWheelDeltaX","wheelDeltaToZoomFactor","deltaCssPx","abs","capped","isMiddleButtonDrag","isShiftLeftDrag","createInsideZoom","eventManager","enabled","lastPointer","isPanning","lastPanGridX","clearPan","onMouseMove","dxCss","deltaPct","onMouseLeave","_payload","onWheel","deltaYCss","deltaXCss","centerPct","enable","disable","DEFAULT_MIN_SPAN","DEFAULT_MAX_SPAN","normalizeZero","copyRange","createZoomState","initialStart","initialEnd","constraints","lastEmitted","minSpan","maxSpan","normalizedMinSpan","normalizedMaxSpan","next","snapshot","toAnchor","nextStart","nextEnd","spec","applyNextRange","targetSpan","anchorCenter","anchorRatio","shift","nextMinSpan","nextMaxSpan","nextMin","nextMax","eps","nextSpan","delta","hasNaNXCache","seriesHasNaNX","hasNaN","computeBarHitTestLayout","barSeries","barWidthRange","gap","clusterWidth","clusterIndexByGlobalSeriesIndex","globalSeriesIndex","findPointsAtX","xValue","tolerance","maxDx","maxDxSq","matches","barLayout","offsetLeftFromCategoryCenter","hitTol","hitIndex","isHit","xCenterRange","xTargetAdjusted","insertionIndex","getXCenterAt","bestDxSq","tryUpdate","dxSq","dxSqAt","dxSqLeft","dxSqRight","getTimestamp","getOpen","getClose","categoryStepCache","step","computeCandlestickBodyWidthRange","plotWidthFallback","categoryWidthRange","t0","minW","maxWCandidate","maxW","isMonotonicNonDecreasingFiniteTimestamps","prev","lowerBoundByTimestamp","findCandlestick","halfW","best","bestDx","dataIndex","isBodyHitAt","yOpen","yClose","findPieSlice","pieConfig","dyUp","angle","slice","wedgeSpan","rel","assertFinite","createLinearScale","rangeMin","rangeMax","self","pixel","createCategoryScale","categories","indexByCategory","rebuildIndex","nextCategories","category","getAnchorTransform","createTextOverlay","container","computedStyle","computedPosition","computedOverflow","didSetRelative","didSetOverflowVisible","previousInlinePosition","previousInlineOverflow","overlay","rotation","translateX","originX","getSeriesName","candidate","getSeriesColor","explicit","palette","getPieSliceLabel","sliceName","sliceIndex","getPieSliceColor","sliceColor","len","createLegend","position","onSeriesToggle","root","list","sliceIndexStr","items","isVisible","swatch","createTooltip","fadeMs","transitionToken","hideTimeoutId","rafId","clearPendingTransitions","isCurrentlyHidden","measureSize","prevVisibility","content","wasHidden","pad","containerW","containerH","myToken","EM_DASH","escapeHtml","resolveSeriesName","params","sanitizeCssColor","isCandlestickValue","formatPercentChange","change","formatRowHtml","valueText","safeName","safeValue","formatCandlestickRowHtml","safeColor","openStr","highStr","lowStr","closeStr","arrow","arrowColor","percentChange","ohlcText","safeOHLC","safeArrow","safePercent","safeArrowColor","formatCandlestickTooltip","formatTooltipItem","formatTooltipAxis","xText","header","rows","normalizeDurationMs","duration","normalizeTimestampMs","createAnimationController","animations","animate","from","to","easing","onUpdate","onComplete","id","cancel","animationId","cancelAll","update","ts","ids","anim","startTime","durationMs","elapsed","shouldComplete","rawT","easeLinear","easeCubicOut","inv","easeCubicInOut","easeBounceOut","n1","d1","getEasing","isHTMLCanvasElementGPU","getCanvasCssSizeFromDevicePixels","MAX_TIME_X_TICK_COUNT","MIN_TIME_X_TICK_COUNT","MIN_X_LABEL_GAP_CSS_PX","finiteOrNull","MAX_ANIMATED_POINTS_PER_SERIES","cartesianDataToDataPointArray","extendBoundsWithDataPoints","seeded","extendBoundsWithOHLCDataPoints","computeGlobalBounds","runtimeRawBoundsByIndex","runtimeBoundsCandidate","rawBoundsCandidate","rawOHLC","yLow","yHigh","computeGridArea","rawCanvasWidth","rawCanvasHeight","sanitizedLeft","sanitizedRight","sanitizedTop","sanitizedBottom","rgba01ToCssRgba","alphaMultiplier","t01","lerpDomain","isTupleOHLCDataPointImported","resolvePieCenterPlotCss","generateLinearTicks","ticks","computeAdaptiveTimeXAxisTicks","axisMin","axisMax","plotClipLeft","plotClipRight","measureCtx","measureCache","fontFamily","cacheKeyPrefix","tickValues","prevRight","ok","measured","computeBaseXDomain","baseMin","baseMax","computeVisibleYBounds","visibleOHLC","computeBaseYDomain","visibleBoundsOverride","explicitMin","explicitMax","autoBoundsMode","computeVisibleXDomain","baseXDomain","fractionRaw","spanFraction","resolveAnimationConfig","animation","durationMsRaw","delayMsRaw","delayMs","resolveIntroAnimationConfig","resolveUpdateAnimationConfig","computeCandlestickTooltipAnchor","bodyMidY","xCanvasCss","yCanvasCss","xContainerCss","yContainerCss","createAnimatedBarYScale","baseYScale","progress01","wrapper","createRenderCoordinator","callbacks","info","legend","pieData","updatedData","updatedSeries","seriesItem","setOptions","tickMeasureCtx","tickMeasureCache","lastSeriesCount","introAnimController","introAnimId","hasRenderedOnce","updateAnimController","updateAnimId","updateProgress01","updateTransition","updateInterpolationCaches","resetUpdateInterpolationCaches","interpolateCartesianSeriesDataByIndex","fromData","toData","cache","created","pTo","yFrom","yTo","interpolatePieSeriesByIndex","fromSeries","toSeries","vFrom","vTo","interpolateSeriesForUpdate","caches","aAny","bAny","aData","bData","animatedData","computeUpdateSnapshotAtProgress","transition","xBase","xVisible","yBase","warnedPieAppendSeries","warnedSamplingDefeatsFastPath","runtimeRawDataByIndex","runtimeBaseSeries","cachedVisibleYBounds","shouldComputeVisibleYBounds","opts","recomputeCachedVisibleYBoundsIfNeeded","lastSampledData","flushScheduled","flushRafId","flushTimeoutId","zoomResampleDebounceTimer","zoomResampleDue","sliceRenderSeriesDue","pendingAppendByIndex","tooltip","lastTooltipContent","lastTooltipX","lastTooltipY","showTooltipInternal","_params","hideTooltipInternal","hideTooltip","gridRenderer","xAxisRenderer","yAxisRenderer","crosshairRenderer","highlightRenderer","ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT","referenceLineRenderer","annotationMarkerRenderer","referenceLineRendererMsaa","annotationMarkerRendererMsaa","mainColorTexture","mainColorView","overlayMsaaTexture","overlayMsaaView","overlayTargetsWidth","overlayTargetsHeight","overlayTargetsFormat","OVERLAY_BLIT_WGSL","overlayBlitBindGroupLayout","overlayBlitPipeline","overlayBlitBindGroup","destroyTexture","tex","ensureOverlayTargets","pointerState","interactionX","interactionXSource","interactionXListeners","lastInteractionScales","emitInteractionX","nextX","source","setInteractionXInternal","requestRender","isFullSpanZoomRange","range","cancelScheduledFlush","cancelZoomResampleDebounce","flushPendingAppends","zoomRangeBefore","isFullSpanZoomBefore","canAutoScroll","prevBaseXDomain","prevVisibleXDomain","didAppendAny","seed","ohlcPoints","dataPoints","computeEffectiveZoomSpanConstraints","withConstraints","anchored","nextBaseXDomain","nextStartRaw","nextEndRaw","recomputeRuntimeBaseSeries","zoomRangeAfter","executeFlush","requestRenderAfter","didAppend","zoomIsFullSpan","zoomActiveNotFullSpan","didResample","recomputeRenderSeries","scheduleFlush","scheduleZoomResample","getPlotSizeCssPx","canvasWidthCss","canvasHeightCss","computeInteractionScalesGridCssPx","domains","buildTooltipParams","buildCandlestickTooltipParams","findPieSliceAtPointer","pieSeries","radii","findCandlestickAtPointer","cs","insideZoom","unsubscribeZoom","lastOptionsZoomRange","zoomRangeListeners","emitZoomRange","getZoomOptionsConfig","insideCfg","sliderCfg","clampPercent","getZoomSpanConstraintsFromOptions","computeDatasetAwareDefaultMinSpan","maxPoints","fromOptions","datasetMin","updateZoom","initRuntimeSeriesFromOptions","owned","baselineSampled","sliceRenderSeriesToVisibleRange","visibleX","bufferedMin","bufferedMax","MIN_TARGET_POINTS","MAX_TARGET_POINTS_ABS","MAX_TARGET_MULTIPLIER","spanFracSafe","bufferedOHLC","baseThreshold","baseT","maxTarget","target","sampled","visibleSampled","bufferedRaw","areaRenderers","lineRenderers","scatterRenderers","scatterDensityRenderers","pieRenderers","candlestickRenderers","barRenderer","ensureAreaRendererCount","ensureLineRendererCount","ensureScatterRendererCount","ensureScatterDensityRendererCount","ensurePieRendererCount","ensureCandlestickRendererCount","cancelUpdateTransition","isDomainEqual","didSeriesDataLikelyChange","aPie","bPie","aRaw","bRaw","didOnlyVisibilityChange","hasVisibilityChange","j","sliceA","sliceB","aSliceVisible","bSliceVisible","aVisible","bVisible","resolvedOptions","fromZoomRange","fromSnapshot","fromXBase","fromXVisible","fromYBase","likelyDataChanged","onlyVisibilityChanged","shouldHaveTooltip","nextCount","toZoomRange","toXBase","toXVisible","toYBase","toSeriesForTransition","domainChanged","updateCfg","totalMs","easingWithDelay","elapsedMs","innerT","seriesForIntro","introCfg","hasDrawableSeriesMarks","it","updateP","yBaseDomain","canvasCssForAnnotations","annotationResult","combinedReferenceLines","combinedMarkers","computed","formatter","trigger","containerX","containerY","paramsArray","m0","pieMatch","candlestickResult","tooltipX","tooltipY","seriesPreparation","yScaleForBars","swapchainView","clearValue","renderSeriesPass","topOverlayPass","defaultGrid","defaultPalette","defaultLineStyle","defaultAreaStyle","candlestickDefaults","scatterDefaults","defaultOptions","darkTheme","lightTheme","getTheme","sanitizeDataZoom","input","record","type","xAxisIndexRaw","startRaw","endRaw","minSpanRaw","maxSpanRaw","xAxisIndex","sanitizeAnnotations","isLabelAnchor","isScatterSymbol","sanitizeString","sanitizeFiniteNumber","sanitizeOpacity01","sanitizeLineDash","sanitizePadding","layerRaw","styleRaw","style","labelRaw","decimalsRaw","offsetRaw","offset","anchorRaw","bgRaw","background","markerRaw","marker","symbolRaw","symbol","mStyleRaw","mStyle","positionRaw","space","sanitizePalette","resolveTheme","themeInput","takeString","fontSizeRaw","colorPaletteCandidate","normalizeOptionalColor","normalizeSampling","normalizeScatterMode","normalizeDensityNormalization","normalizeDensityBinSize","normalizeDensityColormap","arr","sanitized","normalizeCandlestickSampling","normalizeSamplingThreshold","normalizeAxisAutoBounds","computeRawBoundsFromOHLC","candlestickWarned","warnCandlestickNotImplemented","resolveOptions","userOptions","baseTheme","autoScrollRaw","autoScroll","animationRaw","paletteOverride","themeCandidate","paletteFromTheme","safePalette","paletteForIndexing","grid","xAxis","yAxis","explicitColor","inheritedColor","effectiveColor","areaStyle","effectiveStrokeColor","lineStyle","_userAreaStyle","rest","sampledData","binSize","densityColormap","densityNormalization","_sampling","_samplingThreshold","resolvedData","itemIndex","itemColor","itemVisible","resolvedSampling","resolvedSamplingThreshold","resolvedItemStyle","DATA_ZOOM_SLIDER_HEIGHT_CSS_PX","DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX","DATA_ZOOM_SLIDER_RESERVE_CSS_PX","hasSliderDataZoom","resolveOptionsForChart","OptionResolver","normalizeRange","createDataZoomSlider","marginTop","zIndex","showPreview","track","preview","windowEl","leftHandle","rightHandle","centerGrip","activeDragCleanup","applyRangeToDom","getTrackWidthPx","pxToPercent","dxPx","setPointerCaptureBestEffort","el","pointerId","releasePointerCaptureBestEffort","startDrag","dragStartX","startRange","onMove","ev","dxPercent","cleanedUp","cleanup","finish","onLeftDown","onRightDown","onPanDown","unsubscribe","handleBorder","cachedSupportCheck","checkWebGPUSupport","reason","FRAME_BUFFER_SIZE","EXPECTED_FRAME_TIME_MS","FRAME_DROP_THRESHOLD_MULTIPLIER","getCartesianPointCount","getCartesianX","getCartesianY","getCartesianSize","getOHLCTimestamp","getOHLCClose","computeRawBoundsFromData","createChartGPU","supportCheck","coordinator","coordinatorTargetFormat","unsubscribeCoordinatorInteractionXChange","dataZoomSliderHost","dataZoomSlider","runtimeHitTestSeriesCache","initRuntimeHitTestStoreFromResolvedOptions","getRuntimeHitTestSeries","cachedGlobalBounds","interactionScalesCache","hovered","scheduledRaf","lastConfigured","isDirty","frameTimestamps","frameTimestampIndex","frameTimestampCount","totalFrames","totalDroppedFrames","consecutiveDroppedFrames","lastDropTimestamp","lastFrameTime","lastCPUTime","performanceUpdateCallbacks","hasHoverListeners","hasClickListeners","cancelPendingFrame","frameStartTime","resizeInternal","metrics","calculatePerformanceMetrics","unbindCoordinatorInteractionXChange","disposeDataZoomSlider","disposeDataZoomSliderHost","disposeDataZoomUi","ensureDataZoomSliderHost","host","computeZoomInOutAnchorRatio","createCoordinatorZoomStateLike","ratio","syncDataZoomUi","bindCoordinatorInteractionXChange","recreateCoordinator","prevZoomRange","shouldRequestRenderAfterChanges","maxDimension","sizeChanged","didConfigure","resize","getNearestPointFromPointerEvent","zMin","zMax","scales","cartesianMatch","calculateExactFPS","startIndex","totalDelta","prevIndex","currIndex","avgFrameTime","calculateFrameTimeStats","deltas","sum","avg","p50Index","p95Index","p99Index","fps","frameTimeStats","gpuTiming","memory","frameDrops","elapsedTime","buildPayload","seriesNameRaw","seriesName","setHovered","prevSeriesIndex","prevDataIndex","nextSeriesIndex","nextDataIndex","dispose","instance","nextOptions","canvasX","canvasY","errorMessage","ChartGPU","connectCharts","charts","connectionToken","disconnected","unsubscribeFns","broadcast","sourceChart","chart","onCrosshairMove","unsub","createAnnotationHitTester","lineTolerance","textTolerance","pointTolerance","boundsCache","textBoundsCache","cacheValid","getPointX","getPointY","getOHLCHigh","getOHLCLow","computeXDomain","dataXMin","dataXMax","zoomMin","zoomMax","computeYDomain","dataYMin","dataYMax","dataToCanvas","chartOptions","fraction","plotToCanvas","updateCache","annotation","pos","distanceToLine","pointerX","pointerY","lineX","lineY","distanceToPoint","pointX","pointY","isInsideRect","hitTest","closestHit","closestDistance","distance","textRect","centerX","centerY","updateTextBounds","textBounds","invalidateCache","createAnnotationDragHandler","dragState","canvasToData","dataX","dataY","xFraction","yFraction","canvasToPlot","updates","onKeyDown","annotationIndex","startPointerX","startPointerY","isDragging","HIGH_CONTRAST_PALETTE","createAnnotationConfigDialog","dialog","currentOnSave","currentOnCancel","createOverlay","div","handleCancel","createDialog","createField","field","labelEl","createTextInput","placeholder","maxLength","defaultValue","createTextArea","textarea","createColorPicker","selectedColor","currentColor","checkmark","path","child","btn","isSelected","svg","createDropdown","select","opt","option","createSlider","unit","slider","valueDisplay","createButtons","saveLabel","onSaveClick","onCancelClick","cancelBtn","saveBtn","buildLineForm","defaults","form","defaultLabelText","labelInput","colorPicker","lineStyleDropdown","lineWidthSlider","buttons","lineDashMap","labelText","handleSave","buildTextForm","defaultText","textArea","buildPointForm","defaultMarkerSize","markerSizeSlider","hide","handleKeyDown","showCreate","onSave","onCancel","title","firstInput","showEdit","createAnnotationAuthoring","menuZIndex","enableContextMenu","history","historyIndex","hitTester","configDialog","dragHandler","getCurrentAnnotations","applyAnnotations","pushHistory","contextMenu","createContextMenu","menu","createMenuItem","onClick","hideContextMenu","createMenuSeparator","separator","populateContextMenuForAnnotation","handleEditAnnotation","handleDeleteAnnotation","handleAddVerticalLine","handleAddHorizontalLine","handleAddTextNote","populateContextMenuForEmptySpace","lastHitTestResult","showContextMenu","annotationHit","menuRect","adjustedX","adjustedY","computeVisibleYDomain","gridXToDataX","gridToPlotSpace","plotPos","_","onContextMenu","onDocumentClick","onDocumentKeyDown","onWindowScrollOrResize","addVerticalLine","newAnnotation","addTextNote","undo","redo","exportJSON","getAnnotations","internalStateMap","createRenderScheduler","state","startRenderScheduler","internalState","schedulerId","frameHandler","currentTime","currentInternalState","deltaTime","MAX_DELTA_TIME","nextInternalState","stopRenderScheduler","destroyRenderScheduler","createRenderSchedulerAsync","RenderScheduler","version","ChartGPUNamespace"],"mappings":"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"}
|