@chartgpu/chartgpu 0.2.5
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/LICENSE +21 -0
- package/README.md +208 -0
- package/dist/ChartGPU.d.ts +146 -0
- package/dist/ChartGPU.d.ts.map +1 -0
- package/dist/components/createAnnotationConfigDialog.d.ts +24 -0
- package/dist/components/createAnnotationConfigDialog.d.ts.map +1 -0
- package/dist/components/createDataZoomSlider.d.ts +14 -0
- package/dist/components/createDataZoomSlider.d.ts.map +1 -0
- package/dist/components/createLegend.d.ts +9 -0
- package/dist/components/createLegend.d.ts.map +1 -0
- package/dist/components/createTextOverlay.d.ts +17 -0
- package/dist/components/createTextOverlay.d.ts.map +1 -0
- package/dist/components/createTooltip.d.ts +12 -0
- package/dist/components/createTooltip.d.ts.map +1 -0
- package/dist/components/formatTooltip.d.ts +19 -0
- package/dist/components/formatTooltip.d.ts.map +1 -0
- package/dist/config/OptionResolver.d.ts +137 -0
- package/dist/config/OptionResolver.d.ts.map +1 -0
- package/dist/config/defaults.d.ts +56 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/types.d.ts +553 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/core/GPUContext.d.ts +242 -0
- package/dist/core/GPUContext.d.ts.map +1 -0
- package/dist/core/RenderScheduler.d.ts +174 -0
- package/dist/core/RenderScheduler.d.ts.map +1 -0
- package/dist/core/createAnimationController.d.ts +15 -0
- package/dist/core/createAnimationController.d.ts.map +1 -0
- package/dist/core/createRenderCoordinator.d.ts +78 -0
- package/dist/core/createRenderCoordinator.d.ts.map +1 -0
- package/dist/core/renderCoordinator/animation/animationHelpers.d.ts +183 -0
- package/dist/core/renderCoordinator/animation/animationHelpers.d.ts.map +1 -0
- package/dist/core/renderCoordinator/annotations/processAnnotations.d.ts +88 -0
- package/dist/core/renderCoordinator/annotations/processAnnotations.d.ts.map +1 -0
- package/dist/core/renderCoordinator/axis/axisLabelHelpers.d.ts +91 -0
- package/dist/core/renderCoordinator/axis/axisLabelHelpers.d.ts.map +1 -0
- package/dist/core/renderCoordinator/axis/computeAxisTicks.d.ts +53 -0
- package/dist/core/renderCoordinator/axis/computeAxisTicks.d.ts.map +1 -0
- package/dist/core/renderCoordinator/data/computeVisibleSlice.d.ts +66 -0
- package/dist/core/renderCoordinator/data/computeVisibleSlice.d.ts.map +1 -0
- package/dist/core/renderCoordinator/gpu/textureManager.d.ts +69 -0
- package/dist/core/renderCoordinator/gpu/textureManager.d.ts.map +1 -0
- package/dist/core/renderCoordinator/interaction/interactionHelpers.d.ts +160 -0
- package/dist/core/renderCoordinator/interaction/interactionHelpers.d.ts.map +1 -0
- package/dist/core/renderCoordinator/render/renderAnnotationLabels.d.ts +36 -0
- package/dist/core/renderCoordinator/render/renderAnnotationLabels.d.ts.map +1 -0
- package/dist/core/renderCoordinator/render/renderAxisLabels.d.ts +40 -0
- package/dist/core/renderCoordinator/render/renderAxisLabels.d.ts.map +1 -0
- package/dist/core/renderCoordinator/render/renderOverlays.d.ts +70 -0
- package/dist/core/renderCoordinator/render/renderOverlays.d.ts.map +1 -0
- package/dist/core/renderCoordinator/render/renderSeries.d.ts +146 -0
- package/dist/core/renderCoordinator/render/renderSeries.d.ts.map +1 -0
- package/dist/core/renderCoordinator/renderers/rendererPool.d.ts +112 -0
- package/dist/core/renderCoordinator/renderers/rendererPool.d.ts.map +1 -0
- package/dist/core/renderCoordinator/types.d.ts +19 -0
- package/dist/core/renderCoordinator/types.d.ts.map +1 -0
- package/dist/core/renderCoordinator/ui/tooltipLegendHelpers.d.ts +104 -0
- package/dist/core/renderCoordinator/ui/tooltipLegendHelpers.d.ts.map +1 -0
- package/dist/core/renderCoordinator/utils/axisUtils.d.ts +122 -0
- package/dist/core/renderCoordinator/utils/axisUtils.d.ts.map +1 -0
- package/dist/core/renderCoordinator/utils/boundsComputation.d.ts +69 -0
- package/dist/core/renderCoordinator/utils/boundsComputation.d.ts.map +1 -0
- package/dist/core/renderCoordinator/utils/canvasUtils.d.ts +52 -0
- package/dist/core/renderCoordinator/utils/canvasUtils.d.ts.map +1 -0
- package/dist/core/renderCoordinator/utils/dataPointUtils.d.ts +71 -0
- package/dist/core/renderCoordinator/utils/dataPointUtils.d.ts.map +1 -0
- package/dist/core/renderCoordinator/utils/index.d.ts +12 -0
- package/dist/core/renderCoordinator/utils/index.d.ts.map +1 -0
- package/dist/core/renderCoordinator/utils/timeAxisUtils.d.ts +149 -0
- package/dist/core/renderCoordinator/utils/timeAxisUtils.d.ts.map +1 -0
- package/dist/core/renderCoordinator/zoom/zoomHelpers.d.ts +129 -0
- package/dist/core/renderCoordinator/zoom/zoomHelpers.d.ts.map +1 -0
- package/dist/data/cartesianData.d.ts +72 -0
- package/dist/data/cartesianData.d.ts.map +1 -0
- package/dist/data/createDataStore.d.ts +27 -0
- package/dist/data/createDataStore.d.ts.map +1 -0
- package/dist/data/createStreamBuffer.d.ts +20 -0
- package/dist/data/createStreamBuffer.d.ts.map +1 -0
- package/dist/data/lttbSample.d.ts +5 -0
- package/dist/data/lttbSample.d.ts.map +1 -0
- package/dist/data/ohlcSample.d.ts +21 -0
- package/dist/data/ohlcSample.d.ts.map +1 -0
- package/dist/data/packDataPoints.d.ts +65 -0
- package/dist/data/packDataPoints.d.ts.map +1 -0
- package/dist/data/sampleSeries.d.ts +20 -0
- package/dist/data/sampleSeries.d.ts.map +1 -0
- package/dist/esm/ChartGPUWorkerController-B50J-8sx.js +772 -0
- package/dist/esm/ChartGPUWorkerController-B50J-8sx.js.map +1 -0
- package/dist/esm/OptionResolver-R_gJDRSD.js +7150 -0
- package/dist/esm/OptionResolver-R_gJDRSD.js.map +1 -0
- package/dist/esm/assets/worker-entry-Wg897auv.js +779 -0
- package/dist/esm/assets/worker-entry-Wg897auv.js.map +1 -0
- package/dist/esm/createChartInWorker-C4fEeJL8.js +1224 -0
- package/dist/esm/createChartInWorker-C4fEeJL8.js.map +1 -0
- package/dist/esm/index.js +795 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.cjs +1270 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10504 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/createAnnotationAuthoring.d.ts +115 -0
- package/dist/interaction/createAnnotationAuthoring.d.ts.map +1 -0
- package/dist/interaction/createAnnotationDragHandler.d.ts +28 -0
- package/dist/interaction/createAnnotationDragHandler.d.ts.map +1 -0
- package/dist/interaction/createAnnotationHitTester.d.ts +32 -0
- package/dist/interaction/createAnnotationHitTester.d.ts.map +1 -0
- package/dist/interaction/createChartSync.d.ts +27 -0
- package/dist/interaction/createChartSync.d.ts.map +1 -0
- package/dist/interaction/createEventManager.d.ts +24 -0
- package/dist/interaction/createEventManager.d.ts.map +1 -0
- package/dist/interaction/createHoverState.d.ts +20 -0
- package/dist/interaction/createHoverState.d.ts.map +1 -0
- package/dist/interaction/createInsideZoom.d.ts +14 -0
- package/dist/interaction/createInsideZoom.d.ts.map +1 -0
- package/dist/interaction/createZoomState.d.ts +63 -0
- package/dist/interaction/createZoomState.d.ts.map +1 -0
- package/dist/interaction/findCandlestick.d.ts +41 -0
- package/dist/interaction/findCandlestick.d.ts.map +1 -0
- package/dist/interaction/findNearestPoint.d.ts +61 -0
- package/dist/interaction/findNearestPoint.d.ts.map +1 -0
- package/dist/interaction/findPieSlice.d.ts +36 -0
- package/dist/interaction/findPieSlice.d.ts.map +1 -0
- package/dist/interaction/findPointsAtX.d.ts +37 -0
- package/dist/interaction/findPointsAtX.d.ts.map +1 -0
- package/dist/renderers/createAnnotationMarkerRenderer.d.ts +58 -0
- package/dist/renderers/createAnnotationMarkerRenderer.d.ts.map +1 -0
- package/dist/renderers/createAreaRenderer.d.ts +19 -0
- package/dist/renderers/createAreaRenderer.d.ts.map +1 -0
- package/dist/renderers/createAxisRenderer.d.ts +19 -0
- package/dist/renderers/createAxisRenderer.d.ts.map +1 -0
- package/dist/renderers/createBarRenderer.d.ts +20 -0
- package/dist/renderers/createBarRenderer.d.ts.map +1 -0
- package/dist/renderers/createCandlestickRenderer.d.ts +19 -0
- package/dist/renderers/createCandlestickRenderer.d.ts.map +1 -0
- package/dist/renderers/createCrosshairRenderer.d.ts +43 -0
- package/dist/renderers/createCrosshairRenderer.d.ts.map +1 -0
- package/dist/renderers/createGridRenderer.d.ts +45 -0
- package/dist/renderers/createGridRenderer.d.ts.map +1 -0
- package/dist/renderers/createHighlightRenderer.d.ts +41 -0
- package/dist/renderers/createHighlightRenderer.d.ts.map +1 -0
- package/dist/renderers/createLineRenderer.d.ts +18 -0
- package/dist/renderers/createLineRenderer.d.ts.map +1 -0
- package/dist/renderers/createPieRenderer.d.ts +18 -0
- package/dist/renderers/createPieRenderer.d.ts.map +1 -0
- package/dist/renderers/createReferenceLineRenderer.d.ts +81 -0
- package/dist/renderers/createReferenceLineRenderer.d.ts.map +1 -0
- package/dist/renderers/createScatterDensityRenderer.d.ts +14 -0
- package/dist/renderers/createScatterDensityRenderer.d.ts.map +1 -0
- package/dist/renderers/createScatterRenderer.d.ts +20 -0
- package/dist/renderers/createScatterRenderer.d.ts.map +1 -0
- package/dist/renderers/rendererUtils.d.ts +100 -0
- package/dist/renderers/rendererUtils.d.ts.map +1 -0
- package/dist/themes/darkTheme.d.ts +11 -0
- package/dist/themes/darkTheme.d.ts.map +1 -0
- package/dist/themes/index.d.ts +8 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/lightTheme.d.ts +11 -0
- package/dist/themes/lightTheme.d.ts.map +1 -0
- package/dist/themes/types.d.ts +14 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/types/ChartGPU.d.ts +99 -0
- package/dist/types/ChartGPU.d.ts.map +1 -0
- package/dist/types/components/createDataZoomSlider.d.ts +14 -0
- package/dist/types/components/createDataZoomSlider.d.ts.map +1 -0
- package/dist/types/components/createLegend.d.ts +9 -0
- package/dist/types/components/createLegend.d.ts.map +1 -0
- package/dist/types/components/createTextOverlay.d.ts +17 -0
- package/dist/types/components/createTextOverlay.d.ts.map +1 -0
- package/dist/types/components/createTooltip.d.ts +12 -0
- package/dist/types/components/createTooltip.d.ts.map +1 -0
- package/dist/types/components/formatTooltip.d.ts +19 -0
- package/dist/types/components/formatTooltip.d.ts.map +1 -0
- package/dist/types/config/OptionResolver.d.ts +134 -0
- package/dist/types/config/OptionResolver.d.ts.map +1 -0
- package/dist/types/config/defaults.d.ts +55 -0
- package/dist/types/config/defaults.d.ts.map +1 -0
- package/dist/types/config/types.d.ts +485 -0
- package/dist/types/config/types.d.ts.map +1 -0
- package/dist/types/core/GPUContext.d.ts +242 -0
- package/dist/types/core/GPUContext.d.ts.map +1 -0
- package/dist/types/core/RenderScheduler.d.ts +174 -0
- package/dist/types/core/RenderScheduler.d.ts.map +1 -0
- package/dist/types/core/createAnimationController.d.ts +15 -0
- package/dist/types/core/createAnimationController.d.ts.map +1 -0
- package/dist/types/core/createRenderCoordinator.d.ts +129 -0
- package/dist/types/core/createRenderCoordinator.d.ts.map +1 -0
- package/dist/types/data/createDataStore.d.ts +33 -0
- package/dist/types/data/createDataStore.d.ts.map +1 -0
- package/dist/types/data/createStreamBuffer.d.ts +20 -0
- package/dist/types/data/createStreamBuffer.d.ts.map +1 -0
- package/dist/types/data/lttbSample.d.ts +5 -0
- package/dist/types/data/lttbSample.d.ts.map +1 -0
- package/dist/types/data/ohlcSample.d.ts +21 -0
- package/dist/types/data/ohlcSample.d.ts.map +1 -0
- package/dist/types/data/packDataPoints.d.ts +79 -0
- package/dist/types/data/packDataPoints.d.ts.map +1 -0
- package/dist/types/data/sampleSeries.d.ts +3 -0
- package/dist/types/data/sampleSeries.d.ts.map +1 -0
- package/dist/types/index.d.ts +35 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/interaction/createChartSync.d.ts +12 -0
- package/dist/types/interaction/createChartSync.d.ts.map +1 -0
- package/dist/types/interaction/createEventManager.d.ts +24 -0
- package/dist/types/interaction/createEventManager.d.ts.map +1 -0
- package/dist/types/interaction/createHoverState.d.ts +20 -0
- package/dist/types/interaction/createHoverState.d.ts.map +1 -0
- package/dist/types/interaction/createInsideZoom.d.ts +14 -0
- package/dist/types/interaction/createInsideZoom.d.ts.map +1 -0
- package/dist/types/interaction/createZoomState.d.ts +63 -0
- package/dist/types/interaction/createZoomState.d.ts.map +1 -0
- package/dist/types/interaction/findCandlestick.d.ts +41 -0
- package/dist/types/interaction/findCandlestick.d.ts.map +1 -0
- package/dist/types/interaction/findNearestPoint.d.ts +61 -0
- package/dist/types/interaction/findNearestPoint.d.ts.map +1 -0
- package/dist/types/interaction/findPieSlice.d.ts +36 -0
- package/dist/types/interaction/findPieSlice.d.ts.map +1 -0
- package/dist/types/interaction/findPointsAtX.d.ts +37 -0
- package/dist/types/interaction/findPointsAtX.d.ts.map +1 -0
- package/dist/types/renderers/createAreaRenderer.d.ts +18 -0
- package/dist/types/renderers/createAreaRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createAxisRenderer.d.ts +19 -0
- package/dist/types/renderers/createAxisRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createBarRenderer.d.ts +20 -0
- package/dist/types/renderers/createBarRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createCandlestickRenderer.d.ts +19 -0
- package/dist/types/renderers/createCandlestickRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createCrosshairRenderer.d.ts +43 -0
- package/dist/types/renderers/createCrosshairRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createGridRenderer.d.ts +45 -0
- package/dist/types/renderers/createGridRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createHighlightRenderer.d.ts +41 -0
- package/dist/types/renderers/createHighlightRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createLineRenderer.d.ts +18 -0
- package/dist/types/renderers/createLineRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createPieRenderer.d.ts +18 -0
- package/dist/types/renderers/createPieRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createScatterDensityRenderer.d.ts +14 -0
- package/dist/types/renderers/createScatterDensityRenderer.d.ts.map +1 -0
- package/dist/types/renderers/createScatterRenderer.d.ts +19 -0
- package/dist/types/renderers/createScatterRenderer.d.ts.map +1 -0
- package/dist/types/renderers/rendererUtils.d.ts +100 -0
- package/dist/types/renderers/rendererUtils.d.ts.map +1 -0
- package/dist/types/themes/darkTheme.d.ts +11 -0
- package/dist/types/themes/darkTheme.d.ts.map +1 -0
- package/dist/types/themes/index.d.ts +8 -0
- package/dist/types/themes/index.d.ts.map +1 -0
- package/dist/types/themes/lightTheme.d.ts +11 -0
- package/dist/types/themes/lightTheme.d.ts.map +1 -0
- package/dist/types/themes/types.d.ts +14 -0
- package/dist/types/themes/types.d.ts.map +1 -0
- package/dist/types/utils/axisLabelStyling.d.ts +27 -0
- package/dist/types/utils/axisLabelStyling.d.ts.map +1 -0
- package/dist/types/utils/checkWebGPU.d.ts +39 -0
- package/dist/types/utils/checkWebGPU.d.ts.map +1 -0
- package/dist/types/utils/colors.d.ts +14 -0
- package/dist/types/utils/colors.d.ts.map +1 -0
- package/dist/types/utils/easing.d.ts +9 -0
- package/dist/types/utils/easing.d.ts.map +1 -0
- package/dist/types/utils/scales.d.ts +79 -0
- package/dist/types/utils/scales.d.ts.map +1 -0
- package/dist/utils/axisLabelStyling.d.ts +20 -0
- package/dist/utils/axisLabelStyling.d.ts.map +1 -0
- package/dist/utils/checkWebGPU.d.ts +39 -0
- package/dist/utils/checkWebGPU.d.ts.map +1 -0
- package/dist/utils/colors.d.ts +14 -0
- package/dist/utils/colors.d.ts.map +1 -0
- package/dist/utils/easing.d.ts +9 -0
- package/dist/utils/easing.d.ts.map +1 -0
- package/dist/utils/scales.d.ts +79 -0
- package/dist/utils/scales.d.ts.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry-Wg897auv.js","sources":["../src/core/GPUContext.ts","../src/data/packDataPoints.ts","../src/data/createDataStore.ts","../src/data/lttbSample.ts","../src/data/sampleSeries.ts","../src/data/ohlcSample.ts","../src/shaders/grid.wgsl?raw","../src/renderers/rendererUtils.ts","../src/utils/colors.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/interaction/createEventManager.ts","../src/interaction/createInsideZoom.ts","../src/interaction/createZoomState.ts","../src/interaction/findNearestPoint.ts","../src/interaction/findPointsAtX.ts","../src/interaction/findCandlestick.ts","../src/interaction/findPieSlice.ts","../src/utils/scales.ts","../src/components/createTextOverlay.ts","../src/utils/axisLabelStyling.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/worker/ChartGPUWorkerController.ts","../src/worker/worker-entry.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 | OffscreenCanvas;\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: SupportedCanvas | 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: SupportedCanvas): canvas is HTMLCanvasElement {\n return typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement;\n}\n\n/** Gets display dimensions - clientWidth/Height for HTMLCanvasElement, width/height for OffscreenCanvas. */\nfunction getCanvasDimensions(canvas: SupportedCanvas): { width: number; height: number } {\n if (isHTMLCanvasElement(canvas)) {\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 // OffscreenCanvas: dimensions already set by main thread (device pixels)\n const width = canvas.width;\n const height = canvas.height;\n \n // Validate OffscreenCanvas dimensions\n if (!Number.isFinite(width) || !Number.isFinite(height)) {\n throw new Error(\n `GPUContext: Invalid OffscreenCanvas dimensions: width=${width}, height=${height}. ` +\n `OffscreenCanvas must be initialized with finite dimensions before GPUContext creation.`\n );\n }\n \n return { width, height };\n}\n\n/**\n * Creates a new GPUContext state with initial values.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement or OffscreenCanvas) 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?: SupportedCanvas,\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 for OffscreenCanvas (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 or OffscreenCanvas) 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?: SupportedCanvas,\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 or OffscreenCanvas) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n */\n constructor(canvas?: SupportedCanvas, 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 or OffscreenCanvas) 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?: SupportedCanvas, 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 zero-copy transfer to GPU/Workers.\n * \n * These functions convert high-level DataPoint/OHLCDataPoint arrays into interleaved\n * Float32Array buffers suitable for:\n * - Direct GPU buffer uploads via `queue.writeBuffer()`\n * - Zero-copy transfer to Web Workers via postMessage transferList\n * \n * @module packDataPoints\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/Worker transfer.\n * \n * **Format**: `[x0, y0, x1, y1, x2, y2, ...]` (2 floats per point = 8 bytes stride)\n * \n * **Use cases**:\n * - Direct upload to GPU vertex buffers via `queue.writeBuffer(buffer, 0, packed.buffer)`\n * - Zero-copy transfer to workers: `postMessage({ data: packed }, [packed.buffer])`\n * \n * **Performance**: The returned Float32Array's underlying ArrayBuffer is transferable,\n * enabling zero-copy postMessage operations. After transfer, the source Float32Array\n * becomes detached (length = 0).\n * \n * @param points - Array of data points (tuple or object form)\n * @returns Interleaved Float32Array [x0,y0,x1,y1,...]. The .buffer property is transferable.\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 * \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 * // packed.buffer is transferable\n * \n * // Zero-copy transfer to worker:\n * worker.postMessage({ data: packed }, [packed.buffer]);\n * // After transfer, packed.length === 0 (detached)\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/Worker transfer.\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 * **Use cases**:\n * - Direct upload to GPU vertex buffers for candlestick rendering\n * - Zero-copy transfer to workers for streaming candlestick data\n * \n * **Performance**: The returned Float32Array's underlying ArrayBuffer is transferable,\n * enabling zero-copy postMessage operations. After transfer, the source Float32Array\n * becomes detached (length = 0).\n * \n * @param points - Array of OHLC data points (tuple or object form)\n * @returns Interleaved Float32Array [t0,o0,h0,l0,c0,t1,...]. The .buffer property is transferable.\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 * \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 * // packed.buffer is transferable\n * \n * // Zero-copy transfer to worker:\n * worker.postMessage({ data: packed }, [packed.buffer]);\n * // After transfer, packed.length === 0 (detached)\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 } from '../config/types';\nimport { packDataPoints } from './packDataPoints';\n\nexport interface DataStore {\n setSeries(index: number, data: ReadonlyArray<DataPoint>): 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 // 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 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>): void => {\n assertNotDisposed();\n\n const packed = packDataPoints(data);\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 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 = packDataPoints(newPoints);\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 = packDataPoints(nextData);\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 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 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","import type { DataPoint, DataPointTuple, SeriesSampling } from '../config/types';\nimport { lttbSample } from './lttbSample';\n\nfunction isTupleDataPoint(point: DataPoint): point is DataPointTuple {\n return Array.isArray(point);\n}\n\nfunction getXY(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\nfunction getSize(point: DataPoint): number | undefined {\n if (isTupleDataPoint(point)) return point[2];\n return point.size;\n}\n\nfunction clampTargetPoints(targetPoints: number): number {\n const t = Math.floor(targetPoints);\n return Number.isFinite(t) ? t : 0;\n}\n\ntype BucketMode = 'average' | 'max' | 'min';\n\nfunction sampleByBuckets(\n data: ReadonlyArray<DataPoint>,\n targetPoints: number,\n mode: BucketMode\n): ReadonlyArray<DataPoint> {\n const n = data.length;\n const threshold = clampTargetPoints(targetPoints);\n\n if (threshold <= 0 || n === 0) return [];\n if (threshold === 1) return [data[0]!];\n if (threshold === 2) return n >= 2 ? [data[0]!, data[n - 1]!] : [data[0]!];\n if (n <= threshold) return data;\n\n const lastIndex = n - 1;\n const out = new Array<DataPoint>(threshold);\n out[0] = data[0]!;\n out[threshold - 1] = data[lastIndex]!;\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: DataPoint | 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 p = data[i]!;\n const { x, y } = getXY(p);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n sumX += x;\n sumY += y;\n count++;\n\n const size = getSize(p);\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 for (let i = rangeStart; i < rangeEndExclusive; i++) {\n const p = data[i]!;\n const { y } = getXY(p);\n if (!Number.isFinite(y)) continue;\n if (mode === 'max') {\n if (y > bestY) {\n bestY = y;\n chosen = p;\n }\n } else {\n if (y < bestY) {\n bestY = y;\n chosen = p;\n }\n }\n }\n }\n\n out[bucket + 1] = chosen ?? data[rangeStart]!;\n }\n\n return out;\n}\n\nexport function sampleSeriesDataPoints(\n data: ReadonlyArray<DataPoint>,\n sampling: SeriesSampling,\n samplingThreshold: number\n): ReadonlyArray<DataPoint> {\n const threshold = clampTargetPoints(samplingThreshold);\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 (data.length <= threshold) return data;\n\n switch (sampling) {\n case 'lttb':\n return lttbSample(data, threshold);\n case 'average':\n return sampleByBuckets(data, threshold, 'average');\n case 'max':\n return sampleByBuckets(data, threshold, 'max');\n case 'min':\n return sampleByBuckets(data, threshold, 'min');\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","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","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","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 { 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 data: ResolvedAreaSeriesConfig['data'],\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: ResolvedAreaSeriesConfig['data'][number]): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (\n point: ResolvedAreaSeriesConfig['data'][number]\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: ResolvedAreaSeriesConfig['data']\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: ResolvedAreaSeriesConfig['data']): 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 { 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(seriesConfig: ResolvedLineSeriesConfig, dataBuffer: GPUBuffer, xScale: LinearScale, yScale: LinearScale): 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: ResolvedLineSeriesConfig['data'][number]\n): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (point: ResolvedLineSeriesConfig['data'][number]): { 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: ResolvedLineSeriesConfig['data']\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) => {\n assertNotDisposed();\n\n currentVertexBuffer = dataBuffer;\n currentVertexCount = seriesConfig.data.length;\n\n const { xMin, xMax, yMin, yMax } = computeDataBounds(seriesConfig.data);\n const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n writeTransformMat4F32(vsUniformScratchF32, ax, bx, 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 const data = seriesConfigs[s].data;\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 const data = seriesConfigs[s].data;\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 fallbackCategoryCount = Math.max(fallbackCategoryCount, Math.floor(seriesConfigs[s].data.length));\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++) maxBars += Math.max(0, seriesConfigs[s].data.length);\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 const data = series.data;\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 data: ResolvedScatterSeriesConfig['data'],\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.\n let total = 0;\n let validCount = 0;\n for (let i = 0; i < seriesConfig.data.length; i++) {\n const v = seriesConfig.data[i]?.value;\n if (typeof v === 'number' && Number.isFinite(v) && v > 0) {\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\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 const endRad = wrapToTau(current + span);\n current = endRad;\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","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, DataPointTuple, ScatterPointTuple } from '../config/types';\nimport type {\n ResolvedBarSeriesConfig,\n ResolvedScatterSeriesConfig,\n ResolvedSeriesConfig,\n} from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\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// Cache (Story 4.10): used only for scatter-series pruning so we don't degrade to O(n)\n// scans per pointer move when no candidate has been found yet.\nconst scatterMaxRadiusCache = new WeakMap<ResolvedScatterSeriesConfig, number>();\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\ntype TuplePoint = DataPointTuple;\ntype ObjectPoint = Readonly<{ x: number; y: number; size?: number }>;\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 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 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\nconst getMaxScatterRadiusCssPx = (seriesCfg: ResolvedScatterSeriesConfig): number => {\n const cached = scatterMaxRadiusCache.get(seriesCfg);\n if (cached !== undefined) return cached;\n\n const data = seriesCfg.data;\n const seriesSymbolSize = seriesCfg.symbolSize;\n\n let maxRadius = 0;\n\n // Fast path: numeric (or missing) series size means max is just max(point.size, series/default).\n if (typeof seriesSymbolSize !== 'function') {\n const seriesFallback =\n typeof seriesSymbolSize === 'number' && Number.isFinite(seriesSymbolSize)\n ? Math.max(0, seriesSymbolSize)\n : DEFAULT_SCATTER_RADIUS_CSS_PX;\n\n let maxPerPoint = 0;\n let anyPointWithoutSize = false;\n for (let i = 0; i < data.length; i++) {\n const pSize = getPointSizeCssPx(data[i]);\n if (pSize == null) {\n anyPointWithoutSize = true;\n } else {\n const r = Math.max(0, pSize);\n if (r > maxPerPoint) maxPerPoint = r;\n }\n }\n maxRadius = anyPointWithoutSize ? Math.max(maxPerPoint, seriesFallback) : maxPerPoint;\n } else {\n // Slow path: symbolSize function can vary per point, so compute true max once and cache it.\n for (let i = 0; i < data.length; i++) {\n const r = getScatterRadiusCssPx(seriesCfg, data[i]);\n if (r > maxRadius) maxRadius = r;\n }\n }\n\n maxRadius = Number.isFinite(maxRadius) ? Math.max(0, maxRadius) : DEFAULT_SCATTER_RADIUS_CSS_PX;\n scatterMaxRadiusCache.set(seriesCfg, maxRadius);\n return maxRadius;\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;\n for (let i = 0; i < data.length; i++) {\n const { x } = getPointXY(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;\n for (let i = 0; i < data.length; i++) {\n const { x } = getPointXY(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;\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\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;\n for (let i = 0; i < data.length; i++) {\n const { y } = getPointXY(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\nconst lowerBoundTuple = (\n data: ReadonlyArray<TuplePoint>,\n xTarget: number,\n): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid][0];\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\nconst lowerBoundObject = (\n data: ReadonlyArray<ObjectPoint>,\n xTarget: number,\n): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid].x;\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\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') {\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;\n const clusterIndex = clusterSlots.clusterIndexBySeries[b] ?? 0;\n const stackId = clusterSlots.stackIdBySeries[b] ?? '';\n\n for (let i = 0; i < data.length; i++) {\n const { x: xDomain, y: yDomain } = getPointXY(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 point = series[bestBarHit.seriesIndex]?.data[bestBarHit.dataIndex] as DataPoint | undefined;\n if (point) {\n return {\n seriesIndex: bestBarHit.seriesIndex,\n dataIndex: bestBarHit.dataIndex,\n point,\n distance: 0,\n };\n }\n }\n }\n }\n\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 const data = seriesCfg.data;\n const n = data.length;\n if (n === 0) continue;\n\n const isScatter = seriesCfg.type === 'scatter';\n const scatterCfg = isScatter ? (seriesCfg as ResolvedScatterSeriesConfig) : null;\n const maxRadiusInSeries = scatterCfg ? getMaxScatterRadiusCssPx(scatterCfg) : 0;\n const seriesCutoffSq = isScatter ? (md + maxRadiusInSeries) * (md + maxRadiusInSeries) : maxDistSq;\n\n const first = data[0];\n const isTuple = Array.isArray(first);\n\n if (isTuple) {\n const tupleData = data as ReadonlyArray<TuplePoint>;\n const insertionIndex = lowerBoundTuple(tupleData, xTarget);\n\n let left = insertionIndex - 1;\n let right = insertionIndex;\n\n // Expand outward while x-distance alone could still beat bestDistSq.\n while (left >= 0 || right < n) {\n const pruneSq = Math.min(bestDistSq, seriesCutoffSq);\n\n let dxSqLeft = Number.POSITIVE_INFINITY;\n if (left >= 0) {\n const px = tupleData[left][0];\n if (Number.isFinite(px)) {\n const sx = xScale.scale(px);\n if (Number.isFinite(sx)) {\n const dx = sx - x;\n dxSqLeft = dx * dx;\n }\n }\n }\n\n let dxSqRight = Number.POSITIVE_INFINITY;\n if (right < n) {\n const px = tupleData[right][0];\n if (Number.isFinite(px)) {\n const sx = xScale.scale(px);\n if (Number.isFinite(sx)) {\n const dx = sx - x;\n dxSqRight = dx * dx;\n }\n }\n }\n\n if (dxSqLeft > pruneSq && dxSqRight > pruneSq) break;\n\n // If both sides are equally close in x, evaluate both for stable tie behavior.\n if (dxSqLeft <= dxSqRight && dxSqLeft <= pruneSq && left >= 0) {\n const py = tupleData[left][1];\n if (Number.isFinite(py)) {\n const sy = yScale.scale(py);\n if (Number.isFinite(sy)) {\n const dy = sy - y;\n const distSq = dxSqLeft + dy * dy;\n const p = data[left] as DataPoint;\n\n const allowedSq = scatterCfg\n ? (() => {\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n return allowed * allowed;\n })()\n : maxDistSq;\n\n if (distSq <= allowedSq) {\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n s < bestSeriesIndex ||\n (s === bestSeriesIndex && left < bestDataIndex)));\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = s;\n bestDataIndex = left;\n bestPoint = p;\n }\n }\n }\n }\n left--;\n } else if (dxSqLeft <= dxSqRight) {\n left--;\n }\n\n if (dxSqRight <= dxSqLeft && dxSqRight <= pruneSq && right < n) {\n const py = tupleData[right][1];\n if (Number.isFinite(py)) {\n const sy = yScale.scale(py);\n if (Number.isFinite(sy)) {\n const dy = sy - y;\n const distSq = dxSqRight + dy * dy;\n const p = data[right] as DataPoint;\n\n const allowedSq = scatterCfg\n ? (() => {\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n return allowed * allowed;\n })()\n : maxDistSq;\n\n if (distSq <= allowedSq) {\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n s < bestSeriesIndex ||\n (s === bestSeriesIndex && right < bestDataIndex)));\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = s;\n bestDataIndex = right;\n bestPoint = p;\n }\n }\n }\n }\n right++;\n } else if (dxSqRight < dxSqLeft) {\n right++;\n }\n }\n } else {\n const objectData = data as ReadonlyArray<ObjectPoint>;\n const insertionIndex = lowerBoundObject(objectData, xTarget);\n\n let left = insertionIndex - 1;\n let right = insertionIndex;\n\n while (left >= 0 || right < n) {\n const pruneSq = Math.min(bestDistSq, seriesCutoffSq);\n\n let dxSqLeft = Number.POSITIVE_INFINITY;\n if (left >= 0) {\n const px = objectData[left].x;\n if (Number.isFinite(px)) {\n const sx = xScale.scale(px);\n if (Number.isFinite(sx)) {\n const dx = sx - x;\n dxSqLeft = dx * dx;\n }\n }\n }\n\n let dxSqRight = Number.POSITIVE_INFINITY;\n if (right < n) {\n const px = objectData[right].x;\n if (Number.isFinite(px)) {\n const sx = xScale.scale(px);\n if (Number.isFinite(sx)) {\n const dx = sx - x;\n dxSqRight = dx * dx;\n }\n }\n }\n\n if (dxSqLeft > pruneSq && dxSqRight > pruneSq) break;\n\n if (dxSqLeft <= dxSqRight && dxSqLeft <= pruneSq && left >= 0) {\n const py = objectData[left].y;\n if (Number.isFinite(py)) {\n const sy = yScale.scale(py);\n if (Number.isFinite(sy)) {\n const dy = sy - y;\n const distSq = dxSqLeft + dy * dy;\n const p = data[left] as DataPoint;\n\n const allowedSq = scatterCfg\n ? (() => {\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n return allowed * allowed;\n })()\n : maxDistSq;\n\n if (distSq <= allowedSq) {\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n s < bestSeriesIndex ||\n (s === bestSeriesIndex && left < bestDataIndex)));\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = s;\n bestDataIndex = left;\n bestPoint = p;\n }\n }\n }\n }\n left--;\n } else if (dxSqLeft <= dxSqRight) {\n left--;\n }\n\n if (dxSqRight <= dxSqLeft && dxSqRight <= pruneSq && right < n) {\n const py = objectData[right].y;\n if (Number.isFinite(py)) {\n const sy = yScale.scale(py);\n if (Number.isFinite(sy)) {\n const dy = sy - y;\n const distSq = dxSqRight + dy * dy;\n const p = data[right] as DataPoint;\n\n const allowedSq = scatterCfg\n ? (() => {\n const r = getScatterRadiusCssPx(scatterCfg, p);\n const allowed = md + r;\n return allowed * allowed;\n })()\n : maxDistSq;\n\n if (distSq <= allowedSq) {\n const isBetter =\n distSq < bestDistSq ||\n (distSq === bestDistSq &&\n (bestPoint === null ||\n s < bestSeriesIndex ||\n (s === bestSeriesIndex && right < bestDataIndex)));\n if (isBetter) {\n bestDistSq = distSq;\n bestSeriesIndex = s;\n bestDataIndex = right;\n bestPoint = p;\n }\n }\n }\n }\n right++;\n } else if (dxSqRight < dxSqLeft) {\n right++;\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","import type { DataPoint } from '../config/types';\nimport type { ResolvedBarSeriesConfig, ResolvedSeriesConfig } from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { computeBarLayoutPx } from './findNearestPoint';\n\nexport type PointsAtXMatch = Readonly<{\n seriesIndex: number;\n dataIndex: number;\n point: DataPoint;\n}>;\n\ntype TuplePoint = readonly [x: number, y: number];\ntype ObjectPoint = Readonly<{ x: number; y: number }>;\n\nconst hasNaNXCache = new WeakMap<ReadonlyArray<unknown>, boolean>();\n\nconst seriesHasNaNX = (data: ReadonlyArray<DataPoint>, isTuple: boolean): boolean => {\n if (hasNaNXCache.has(data)) return hasNaNXCache.get(data)!;\n\n let hasNaN = false;\n\n if (isTuple) {\n const tupleData = data as ReadonlyArray<TuplePoint>;\n for (let i = 0; i < tupleData.length; i++) {\n const x = tupleData[i][0];\n if (Number.isNaN(x)) {\n hasNaN = true;\n break;\n }\n }\n } else {\n const objectData = data as ReadonlyArray<ObjectPoint>;\n for (let i = 0; i < objectData.length; i++) {\n const x = objectData[i].x;\n if (Number.isNaN(x)) {\n hasNaN = true;\n break;\n }\n }\n }\n\n hasNaNXCache.set(data, 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 lowerBoundTuple = (data: ReadonlyArray<TuplePoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid][0];\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\nconst lowerBoundObject = (data: ReadonlyArray<ObjectPoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid].x;\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 const data = seriesConfig.data;\n const n = data.length;\n if (n === 0) continue;\n\n const first = data[0];\n const isTuple = Array.isArray(first);\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, isTuple)) {\n // NaN breaks ordering; linear scan for correctness.\n if (isTuple) {\n const tupleData = data as ReadonlyArray<TuplePoint>;\n for (let i = 0; i < n; i++) {\n const px = tupleData[i][0];\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 const objectData = data as ReadonlyArray<ObjectPoint>;\n for (let i = 0; i < n; i++) {\n const px = objectData[i].x;\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 }\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 = isTuple\n ? lowerBoundTuple(data as ReadonlyArray<TuplePoint>, xTargetAdjusted)\n : lowerBoundObject(data as ReadonlyArray<ObjectPoint>, xTargetAdjusted);\n\n const getXCenterAt = (idx: number): number | null => {\n if (idx < 0 || idx >= n) return null;\n const px = isTuple\n ? (data as ReadonlyArray<TuplePoint>)[idx][0]\n : (data as ReadonlyArray<ObjectPoint>)[idx].x;\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 matches.push({ seriesIndex: s, dataIndex: hitIndex, point: data[hitIndex] as DataPoint });\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 bestPoint = data[idx] as DataPoint;\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, isTuple)) {\n if (isTuple) {\n const tupleData = data as ReadonlyArray<TuplePoint>;\n for (let i = 0; i < n; i++) {\n const px = tupleData[i][0];\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 objectData = data as ReadonlyArray<ObjectPoint>;\n for (let i = 0; i < n; i++) {\n const px = objectData[i].x;\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 }\n } else if (isTuple) {\n const tupleData = data as ReadonlyArray<TuplePoint>;\n const insertionIndex = lowerBoundTuple(tupleData, xTarget);\n\n let left = insertionIndex - 1;\n let right = insertionIndex;\n\n const dxSqAt = (idx: number): number | null => {\n const px = tupleData[idx][0];\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 } else {\n const objectData = data as ReadonlyArray<ObjectPoint>;\n const insertionIndex = lowerBoundObject(objectData, xTarget);\n\n let left = insertionIndex - 1;\n let right = insertionIndex;\n\n const dxSqAt = (idx: number): number | null => {\n const px = objectData[idx].x;\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 (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).\n let total = 0;\n let validCount = 0;\n for (let i = 0; i < data.length; i++) {\n const v = data[i]?.value;\n if (typeof v === 'number' && Number.isFinite(v) && v > 0) {\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\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 const end = wrapToTau(current + span);\n current = end;\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 ","/**\n * Shared axis label styling utilities.\n * Ensures consistent styling between main thread (DOM overlay) and worker thread rendering.\n */\n\nimport type { AxisLabel } from '../config/types.js';\nimport type { TextOverlay } from '../components/createTextOverlay.js';\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 label: AxisLabel,\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 (label.isTitle) {\n span.style.fontWeight = '600';\n }\n}\n\n/**\n * Adds axis labels to a text overlay with consistent styling.\n */\nexport function addAxisLabelsToOverlay(\n overlay: TextOverlay,\n xLabels: readonly AxisLabel[],\n yLabels: readonly AxisLabel[],\n theme: AxisLabelThemeConfig\n): void {\n // Clear existing labels\n overlay.clear();\n\n const axisNameFontSize = getAxisTitleFontSize(theme.fontSize);\n\n // Add X-axis labels\n for (const label of xLabels) {\n const span = overlay.addLabel(label.text, label.x, label.y, {\n fontSize: label.isTitle ? axisNameFontSize : theme.fontSize,\n color: theme.textColor,\n anchor: label.anchor ?? 'middle',\n rotation: label.rotation,\n });\n styleAxisLabelSpan(span, label, theme);\n }\n\n // Add Y-axis labels\n for (const label of yLabels) {\n const span = overlay.addLabel(label.text, label.x, label.y, {\n fontSize: label.isTitle ? axisNameFontSize : theme.fontSize,\n color: theme.textColor,\n anchor: label.anchor ?? 'end',\n rotation: label.rotation,\n });\n styleAxisLabelSpan(span, label, theme);\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): 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 = 'none';\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 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\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\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\n item.appendChild(swatch);\n item.appendChild(label);\n items.push(item);\n }\n } else {\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\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\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 ResolvedAreaSeriesConfig,\n ResolvedBarSeriesConfig,\n ResolvedCandlestickSeriesConfig,\n ResolvedChartGPUOptions,\n ResolvedPieSeriesConfig,\n} from '../config/OptionResolver';\nimport type { AnimationConfig, AxisLabel, DataPoint, DataPointTuple, LegendItem, PointerEventData, OHLCDataPoint, OHLCDataPointTuple, PieCenter, PieRadius, TooltipData } from '../config/types';\nimport type { SupportedCanvas } from './GPUContext';\nimport { isHTMLCanvasElement as isHTMLCanvasElementGPU } from './GPUContext';\nimport { createDataStore } from '../data/createDataStore';\nimport { sampleSeriesDataPoints } from '../data/sampleSeries';\nimport { ohlcSample } from '../data/ohlcSample';\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 type { CrosshairRenderOptions } from '../renderers/createCrosshairRenderer';\nimport { createHighlightRenderer } from '../renderers/createHighlightRenderer';\nimport type { HighlightPoint } from '../renderers/createHighlightRenderer';\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 type { NearestPointMatch } from '../interaction/findNearestPoint';\nimport { findPointsAtX } from '../interaction/findPointsAtX';\nimport { computeCandlestickBodyWidthRange, findCandlestick } from '../interaction/findCandlestick';\nimport type { CandlestickMatch } from '../interaction/findCandlestick';\nimport { findPieSlice } from '../interaction/findPieSlice';\nimport type { PieSliceMatch } 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 { getAxisTitleFontSize, styleAxisLabelSpan } from '../utils/axisLabelStyling';\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: SupportedCanvas | 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, width/DPR for OffscreenCanvas. */\nfunction getCanvasCssWidth(canvas: SupportedCanvas | null, devicePixelRatio: number = 1): number {\n if (!canvas) {\n return 0;\n }\n if (isHTMLCanvasElement(canvas)) {\n return canvas.clientWidth;\n }\n // OffscreenCanvas: width property is in device pixels. Convert to CSS pixels by dividing by DPR.\n return canvas.width / devicePixelRatio;\n}\n\n/** Gets canvas CSS height - clientHeight for HTMLCanvasElement, height/DPR for OffscreenCanvas. */\nfunction getCanvasCssHeight(canvas: SupportedCanvas | null, devicePixelRatio: number = 1): number {\n if (!canvas) {\n return 0;\n }\n if (isHTMLCanvasElement(canvas)) {\n return canvas.clientHeight;\n }\n // OffscreenCanvas: height property is in device pixels. Convert to CSS pixels by dividing by DPR.\n return canvas.height / devicePixelRatio;\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 /**\n * Accepts a pointer event with pre-computed grid coordinates for worker thread event forwarding.\n * Only available when domOverlays is false.\n */\n handlePointerEvent(event: PointerEventData): 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 * When false, DOM overlays (tooltip, legend, text overlay, event manager) are disabled.\n * Instead, callbacks are used to emit data for external rendering.\n * Default: true (DOM overlays enabled).\n */\n readonly domOverlays?: boolean;\n /**\n * Called when tooltip data changes (only when domOverlays is false).\n * Receives tooltip data including content, params array, and position, or null when hidden.\n */\n readonly onTooltipUpdate?: (data: TooltipData | null) => void;\n /**\n * Called when legend items change (only when domOverlays is false).\n */\n readonly onLegendUpdate?: (items: ReadonlyArray<LegendItem>) => void;\n /**\n * Called when axis labels change (only when domOverlays is false).\n */\n readonly onAxisLabelsUpdate?: (xLabels: ReadonlyArray<AxisLabel>, yLabels: ReadonlyArray<AxisLabel>) => void;\n /**\n * Called when hover state changes (only when domOverlays is false).\n */\n readonly onHoverChange?: (payload: ChartGPUEventPayload | null) => void;\n /**\n * Called when crosshair moves (only when domOverlays is false).\n * Receives canvas-local CSS pixel x coordinate, or null when crosshair is hidden.\n */\n readonly onCrosshairMove?: (x: number | null) => void;\n /**\n * Called when user taps/clicks (only when domOverlays is false).\n * Includes hit test result with seriesIndex, dataIndex, and value.\n * Main thread is responsible for tap detection; worker thread performs hit testing.\n */\n readonly onClickData?: (payload: {\n readonly x: number;\n readonly y: number;\n readonly gridX: number;\n readonly gridY: number;\n readonly isInGrid: boolean;\n readonly nearest: NearestPointMatch | null;\n readonly pieSlice: PieSliceMatch | null;\n readonly candlestick: CandlestickMatch | null;\n }) => 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;\nconst DEFAULT_TICK_LENGTH_CSS_PX: number = 6;\nconst LABEL_PADDING_CSS_PX = 4;\nconst DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX = 1;\nconst DEFAULT_HIGHLIGHT_SIZE_CSS_PX = 4;\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\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 // Try to seed from the appended points.\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 = 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 const data = seriesConfig.data;\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\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 // - Invalid dimensions from OffscreenCanvas in worker mode\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/**\n * Estimates the maximum width of Y-axis tick labels in CSS pixels.\n * Used in worker mode where DOM measurement is not available.\n *\n * Uses a heuristic: ~0.6 * fontSize per character for typical numeric labels.\n * This is conservative and should prevent overlap in most cases.\n */\nconst estimateMaxYTickLabelWidth = (\n yLabels: ReadonlyArray<{ readonly text: string }>,\n fontSize: number\n): number => {\n if (yLabels.length === 0) return 0;\n\n // Find the longest label text\n const maxChars = yLabels.reduce((max, label) => Math.max(max, label.text.length), 0);\n\n // Estimate width: ~0.6 * fontSize per character for typical monospace-ish numeric text\n // This is conservative to prevent overlap\n return Math.ceil(maxChars * fontSize * 0.6);\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\ntype TuplePoint = DataPointTuple;\ntype ObjectPoint = Readonly<{ x: number; y: number; size?: number }>;\n\nconst isTuplePoint = (p: DataPoint): p is TuplePoint => Array.isArray(p);\nconst isTupleDataArray = (data: ReadonlyArray<DataPoint>): data is ReadonlyArray<TuplePoint> =>\n data.length > 0 && isTuplePoint(data[0]!);\n\n// Cache monotonicity checks to avoid O(n) scans on every zoom operation.\nconst monotonicXCache = new WeakMap<ReadonlyArray<DataPoint>, boolean>();\n\nconst isMonotonicNonDecreasingFiniteX = (data: ReadonlyArray<DataPoint>, isTuple: boolean): boolean => {\n const cached = monotonicXCache.get(data);\n if (cached !== undefined) return cached;\n\n let prevX = Number.NEGATIVE_INFINITY;\n\n if (isTuple) {\n const tupleData = data as ReadonlyArray<TuplePoint>;\n for (let i = 0; i < tupleData.length; i++) {\n const x = tupleData[i][0];\n if (!Number.isFinite(x)) {\n monotonicXCache.set(data, false);\n return false;\n }\n if (x < prevX) {\n monotonicXCache.set(data, false);\n return false;\n }\n prevX = x;\n }\n monotonicXCache.set(data, true);\n return true;\n }\n\n const objectData = data as ReadonlyArray<ObjectPoint>;\n for (let i = 0; i < objectData.length; i++) {\n const x = objectData[i].x;\n if (!Number.isFinite(x)) {\n monotonicXCache.set(data, false);\n return false;\n }\n if (x < prevX) {\n monotonicXCache.set(data, false);\n return false;\n }\n prevX = x;\n }\n monotonicXCache.set(data, true);\n return true;\n};\n\nconst lowerBoundXTuple = (data: ReadonlyArray<TuplePoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid][0];\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\nconst upperBoundXTuple = (data: ReadonlyArray<TuplePoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid][0];\n if (x <= xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\nconst lowerBoundXObject = (data: ReadonlyArray<ObjectPoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid].x;\n if (x < xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\nconst upperBoundXObject = (data: ReadonlyArray<ObjectPoint>, xTarget: number): number => {\n let lo = 0;\n let hi = data.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const x = data[mid].x;\n if (x <= xTarget) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n};\n\nconst sliceVisibleRangeByX = (data: ReadonlyArray<DataPoint>, xMin: number, xMax: number): ReadonlyArray<DataPoint> => {\n const n = data.length;\n if (n === 0) return data;\n if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return data;\n\n const isTuple = isTupleDataArray(data);\n const canBinarySearch = isMonotonicNonDecreasingFiniteX(data, isTuple);\n\n if (canBinarySearch) {\n const lo = isTuple\n ? lowerBoundXTuple(data as ReadonlyArray<TuplePoint>, xMin)\n : lowerBoundXObject(data as ReadonlyArray<ObjectPoint>, xMin);\n const hi = isTuple\n ? upperBoundXTuple(data as ReadonlyArray<TuplePoint>, xMax)\n : upperBoundXObject(data as ReadonlyArray<ObjectPoint>, 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 x).\n const out: DataPoint[] = [];\n for (let i = 0; i < n; i++) {\n const p = data[i]!;\n const { x } = getPointXY(p);\n if (!Number.isFinite(x)) continue;\n if (x >= xMin && x <= xMax) out.push(p);\n }\n return out;\n};\n\nconst findVisibleRangeIndicesByX = (\n data: ReadonlyArray<DataPoint>,\n xMin: number,\n xMax: number\n): { readonly start: number; readonly end: number } => {\n const n = data.length;\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 isTuple = isTupleDataArray(data);\n const canBinarySearch = isMonotonicNonDecreasingFiniteX(data, isTuple);\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 = isTuple\n ? lowerBoundXTuple(data as ReadonlyArray<TuplePoint>, xMin)\n : lowerBoundXObject(data as ReadonlyArray<ObjectPoint>, xMin);\n const end = isTuple\n ? upperBoundXTuple(data as ReadonlyArray<TuplePoint>, xMax)\n : upperBoundXObject(data as ReadonlyArray<ObjectPoint>, 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\nfunction 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.\nconst monotonicTimestampCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, boolean>();\n\nconst 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\nconst 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\nconst 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\ntype OHLCObjectPoint = Readonly<{ timestamp: number; open: number; close: number; low: number; high: number }>;\n\nconst lowerBoundTimestampObject = (data: ReadonlyArray<OHLCObjectPoint>, 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\nconst upperBoundTimestampObject = (data: ReadonlyArray<OHLCObjectPoint>, 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 * Slices OHLC/candlestick data to the visible timestamp range [xMin, xMax].\n *\n * Uses binary search when timestamps are sorted ascending; otherwise falls back to linear scan.\n */\nconst 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<OHLCObjectPoint>, xMin);\n const hi = isTuple\n ? upperBoundTimestampTuple(data as ReadonlyArray<OHLCDataPointTuple>, xMax)\n : upperBoundTimestampObject(data as ReadonlyArray<OHLCObjectPoint>, 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\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 DEFAULT_MAX_TICK_FRACTION_DIGITS = 6;\n\nconst 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\nconst createTickFormatter = (tickStep: number): Intl.NumberFormat => {\n const maximumFractionDigits = computeMaxFractionDigitsFromStep(tickStep);\n return new Intl.NumberFormat(undefined, { maximumFractionDigits });\n};\n\nconst 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\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\nconst computeBaseYDomain = (\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 yMin = finiteOrUndefined(options.yAxis.min) ?? bounds.yMin;\n const yMax = finiteOrUndefined(options.yAxis.max) ?? 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 | OffscreenCanvas\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 // In worker mode (OffscreenCanvas), offsetLeft/offsetTop don't exist - return canvas-local coordinates\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;\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\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: GPUContextLike,\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 and domOverlays !== false.\n // OffscreenCanvas is for rendering only.\n const domOverlaysEnabled = callbacks?.domOverlays !== false;\n const overlayContainer = domOverlaysEnabled && isHTMLCanvasElement(gpuContext.canvas) ? gpuContext.canvas.parentElement : null;\n const overlay: TextOverlay | null = overlayContainer ? createTextOverlay(overlayContainer) : null;\n const legend: Legend | null = overlayContainer ? createLegend(overlayContainer, 'right') : 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\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 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 // 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/crosshair callbacks\n const showTooltipInternal = (x: number, y: number, content: string, params: TooltipParams | TooltipParams[]) => {\n tooltip?.show(x, y, content);\n if (!domOverlaysEnabled && callbacks?.onTooltipUpdate) {\n const paramsArray = Array.isArray(params) ? params : [params];\n callbacks.onTooltipUpdate({ content, params: paramsArray, x, y });\n }\n };\n\n const hideTooltipInternal = () => {\n tooltip?.hide();\n if (!domOverlaysEnabled && callbacks?.onTooltipUpdate) {\n callbacks.onTooltipUpdate(null);\n }\n };\n\n const hideTooltip = () => {\n lastTooltipContent = null;\n lastTooltipX = null;\n lastTooltipY = null;\n hideTooltipInternal();\n };\n\n const emitCrosshairCallback = (x: number | null) => {\n if (!domOverlaysEnabled && callbacks?.onCrosshairMove) {\n callbacks.onCrosshairMove(x);\n }\n };\n\n const emitHoverCallback = (payload: ChartGPUEventPayload | null) => {\n if (!domOverlaysEnabled && callbacks?.onHoverChange) {\n callbacks.onHoverChange(payload);\n }\n };\n\n const updateLegend = (series: ResolvedChartGPUOptions['series'], theme: ResolvedChartGPUOptions['theme']) => {\n legend?.update(series, theme);\n if (!domOverlaysEnabled && callbacks?.onLegendUpdate) {\n const items: LegendItem[] = series.map((s, idx) => ({\n name: s.name ?? '',\n color: s.color ?? '#888',\n seriesIndex: idx,\n }));\n callbacks.onLegendUpdate(items);\n }\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 const initialGridArea = computeGridArea(gpuContext, currentOptions);\n \n // Event manager requires HTMLCanvasElement (DOM events) and domOverlays enabled.\n // OffscreenCanvas doesn't support interactive features.\n const eventManager = domOverlaysEnabled && 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 ReadonlyArray<DataPoint>;\n raw = seed.length === 0 ? [] : seed.slice();\n runtimeRawDataByIndex[seriesIndex] = raw;\n runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? computeRawBoundsFromData(raw);\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 if (\n s.type === 'line' &&\n s.sampling === 'none' &&\n isFullSpanZoomBefore &&\n gpuSeriesKindByIndex[seriesIndex] === 'fullRawLine'\n ) {\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 }\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 }\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 } 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: SupportedCanvas,\n gridArea: GridArea\n ): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n let canvasWidthCss: number;\n let canvasHeightCss: number;\n\n if (isHTMLCanvasElement(canvas)) {\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 } else {\n // OffscreenCanvas: calculate CSS pixels from canvas dimensions divided by device pixel ratio\n const dpr = gpuContext.devicePixelRatio ?? 1.0;\n console.log('[getPlotSizeCssPx] OffscreenCanvas dimensions:', {\n canvasWidth: canvas.width,\n canvasHeight: canvas.height,\n dpr,\n calculatedCssWidth: canvas.width / dpr,\n calculatedCssHeight: canvas.height / dpr\n });\n canvasWidthCss = canvas.width / dpr;\n canvasHeightCss = canvas.height / dpr;\n if (!(canvasWidthCss > 0) || !(canvasHeightCss > 0)) return null;\n }\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 // Support both HTMLCanvasElement and OffscreenCanvas for worker thread compatibility\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 console.log('[computeInteractionScalesGridCssPx] Computed interaction scales:', {\n canvasType: isHTMLCanvasElement(canvas) ? 'HTMLCanvasElement' : 'OffscreenCanvas',\n plotWidthCss: result.plotWidthCss,\n plotHeightCss: result.plotHeightCss,\n xDomain: domains.xDomain,\n yDomain: domains.yDomain,\n xRange: [0, plotSize.plotWidthCss],\n yRange: [plotSize.plotHeightCss, 0]\n });\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 for (let i = currentOptions.series.length - 1; i >= 0; i--) {\n const s = 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) 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 for (let i = series.length - 1; i >= 0; i--) {\n const s = series[i];\n if (s.type !== 'candlestick') 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 emitCrosshairCallback(payload.isInGrid ? payload.x : null);\n emitHoverCallback(payload.isInGrid ? payload : null);\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 emitCrosshairCallback(null);\n emitHoverCallback(null);\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 ReadonlyArray<DataPoint> | null) ??\n ((s.rawData ?? s.data) as ReadonlyArray<DataPoint>);\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 // Slice cached data immediately for smooth panning\n sliceRenderSeriesToVisibleRange();\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 ReadonlyArray<DataPoint>;\n // Coordinator-owned: copy into a mutable array (streaming appends mutate this).\n const owned = raw.length === 0 ? [] : raw.slice();\n runtimeRawDataByIndex[i] = owned;\n runtimeRawBoundsByIndex[i] = s.rawBounds ?? computeRawBoundsFromData(owned);\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) ?? ((s.rawData ?? s.data) as ReadonlyArray<DataPoint>);\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 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 unknown as ReadonlyArray<OHLCDataPoint>, visibleX.min, visibleX.max)\n };\n } else {\n next[i] = {\n ...baseline,\n data: sliceVisibleRangeByX(cache.data as unknown as ReadonlyArray<DataPoint>, 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 ReadonlyArray<DataPoint>, visibleX.min, visibleX.max)\n };\n }\n }\n\n renderSeries = next;\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) ?? ((s.rawData ?? s.data) as ReadonlyArray<DataPoint>);\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, sampling, target);\n\n // Store sampled data in cache with buffered range\n lastSampledData[i] = {\n data: sampled,\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, visibleX.min, visibleX.max);\n next[i] = { ...s, data: visibleSampled };\n }\n\n renderSeries = next;\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 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);\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\n currentOptions = resolvedOptions;\n runtimeBaseSeries = resolvedOptions.series;\n renderSeries = resolvedOptions.series;\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 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);\n const toSeriesForTransition = renderSeries;\n\n const domainChanged = !isDomainEqual(fromSnapshot.xBaseDomain, toXBase) || !isDomainEqual(fromSnapshot.yBaseDomain, toYBase);\n\n const shouldAnimateUpdate = hasRenderedOnce && (domainChanged || likelyDataChanged);\n if (!shouldAnimateUpdate) return;\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\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 shouldRenderArea = (series: ResolvedChartGPUOptions['series'][number]): boolean => {\n switch (series.type) {\n case 'area':\n return true;\n case 'line':\n return series.areaStyle != null;\n case 'bar':\n return false;\n case 'scatter':\n return false;\n case 'pie':\n return false;\n case 'candlestick':\n return false;\n default:\n return assertUnreachable(series);\n }\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 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 if (s.data.length > 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);\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 // 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 dpr = gridArea.devicePixelRatio;\n const canvasCssWidth = gpuContext.canvas ? getCanvasCssWidth(gpuContext.canvas, dpr) : 0;\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 gridRenderer.prepare(gridArea, { color: currentOptions.theme.gridLineColor });\n if (hasCartesianSeries) {\n xAxisRenderer.prepare(\n currentOptions.xAxis,\n xScale,\n 'x',\n gridArea,\n currentOptions.theme.axisLineColor,\n currentOptions.theme.axisTickColor,\n xTickCount\n );\n 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 prepare uses canvas-local CSS px (EventManager payload x/y) and current gridArea.\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 crosshairRenderer.prepare(effectivePointer.x, effectivePointer.y, gridArea, crosshairOptions);\n crosshairRenderer.setVisible(true);\n emitCrosshairCallback(effectivePointer.x);\n } else {\n crosshairRenderer.setVisible(false);\n emitCrosshairCallback(null);\n }\n\n // Highlight: on hover, find nearest point and draw a ring highlight clipped to plot rect.\n if (effectivePointer.source === 'mouse' && effectivePointer.hasPointer && effectivePointer.isInGrid) {\n if (interactionScales) {\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 highlightRenderer.prepare(point, seriesColor, DEFAULT_HIGHLIGHT_SIZE_CSS_PX);\n highlightRenderer.setVisible(true);\n } else {\n highlightRenderer.setVisible(false);\n }\n } else {\n highlightRenderer.setVisible(false);\n }\n } else {\n highlightRenderer.setVisible(false);\n }\n } else {\n highlightRenderer.setVisible(false);\n }\n\n // Tooltip: on hover, find matches and render tooltip near cursor.\n // Note: Tooltips require HTMLCanvasElement (DOM-specific positioning) for DOM rendering.\n // However, in worker mode (!domOverlaysEnabled), we still need to run hit-testing and callbacks.\n if (effectivePointer.hasPointer && effectivePointer.isInGrid && currentOptions.tooltip?.show !== false) {\n const canvas = gpuContext.canvas;\n\n console.log('[Tooltip block] State check:', {\n hasInteractionScales: !!interactionScales,\n domOverlaysEnabled,\n hasCanvas: !!canvas,\n canvasType: canvas ? (isHTMLCanvasElement(canvas) ? 'HTMLCanvasElement' : 'OffscreenCanvas') : 'null',\n interactionScales: interactionScales ? {\n plotWidthCss: interactionScales.plotWidthCss,\n plotHeightCss: interactionScales.plotHeightCss\n } : null\n });\n\n if (interactionScales && (!domOverlaysEnabled || (canvas && isHTMLCanvasElement(canvas)))) {\n const formatter = currentOptions.tooltip?.formatter;\n const trigger = currentOptions.tooltip?.trigger ?? 'item';\n\n // In worker mode (OffscreenCanvas), offsetLeft/offsetTop don't exist\n // Use effectivePointer coordinates directly as they're already in container-local CSS pixels\n const containerX = isHTMLCanvasElement(canvas) ? canvas.offsetLeft + effectivePointer.x : effectivePointer.x;\n const containerY = isHTMLCanvasElement(canvas) ? canvas.offsetTop + effectivePointer.y : 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 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 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 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 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 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 const defaultBaseline = currentOptions.yAxis.min ?? yBaseDomain.min;\n const barSeriesConfigs: ResolvedBarSeriesConfig[] = [];\n\n const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n\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 areaRenderers[i].prepare(s, s.data, 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 if (!appendedGpuThisFrame.has(i)) {\n dataStore.setSeries(i, s.data);\n }\n const buffer = dataStore.getSeriesBuffer(i);\n lineRenderers[i].prepare(s, buffer, xScale, yScale);\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 areaRenderers[i].prepare(areaLike, areaLike.data, 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 const rawData = s.rawData ?? s.data;\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 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 scatterRenderers[i].prepare(animated, s.data, 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) {\n const canvas = gpuContext.canvas;\n const plotWidthCss = interactionScales?.plotWidthCss ?? (canvas && isHTMLCanvasElement(canvas) ? getPlotSizeCssPx(canvas, gridArea)?.plotWidthCss : null);\n const plotHeightCss =\n interactionScales?.plotHeightCss ?? (canvas && isHTMLCanvasElement(canvas) ? getPlotSizeCssPx(canvas, gridArea)?.plotHeightCss : null);\n const maxRadiusCss =\n typeof plotWidthCss === 'number' && typeof plotHeightCss === 'number'\n ? 0.5 * Math.min(plotWidthCss, plotHeightCss)\n : 0;\n\n if (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 pieRenderers[i].prepare(animated, gridArea);\n break;\n }\n }\n pieRenderers[i].prepare(s, gridArea);\n break;\n }\n case 'candlestick': {\n // Candlestick renderer handles clipping internally, no intro animation for now.\n candlestickRenderers[i].prepare(s, s.data, xScale, yScale, gridArea, currentOptions.theme.backgroundColor);\n break;\n }\n default:\n assertUnreachable(s);\n }\n }\n\n // Bars are prepared once and rendered via a single instanced draw call.\n const yScaleForBars = introP < 1 ? createAnimatedBarYScale(yScale, plotClipRect, barSeriesConfigs, introP) : yScale;\n barRenderer.prepare(barSeriesConfigs, dataStore, xScale, yScaleForBars, gridArea);\n\n const textureView = 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 for (let i = 0; i < seriesForRender.length; i++) {\n const s = seriesForRender[i];\n if (s.type === 'scatter' && s.mode === 'density') {\n scatterDensityRenderers[i].encodeCompute(encoder);\n }\n }\n\n const pass = encoder.beginRenderPass({\n label: 'renderCoordinator/renderPass',\n colorAttachments: [\n {\n view: textureView,\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 gridRenderer.render(pass);\n\n for (let i = 0; i < seriesForRender.length; i++) {\n if (seriesForRender[i].type === 'pie') {\n pieRenderers[i].render(pass);\n }\n }\n\n for (let i = 0; i < seriesForRender.length; i++) {\n if (shouldRenderArea(seriesForRender[i])) {\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 pass.setScissorRect(plotScissor.x, plotScissor.y, w, plotScissor.h);\n areaRenderers[i].render(pass);\n pass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n } else {\n pass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n areaRenderers[i].render(pass);\n pass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n }\n }\n // Clip bars to the plot grid (mirrors area/line scissor usage).\n if (plotScissor.w > 0 && plotScissor.h > 0) {\n pass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n barRenderer.render(pass);\n pass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n for (let i = 0; i < seriesForRender.length; i++) {\n if (seriesForRender[i].type === 'candlestick') {\n candlestickRenderers[i].render(pass);\n }\n }\n for (let i = 0; i < seriesForRender.length; i++) {\n const s = seriesForRender[i];\n if (s.type !== 'scatter') continue;\n if (s.mode === 'density') {\n scatterDensityRenderers[i].render(pass);\n } else {\n scatterRenderers[i].render(pass);\n }\n }\n for (let i = 0; i < seriesForRender.length; i++) {\n if (seriesForRender[i].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 pass.setScissorRect(plotScissor.x, plotScissor.y, w, plotScissor.h);\n lineRenderers[i].render(pass);\n pass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n } else {\n pass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n lineRenderers[i].render(pass);\n pass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n }\n }\n }\n\n highlightRenderer.render(pass);\n if (hasCartesianSeries) {\n xAxisRenderer.render(pass);\n yAxisRenderer.render(pass);\n }\n crosshairRenderer.render(pass);\n\n pass.end();\n device.queue.submit([encoder.finish()]);\n\n hasRenderedOnce = true;\n\n // Generate axis labels for DOM overlay (main thread) or callback (worker mode)\n const shouldGenerateAxisLabels = hasCartesianSeries && (\n (overlay && overlayContainer) || // DOM mode with overlay\n (!domOverlaysEnabled && callbacks?.onAxisLabelsUpdate) // Worker mode with callback\n );\n\n if (shouldGenerateAxisLabels) {\n const canvas = gpuContext.canvas;\n\n // Get canvas dimensions (works for both HTMLCanvasElement and OffscreenCanvas)\n const canvasCssWidth = getCanvasCssWidth(canvas, gpuContext.devicePixelRatio ?? 1);\n const canvasCssHeight = getCanvasCssHeight(canvas, gpuContext.devicePixelRatio ?? 1);\n if (canvasCssWidth <= 0 || canvasCssHeight <= 0) return;\n\n // Calculate offsets (only for DOM mode with HTMLCanvasElement)\n // In worker mode (OffscreenCanvas), offsets are 0 since there's no offsetLeft/offsetTop\n const offsetX = isHTMLCanvasElement(canvas) ? canvas.offsetLeft : 0;\n const offsetY = isHTMLCanvasElement(canvas) ? canvas.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 DOM overlay if it exists\n overlay?.clear();\n\n // Collect axis labels for callback emission\n const collectedXLabels: AxisLabel[] = [];\n const collectedYLabels: AxisLabel[] = [];\n\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 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 // Collect label data for callback (worker mode)\n const axisLabel: AxisLabel = { axis: 'x', text: label, x: offsetX + xCss, y: offsetY + xLabelY, anchor, isTitle: false };\n collectedXLabels.push(axisLabel);\n\n // Add to DOM overlay if it exists (main thread mode)\n if (overlay) {\n const span = overlay.addLabel(label, offsetX + xCss, offsetY + xLabelY, {\n fontSize: currentOptions.theme.fontSize,\n color: currentOptions.theme.textColor,\n anchor,\n });\n styleAxisLabelSpan(span, axisLabel, currentOptions.theme);\n }\n }\n\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 // Collect label data for callback (worker mode)\n const axisLabel: AxisLabel = { axis: 'y', text: label, x: offsetX + yLabelX, y: offsetY + yCss, anchor: 'end', isTitle: false };\n collectedYLabels.push(axisLabel);\n\n // Add to DOM overlay if it exists (main thread mode)\n if (overlay) {\n const span = overlay.addLabel(label, offsetX + yLabelX, offsetY + yCss, {\n fontSize: currentOptions.theme.fontSize,\n color: currentOptions.theme.textColor,\n anchor: 'end',\n });\n styleAxisLabelSpan(span, axisLabel, currentOptions.theme);\n ySpans.push(span);\n }\n }\n\n const axisNameFontSize = getAxisTitleFontSize(currentOptions.theme.fontSize);\n\n const xAxisName = currentOptions.xAxis.name?.trim() ?? '';\n if (xAxisName.length > 0) {\n const xCenter = (plotLeftCss + plotRightCss) / 2;\n // Center title vertically between the tick labels and the zoom slider (when present).\n // The zoom slider is an absolute-positioned overlay at the bottom of the canvas. We reserve\n // additional `grid.bottom` space so tick labels stay visible above it.\n //\n // xLabelY is the vertical center of the tick labels; add half font size to approximate the\n // tick-label \"bottom edge\" and then center the axis title within the remaining space.\n const xTickLabelsBottom = xLabelY + currentOptions.theme.fontSize * 0.5;\n const hasSliderZoom = currentOptions.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n const sliderTrackHeightCssPx = 32; // Keep in sync with ChartGPU/createDataZoomSlider defaults.\n const bottomLimitCss = hasSliderZoom ? canvasCssHeight - sliderTrackHeightCssPx : canvasCssHeight;\n const xTitleY = (xTickLabelsBottom + bottomLimitCss) / 2;\n\n // Collect label data for callback (worker mode)\n const axisLabel: AxisLabel = { axis: 'x', text: xAxisName, x: offsetX + xCenter, y: offsetY + xTitleY, anchor: 'middle', isTitle: true };\n collectedXLabels.push(axisLabel);\n\n // Add to DOM overlay if it exists (main thread mode)\n if (overlay) {\n const span = overlay.addLabel(xAxisName, offsetX + xCenter, offsetY + xTitleY, {\n fontSize: axisNameFontSize,\n color: currentOptions.theme.textColor,\n anchor: 'middle',\n });\n styleAxisLabelSpan(span, axisLabel, currentOptions.theme);\n }\n }\n\n const yAxisName = currentOptions.yAxis.name?.trim() ?? '';\n if (yAxisName.length > 0) {\n // In DOM mode: measure actual rendered label widths\n // In worker mode: estimate based on character count and font size\n const maxTickLabelWidth =\n ySpans.length === 0\n ? estimateMaxYTickLabelWidth(collectedYLabels, currentOptions.theme.fontSize)\n : 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 // Collect label data for callback (worker mode)\n const axisLabel: AxisLabel = { axis: 'y', text: yAxisName, x: offsetX + yTitleX, y: offsetY + yCenter, anchor: 'middle', rotation: -90, isTitle: true };\n collectedYLabels.push(axisLabel);\n\n // Add to DOM overlay if it exists (main thread mode)\n if (overlay) {\n const span = overlay.addLabel(yAxisName, offsetX + yTitleX, offsetY + yCenter, {\n fontSize: axisNameFontSize,\n color: currentOptions.theme.textColor,\n anchor: 'middle',\n rotation: -90,\n });\n styleAxisLabelSpan(span, axisLabel, currentOptions.theme);\n }\n }\n\n // Emit axis labels callback when DOM overlays are disabled (worker mode)\n if (!domOverlaysEnabled && callbacks?.onAxisLabelsUpdate) {\n callbacks.onAxisLabelsUpdate(collectedXLabels, collectedYLabels);\n }\n }\n };\n\n const handlePointerEvent: RenderCoordinator['handlePointerEvent'] = (event) => {\n assertNotDisposed();\n if (domOverlaysEnabled) {\n // When DOM overlays are enabled, ignore handlePointerEvent (use native DOM events instead)\n return;\n }\n\n const canvas = gpuContext.canvas;\n if (!canvas) return;\n\n // Validate event coordinates (guard against NaN/Infinity from worker thread serialization issues)\n if (\n !Number.isFinite(event.x) ||\n !Number.isFinite(event.y) ||\n !Number.isFinite(event.gridX) ||\n !Number.isFinite(event.gridY) ||\n !Number.isFinite(event.plotWidthCss) ||\n !Number.isFinite(event.plotHeightCss)\n ) {\n return;\n }\n\n // Use pre-computed grid coordinates from event\n const { type, x, y, gridX, gridY, plotWidthCss, plotHeightCss, isInGrid } = event;\n\n if (type === 'leave') {\n pointerState = { ...pointerState, isInGrid: false, hasPointer: false };\n crosshairRenderer.setVisible(false);\n lastTooltipContent = null;\n lastTooltipX = null;\n lastTooltipY = null;\n \n hideTooltipInternal();\n emitCrosshairCallback(null);\n emitHoverCallback(null);\n \n setInteractionXInternal(null, 'mouse');\n requestRender();\n return;\n }\n\n if (type === 'move') {\n // Update pointer state for hover/crosshair\n pointerState = {\n source: 'mouse',\n x,\n y,\n gridX,\n gridY,\n isInGrid,\n hasPointer: true,\n };\n\n requestRender();\n return;\n }\n\n if (type === 'click') {\n // Perform hit testing for click events\n if (!callbacks?.onClickData) return;\n\n let nearest: NearestPointMatch | null = null;\n let pieSlice: PieSliceMatch | null = null;\n let candlestick: CandlestickMatch | null = null;\n\n // Use cached interaction scales and render series from last render\n if (isInGrid && lastInteractionScales) {\n // Pie slice hit testing\n pieSlice = findPieSliceAtPointer(\n renderSeries,\n gridX,\n gridY,\n plotWidthCss,\n plotHeightCss\n );\n\n // Candlestick hit testing\n if (!pieSlice) {\n const candlestickResult = findCandlestickAtPointer(\n renderSeries,\n gridX,\n gridY,\n lastInteractionScales\n );\n if (candlestickResult) {\n candlestick = {\n seriesIndex: candlestickResult.seriesIndex,\n dataIndex: candlestickResult.params.dataIndex,\n point: candlestickResult.match.point,\n };\n }\n }\n\n // Nearest point hit testing\n if (!pieSlice && !candlestick) {\n nearest = findNearestPoint(\n renderSeries,\n gridX,\n gridY,\n lastInteractionScales.xScale,\n lastInteractionScales.yScale,\n 20 // maxDistance in CSS pixels\n );\n }\n }\n\n callbacks.onClickData({\n x,\n y,\n gridX,\n gridY,\n isInGrid,\n nearest,\n pieSlice,\n candlestick,\n });\n return;\n }\n\n if (type === 'wheel') {\n // Handle mouse wheel zoom (only when inside grid and zoom is enabled)\n if (!isInGrid || !zoomState) return;\n \n const deltaX = event.deltaX ?? 0;\n const deltaY = event.deltaY ?? 0;\n const deltaMode = event.deltaMode ?? 0;\n \n // Normalize delta to CSS pixels\n const normalizeWheelDelta = (delta: number, basis: number): number => {\n if (!Number.isFinite(delta) || delta === 0) return 0;\n \n switch (deltaMode) {\n case 1: // DOM_DELTA_LINE\n return delta * 16;\n case 2: // DOM_DELTA_PAGE\n return delta * (Number.isFinite(basis) && basis > 0 ? basis : 800);\n default: // DOM_DELTA_PIXEL\n return delta;\n }\n };\n \n const deltaYCss = normalizeWheelDelta(deltaY, plotHeightCss);\n const deltaXCss = normalizeWheelDelta(deltaX, 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 zoomState.pan(deltaPct);\n return;\n }\n \n // Vertical scroll zoom logic\n if (deltaYCss === 0) return;\n \n // Calculate zoom factor from wheel delta\n // Positive delta = scroll down = zoom out; negative = zoom in\n const abs = Math.abs(deltaYCss);\n if (!Number.isFinite(abs) || abs === 0) return;\n \n // Cap extreme deltas (some devices can emit huge values)\n const capped = Math.min(abs, 200);\n const sensitivity = 0.002;\n const factor = Math.exp(capped * sensitivity);\n \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 \n // Calculate zoom center based on pointer position in plot\n const r = Math.min(1, Math.max(0, gridX / plotWidthCss));\n const centerPct = Math.min(100, Math.max(0, start + r * span));\n \n // Apply zoom\n if (deltaYCss < 0) {\n zoomState.zoomIn(centerPct, factor);\n } else {\n zoomState.zoomOut(centerPct, factor);\n }\n \n requestRender();\n return;\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\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 overlay?.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 emitCrosshairCallback(null);\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 handlePointerEvent,\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' },\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 AxisConfig,\n CandlestickItemStyleConfig,\n CandlestickSeriesConfig,\n CandlestickStyle,\n ChartGPUOptions,\n DataPoint,\n DataPointTuple,\n DataZoomConfig,\n GridConfig,\n LineStyleConfig,\n OHLCDataPoint,\n OHLCDataPointTuple,\n AreaSeriesConfig,\n BarSeriesConfig,\n LineSeriesConfig,\n PieDataItem,\n PieSeriesConfig,\n ScatterSeriesConfig,\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';\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<Omit<PieDataItem, 'color'> & { readonly color: string }>;\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'> {\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}\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 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 isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst computeRawBoundsFromData = (data: ReadonlyArray<DataPoint>): RawBounds | undefined => {\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 p = data[i]!;\n const x = isTupleDataPoint(p) ? p[0] : p.x;\n const y = isTupleDataPoint(p) ? p[1] : p.y;\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 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 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 }\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 }\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 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 = computeRawBoundsFromData(s.data);\n return {\n ...s,\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 = computeRawBoundsFromData(s.data);\n const sampledData = sampleSeriesDataPoints(s.data, sampling, samplingThreshold);\n\n return {\n ...rest,\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 = computeRawBoundsFromData(s.data);\n return {\n ...s,\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 = computeRawBoundsFromData(s.data);\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 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 return {\n ...item,\n color: itemColor ?? fallback,\n };\n });\n\n return { ...rest, 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 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 animation,\n theme,\n palette: theme.colorPalette,\n series,\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 * (both main-thread and worker-based) 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","/**\n * ChartGPUWorkerController - Worker-side chart instance manager\n * \n * Manages multiple chart instances via messages from the main thread.\n * Uses a class-based approach (acceptable exception for internal worker singleton managing mutable state).\n * \n * ## Performance Optimizations\n * \n * This implementation is optimized for high-frequency operations:\n * \n * 1. **Shared State Closures**: ChartInstanceState is captured in coordinator callbacks\n * to eliminate Map lookups in hot paths (onRequestRender called on every data update,\n * render loop at 60fps).\n * \n * 2. **Cached Render Loop**: Render callback caches coordinator and state references,\n * avoiding Map lookups on every frame (critical for 60fps performance).\n * \n * 3. **Optimized Deserialization**: deserializeDataPoints uses:\n * - Pre-allocated arrays (no dynamic resizing)\n * - Unrolled offset calculation in loop increment\n * - Early validation (fail fast)\n * \n * 4. **Reduced Branching**: Click handler uses early returns instead of nested conditionals,\n * improving branch prediction and reducing instruction pipeline stalls.\n * \n * 5. **Zero-Copy Data Transfer**: ArrayBuffers are transferred (not cloned) via postMessage,\n * eliminating serialization overhead for large datasets.\n * \n * 6. **Batch Validation**: appendDataBatch validates all items upfront before processing,\n * ensuring transactional behavior and avoiding partial updates on error.\n */\n\nimport type {\n WorkerInboundMessage,\n WorkerOutboundMessage,\n InitMessage,\n ResizeMessage,\n ErrorMessage,\n} from './protocol';\nimport type {\n DataPoint,\n OHLCDataPoint,\n ChartGPUOptions,\n PerformanceMetrics,\n PerformanceCapabilities,\n ExactFPS,\n Milliseconds,\n Bytes,\n FrameTimeStats,\n GPUTimingStats,\n MemoryStats,\n FrameDropStats,\n} from '../config/types';\nimport { createGPUContext, initializeGPUContext, destroyGPUContext, type GPUContextState } from '../core/GPUContext';\nimport { createRenderCoordinator, type RenderCoordinator } from '../core/createRenderCoordinator';\nimport { resolveOptionsForChart } from '../config/OptionResolver';\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 * Performance tracking state for a chart instance.\n * Circular buffer pattern for exact FPS measurement.\n */\ninterface PerformanceTrackingState {\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 lastFrameTime: number;\n \n // GPU timing (optional)\n gpuTimingEnabled: boolean;\n lastCPUTime: number;\n lastGPUTime: number;\n}\n\n/**\n * Mutable state flags for a chart instance.\n * Shared between ChartInstance and coordinator callbacks for optimal performance.\n */\ninterface ChartInstanceState {\n renderPending: boolean;\n disposed: boolean;\n deviceLost: boolean;\n performance: PerformanceTrackingState;\n}\n\n/**\n * Represents a chart instance managed by the worker.\n * Contains all state needed for rendering and interaction.\n */\ninterface ChartInstance {\n readonly chartId: string;\n gpuContext: GPUContextState;\n readonly coordinator: RenderCoordinator;\n readonly canvas: OffscreenCanvas;\n readonly renderChannel: MessageChannel;\n /** Shared mutable state (avoid Map lookups in hot paths) */\n readonly state: ChartInstanceState;\n}\n\n/**\n * Error codes for categorizing worker errors.\n */\ntype ErrorCode = 'WEBGPU_INIT_FAILED' | 'DEVICE_LOST' | 'RENDER_ERROR' | 'DATA_ERROR' | 'UNKNOWN';\n\n/**\n * Performance-optimized validation helper for seriesIndex.\n * Extracted to reduce code duplication and improve performance.\n * \n * @param seriesIndex - Series index to validate\n * @param context - Context string for error message\n * @throws {Error} If validation fails\n */\nfunction validateSeriesIndex(seriesIndex: number, context: string): void {\n if (!Number.isInteger(seriesIndex) || seriesIndex < 0) {\n throw new Error(`Invalid seriesIndex ${context}: ${seriesIndex}. Must be a non-negative integer.`);\n }\n}\n\n/**\n * Performance-optimized validation helper for pointCount.\n * Extracted to reduce code duplication and improve performance.\n * \n * @param pointCount - Point count to validate\n * @param context - Context string for error message\n * @throws {Error} If validation fails\n */\nfunction validatePointCount(pointCount: number, context: string): void {\n if (!Number.isInteger(pointCount) || pointCount < 0) {\n throw new Error(`Invalid pointCount ${context}: ${pointCount}. Must be a non-negative integer.`);\n }\n}\n\n/**\n * Performance-optimized error message extractor.\n * Reduces repeated instanceof checks in hot paths.\n * \n * @param error - Error object or value\n * @returns Tuple of [message, stack]\n */\nfunction extractErrorInfo(error: unknown): [string, string | undefined] {\n if (error instanceof Error) {\n return [error.message, error.stack];\n }\n return [String(error), undefined];\n}\n\n/**\n * ChartGPUWorkerController - Singleton worker-side controller.\n * \n * Manages multiple chart instances and handles message-based communication\n * with the main thread. Uses class-based approach as acceptable exception\n * for internal worker singleton managing mutable state.\n */\nexport class ChartGPUWorkerController {\n private readonly charts = new Map<string, ChartInstance>();\n private messageHandler: ((msg: WorkerOutboundMessage) => void) | null = null;\n\n /**\n * Registers a message handler to send outbound messages to the main thread.\n * \n * @param handler - Function to call when emitting messages to main thread\n */\n onMessage(handler: (msg: WorkerOutboundMessage) => void): void {\n this.messageHandler = handler;\n }\n\n /**\n * Main entry point for handling inbound messages from the main thread.\n * Routes messages to appropriate handlers with exhaustive type checking.\n * \n * @param msg - Inbound message from main thread\n */\n async handleMessage(msg: WorkerInboundMessage): Promise<void> {\n try {\n switch (msg.type) {\n case 'init':\n await this.initChart(msg);\n break;\n case 'setOption':\n this.handleSetOption(msg.chartId, msg.options);\n break;\n case 'appendData':\n this.handleAppendData(msg.chartId, msg.seriesIndex, msg.data, msg.pointCount, msg.stride);\n break;\n case 'appendDataBatch':\n this.handleAppendDataBatch(msg.chartId, msg.items);\n break;\n case 'resize':\n this.handleResize(msg.chartId, msg);\n break;\n case 'forwardPointerEvent':\n this.handlePointerEvent(msg.chartId, msg.event);\n break;\n case 'setZoomRange':\n this.handleSetZoomRange(msg.chartId, msg.start, msg.end);\n break;\n case 'setInteractionX':\n this.handleSetInteractionX(msg.chartId, msg.x, msg.source);\n break;\n case 'setAnimation':\n this.handleSetAnimation(msg.chartId, msg.enabled, msg.config);\n break;\n case 'setGPUTiming':\n this.handleSetGPUTiming(msg.chartId, msg.enabled);\n break;\n case 'dispose':\n this.disposeChart(msg.chartId);\n break;\n default:\n // Exhaustive type check - ensures we handle all message types\n const exhaustive: never = msg;\n this.emitError(\n '', // No chartId available for unknown message\n 'UNKNOWN',\n `Unknown message type: ${(exhaustive as any).type}`,\n 'handleMessage'\n );\n }\n } catch (error) {\n // Catch any unhandled errors and emit error message\n const chartId = 'chartId' in msg ? msg.chartId : '';\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n \n this.emitError(chartId, 'UNKNOWN', message, 'handleMessage', stack);\n }\n }\n\n /**\n * Initializes a new chart instance with WebGPU context and render coordinator.\n * \n * @param msg - Init message containing canvas, options, and configuration\n */\n private async initChart(msg: InitMessage): Promise<void> {\n let renderChannel: MessageChannel | null = null;\n\n try {\n // Ensure chart doesn't already exist\n if (this.charts.has(msg.chartId)) {\n this.emitError(\n msg.chartId,\n 'UNKNOWN',\n `Chart with ID \"${msg.chartId}\" already exists`,\n 'init',\n undefined,\n msg.messageId\n );\n return;\n }\n\n // Validate devicePixelRatio\n if (msg.devicePixelRatio <= 0) {\n throw new Error(`Invalid devicePixelRatio: ${msg.devicePixelRatio}. Must be positive.`);\n }\n\n // Create GPU context with OffscreenCanvas\n const gpuOptions = {\n devicePixelRatio: msg.devicePixelRatio,\n powerPreference: msg.gpuOptions?.powerPreference,\n };\n const gpuContext = createGPUContext(msg.canvas, gpuOptions);\n let initializedContext = await initializeGPUContext(gpuContext);\n\n // Resolve chart options with slider bottom-space reservation\n const resolvedOptions = resolveOptionsForChart(msg.options);\n\n // Create MessageChannel for render scheduling\n renderChannel = new MessageChannel();\n \n // PERFORMANCE: Pre-create shared instance state that will be captured in coordinator callbacks\n // This avoids Map lookups in hot paths (onRequestRender called on every data update/zoom/resize)\n // CRITICAL: Must be declared BEFORE device.lost handler to avoid ReferenceError\n const performanceState: PerformanceTrackingState = {\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 lastFrameTime: 0,\n gpuTimingEnabled: false,\n lastCPUTime: 0,\n lastGPUTime: 0,\n };\n\n const state: ChartInstanceState = {\n renderPending: false,\n disposed: false,\n deviceLost: false,\n performance: performanceState,\n };\n\n // Set up early device loss monitoring (before coordinator creation)\n // This catches device loss during initialization\n // PERFORMANCE: Capture state reference to avoid Map lookup in device.lost handler\n if (initializedContext.device) {\n initializedContext.device.lost.then((info) => {\n state.deviceLost = true;\n this.emit({\n type: 'deviceLost',\n chartId: msg.chartId,\n reason: info.reason === 'destroyed' ? 'destroyed' : 'unknown',\n message: info.message || info.reason || 'Device lost during initialization',\n });\n }).catch(() => {\n // Ignore errors in device.lost promise (can occur if device is destroyed before lost promise resolves)\n });\n\n // Set up uncaptured error handler for GPU validation errors\n initializedContext.device.addEventListener('uncapturederror', (event: GPUUncapturedErrorEvent) => {\n const errorMessage = event.error instanceof GPUValidationError\n ? `WebGPU Validation Error: ${event.error.message}`\n : event.error instanceof GPUOutOfMemoryError\n ? `WebGPU Out of Memory: ${event.error.message}`\n : `WebGPU Error: ${event.error.message}`;\n \n this.emitError(msg.chartId, 'RENDER_ERROR', errorMessage, 'uncaptured_gpu_error');\n });\n }\n\n // Create render coordinator with worker-mode callbacks\n const coordinator = createRenderCoordinator(\n initializedContext,\n resolvedOptions,\n {\n // CRITICAL: Disable DOM overlays for worker mode\n domOverlays: false,\n\n // Request render via MessageChannel for efficient scheduling\n // PERFORMANCE: Use closure-captured state instead of Map lookup (critical for 60fps)\n // CRITICAL: Post to port2, listen on port1 (MessageChannel requires opposite ends)\n onRequestRender: () => {\n if (!state.renderPending && !state.disposed && renderChannel) {\n state.renderPending = true;\n renderChannel.port2.postMessage(null);\n }\n },\n\n // Emit tooltip updates to main thread for DOM rendering\n onTooltipUpdate: (data) => {\n this.emit({\n type: 'tooltipUpdate',\n chartId: msg.chartId,\n data,\n });\n \n // Derive hover state from tooltip data\n // Tooltip data contains all the info needed for hover events\n if (data && data.params.length > 0) {\n const firstParam = data.params[0];\n this.emit({\n type: 'hoverChange',\n chartId: msg.chartId,\n payload: {\n seriesIndex: firstParam.seriesIndex,\n dataIndex: firstParam.dataIndex,\n value: firstParam.value,\n x: data.x,\n y: data.y,\n },\n });\n } else {\n // Tooltip hidden = hover cleared\n this.emit({\n type: 'hoverChange',\n chartId: msg.chartId,\n payload: null,\n });\n }\n },\n\n // Emit legend updates to main thread\n onLegendUpdate: (items) => {\n this.emit({\n type: 'legendUpdate',\n chartId: msg.chartId,\n items,\n });\n },\n\n // Emit axis label updates to main thread\n onAxisLabelsUpdate: (xLabels, yLabels) => {\n this.emit({\n type: 'axisLabelsUpdate',\n chartId: msg.chartId,\n xLabels,\n yLabels,\n });\n },\n\n // Emit crosshair position to main thread\n onCrosshairMove: (x) => {\n // Only emit if crosshair is active (x is not null)\n // Note: source parameter is not provided by callback - it's tracked\n // separately when setInteractionX is called programmatically\n if (x !== null) {\n this.emit({\n type: 'crosshairMove',\n chartId: msg.chartId,\n x,\n });\n }\n },\n\n // Emit click events to main thread\n onClickData: (payload) => {\n // PERFORMANCE: Early return if no hit (most common case in sparse data)\n if (!payload.nearest && !payload.pieSlice && !payload.candlestick) {\n return;\n }\n \n // PERFORMANCE: Use early returns to avoid nested conditionals\n if (payload.nearest) {\n this.emit({\n type: 'click',\n chartId: msg.chartId,\n payload: {\n seriesIndex: payload.nearest.seriesIndex,\n dataIndex: payload.nearest.dataIndex,\n value: payload.nearest.point as readonly [number, number],\n x: payload.x,\n y: payload.y,\n },\n });\n return;\n }\n \n if (payload.pieSlice) {\n this.emit({\n type: 'click',\n chartId: msg.chartId,\n payload: {\n seriesIndex: payload.pieSlice.seriesIndex,\n dataIndex: payload.pieSlice.dataIndex,\n value: [payload.pieSlice.slice.value, 0] as readonly [number, number],\n x: payload.x,\n y: payload.y,\n },\n });\n return;\n }\n \n if (payload.candlestick) {\n this.emit({\n type: 'click',\n chartId: msg.chartId,\n payload: {\n seriesIndex: payload.candlestick.seriesIndex,\n dataIndex: payload.candlestick.dataIndex,\n value: payload.candlestick.point as readonly [number, number, number, number, number],\n x: payload.x,\n y: payload.y,\n },\n });\n }\n },\n\n // Emit device lost events to main thread\n onDeviceLost: (reason) => {\n state.deviceLost = true;\n this.emit({\n type: 'deviceLost',\n chartId: msg.chartId,\n reason: reason === 'destroyed' ? 'destroyed' : 'unknown',\n message: reason,\n });\n },\n }\n );\n\n // Subscribe to zoom range changes from coordinator and emit to main thread\n // This ensures the zoom slider UI updates when zoom changes via wheel/programmatic means\n coordinator.onZoomRangeChange((range) => {\n this.emit({\n type: 'zoomChange',\n chartId: msg.chartId,\n start: range.start,\n end: range.end,\n });\n });\n\n // Store chart instance with shared state\n const instance: ChartInstance = {\n chartId: msg.chartId,\n gpuContext: initializedContext,\n coordinator,\n canvas: msg.canvas,\n renderChannel,\n state, // Shared state object (captured in coordinator callbacks)\n };\n this.charts.set(msg.chartId, instance);\n\n // Get initial zoom range for inclusion in ready message\n // This ensures the proxy has the correct zoom range immediately upon initialization\n // rather than waiting for a separate zoomChange message to be processed\n const initialZoomRange = coordinator.getZoomRange();\n\n // Set up render loop on the MessageChannel\n // Null check satisfies TypeScript - renderChannel is guaranteed non-null at this point\n // PERFORMANCE CRITICAL: Cache references in closure to eliminate Map lookup on every frame\n if (renderChannel) {\n const chartId = msg.chartId;\n const cachedCoordinator = coordinator;\n const cachedState = state;\n \n renderChannel.port1.onmessage = () => {\n // Use cached state instead of Map lookup - significant perf win for 60fps render loop\n if (!cachedState.disposed && !cachedState.deviceLost) {\n cachedState.renderPending = false;\n \n const perfState = cachedState.performance;\n const frameStartTime = performance.now();\n \n try {\n // Record frame timestamp in circular buffer BEFORE rendering\n perfState.frameTimestamps[perfState.frameTimestampIndex] = frameStartTime;\n perfState.frameTimestampIndex = (perfState.frameTimestampIndex + 1) % FRAME_BUFFER_SIZE;\n if (perfState.frameTimestampCount < FRAME_BUFFER_SIZE) {\n perfState.frameTimestampCount++;\n }\n perfState.totalFrames++;\n\n // Frame drop detection (only after first frame)\n if (perfState.lastFrameTime > 0) {\n const deltaTime = frameStartTime - perfState.lastFrameTime;\n if (deltaTime > EXPECTED_FRAME_TIME_MS * FRAME_DROP_THRESHOLD_MULTIPLIER) {\n perfState.totalDroppedFrames++;\n perfState.consecutiveDroppedFrames++;\n perfState.lastDropTimestamp = frameStartTime;\n } else {\n // Reset consecutive counter on successful frame\n perfState.consecutiveDroppedFrames = 0;\n }\n }\n perfState.lastFrameTime = frameStartTime;\n\n // Render frame\n cachedCoordinator.render();\n\n const frameEndTime = performance.now();\n const cpuTime = frameEndTime - frameStartTime;\n perfState.lastCPUTime = cpuTime;\n\n // GPU timing (optional, requires queue.onSubmittedWorkDone)\n // For now, we track CPU time only. GPU timing would require timestamp-query feature.\n // This can be added later when implementing GPU timing support.\n\n // Calculate and emit performance metrics\n const metrics = this.calculatePerformanceMetrics(perfState);\n this.emit({\n type: 'performance-update',\n chartId,\n metrics,\n });\n\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'RENDER_ERROR', message, 'render', stack);\n }\n } else if (cachedState.deviceLost) {\n // Silently skip render if device is lost\n cachedState.renderPending = false;\n }\n };\n }\n\n // Get GPU capabilities for diagnostics\n // Note: adapter.info() is an async method that returns GPUAdapterInfo\n // For simplicity, we just report that an adapter was obtained\n // adapter.features is a Set<GPUFeatureName>, convert to string array\n // Performance: Use spread operator instead of Array.from() - slightly faster\n const capabilities = initializedContext.adapter\n ? {\n adapter: 'WebGPU Adapter',\n features: initializedContext.adapter.features ? [...initializedContext.adapter.features] as string[] : [],\n }\n : undefined;\n\n // Determine performance capabilities\n const performanceCapabilities: PerformanceCapabilities = {\n gpuTimingSupported: initializedContext.adapter?.features.has('timestamp-query') ?? false,\n highResTimerSupported: typeof performance !== 'undefined' && typeof performance.now === 'function',\n performanceMetricsSupported: true, // Always supported in worker\n };\n\n // Emit ready message with matching messageId and initial zoom range\n // CRITICAL: Including initial zoom range in ready message ensures the proxy\n // can initialize its slider with the correct range before any async message processing\n this.emit({\n type: 'ready',\n chartId: msg.chartId,\n messageId: msg.messageId,\n capabilities,\n performanceCapabilities,\n initialZoomRange,\n });\n\n // Trigger initial render through MessageChannel to track performance metrics\n if (!state.renderPending && !state.disposed && renderChannel) {\n state.renderPending = true;\n renderChannel.port2.postMessage(null);\n }\n } catch (error) {\n // Clean up MessageChannel if initialization failed\n if (renderChannel) {\n try {\n renderChannel.port1.close();\n renderChannel.port2.close();\n } catch (cleanupError) {\n // Ignore cleanup errors during error handling\n }\n }\n\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n const code: ErrorCode = message.includes('WebGPU')\n ? 'WEBGPU_INIT_FAILED'\n : 'UNKNOWN';\n\n this.emitError(msg.chartId, code, message, 'init', stack, msg.messageId);\n }\n }\n\n /**\n * Updates chart options for an existing instance.\n * \n * @param chartId - Chart instance identifier\n * @param options - New chart options to apply\n */\n private handleSetOption(chartId: string, options: ChartGPUOptions): void {\n try {\n const instance = this.getChartInstance(chartId, 'setOption');\n const resolvedOptions = resolveOptionsForChart(options);\n instance.coordinator.setOptions(resolvedOptions);\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'setOption', stack);\n }\n }\n\n /**\n * Appends data points to a specific series.\n * \n * Performance: Uses shared validation helpers to reduce code size and improve performance.\n * \n * @param chartId - Chart instance identifier\n * @param seriesIndex - Index of the series to append to\n * @param data - ArrayBuffer containing interleaved Float32 point data\n * @param pointCount - Number of points in the buffer\n * @param stride - Bytes per point (8 for DataPoint, 20 for OHLCDataPoint)\n */\n private handleAppendData(\n chartId: string,\n seriesIndex: number,\n data: ArrayBuffer,\n pointCount: number,\n stride: number\n ): void {\n try {\n // Performance: Use shared validation helpers\n validateSeriesIndex(seriesIndex, 'in appendData');\n validatePointCount(pointCount, 'in appendData');\n\n const instance = this.getChartInstance(chartId, 'appendData');\n const points = deserializeDataPoints(data, pointCount, stride);\n instance.coordinator.appendData(seriesIndex, points);\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'DATA_ERROR', message, 'appendData', stack);\n }\n }\n\n /**\n * Batch appends data to multiple series in a single operation.\n * \n * Performance optimizations:\n * - Validates all items upfront before processing (fail fast)\n * - Caches instance lookup outside loop\n * - Uses shared validation helpers\n * - Defers render request until all appends complete (batching)\n * \n * @param chartId - Chart instance identifier\n * @param items - Array of append operations to perform\n */\n private handleAppendDataBatch(\n chartId: string,\n items: ReadonlyArray<{\n readonly seriesIndex: number;\n readonly data: ArrayBuffer;\n readonly pointCount: number;\n readonly stride: number;\n }>\n ): void {\n try {\n const instance = this.getChartInstance(chartId, 'appendDataBatch');\n\n // Performance: Validate all items upfront before processing any (fail fast)\n const itemsLength = items.length;\n for (let i = 0; i < itemsLength; i++) {\n const item = items[i];\n // Performance: Use shared validation helpers\n validateSeriesIndex(item.seriesIndex, `at batch index ${i}`);\n validatePointCount(item.pointCount, `at batch index ${i}`);\n }\n\n // Performance: Process all append operations in batch\n // Each appendData call would normally trigger a render request,\n // but coordinator should coalesce them internally\n for (let i = 0; i < itemsLength; i++) {\n const item = items[i];\n const points = deserializeDataPoints(item.data, item.pointCount, item.stride);\n instance.coordinator.appendData(item.seriesIndex, points);\n }\n\n // Note: Render request is automatically triggered by coordinator's onRequestRender callback\n // No need to manually trigger render here - it's already coalesced\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'DATA_ERROR', message, 'appendDataBatch', stack);\n }\n }\n\n /**\n * Handles canvas resize events.\n * \n * @param chartId - Chart instance identifier\n * @param msg - Resize message with new dimensions\n */\n private handleResize(chartId: string, msg: ResizeMessage): void {\n try {\n const instance = this.getChartInstance(chartId, 'resize');\n\n // Check device lost state\n if (instance.state.deviceLost) {\n throw new Error('Cannot resize: GPU device is lost');\n }\n\n // Validate dimensions\n const { width, height, devicePixelRatio } = msg;\n if (width <= 0 || height <= 0) {\n throw new Error(`Invalid dimensions: width=${width}, height=${height}. Must be positive.`);\n }\n if (devicePixelRatio <= 0) {\n throw new Error(`Invalid devicePixelRatio: ${devicePixelRatio}. Must be positive.`);\n }\n\n // Calculate canvas dimensions with proper rounding\n const targetWidth = Math.floor(width * devicePixelRatio);\n const targetHeight = Math.floor(height * devicePixelRatio);\n\n // Validate that dimensions are non-zero after scaling\n if (targetWidth === 0 || targetHeight === 0) {\n throw new Error(\n `Computed canvas dimensions are zero: ${targetWidth}x${targetHeight}. ` +\n `CSS dimensions (${width}x${height}px) are too small for device pixel ratio ${devicePixelRatio}. ` +\n `Minimum canvas size is 1px in CSS space.`\n );\n }\n\n // Clamp to device limits\n const device = instance.gpuContext.device;\n if (!device) {\n throw new Error('GPU device is not available');\n }\n\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 // Update canvas dimensions\n instance.canvas.width = finalWidth;\n instance.canvas.height = finalHeight;\n\n // Reconfigure canvas context\n const canvasContext = instance.gpuContext.canvasContext;\n const preferredFormat = instance.gpuContext.preferredFormat;\n \n if (!canvasContext) {\n throw new Error('Canvas context is not available');\n }\n if (!preferredFormat) {\n throw new Error('Preferred texture format is not available');\n }\n\n try {\n canvasContext.configure({\n device,\n format: preferredFormat,\n alphaMode: instance.gpuContext.alphaMode,\n });\n } catch (configError) {\n throw new Error(\n `Failed to reconfigure canvas context: ${configError instanceof Error ? configError.message : String(configError)}`\n );\n }\n\n // Request render if specified\n // Use MessageChannel to ensure performance metrics are tracked\n if (msg.requestRender) {\n if (!instance.state.renderPending && !instance.state.disposed) {\n instance.state.renderPending = true;\n instance.renderChannel.port2.postMessage(null);\n }\n }\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'RENDER_ERROR', message, 'resize', stack);\n }\n }\n\n /**\n * Forwards a pointer event to the coordinator for interaction handling.\n * \n * @param chartId - Chart instance identifier\n * @param event - Pre-computed pointer event data from main thread\n */\n private handlePointerEvent(\n chartId: string,\n event: import('../config/types').PointerEventData\n ): void {\n try {\n console.log('[ChartGPUWorkerController] Received pointer event:', {\n type: event.type,\n gridX: event.gridX,\n gridY: event.gridY,\n isInGrid: event.isInGrid,\n });\n const instance = this.getChartInstance(chartId, 'forwardPointerEvent');\n instance.coordinator.handlePointerEvent(event);\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'forwardPointerEvent', stack);\n }\n }\n\n /**\n * Sets the zoom range programmatically.\n * \n * @param chartId - Chart instance identifier\n * @param start - Start position in percent space [0, 100]\n * @param end - End position in percent space [0, 100]\n */\n private handleSetZoomRange(chartId: string, start: number, end: number): void {\n try {\n // Validate zoom range (percent space [0, 100])\n if (start < 0 || start > 100 || end < 0 || end > 100) {\n throw new Error(`Invalid zoom range: [${start}, ${end}]. Values must be in [0, 100] (percent space).`);\n }\n if (start >= end) {\n throw new Error(`Invalid zoom range: start (${start}) must be less than end (${end}).`);\n }\n\n const instance = this.getChartInstance(chartId, 'setZoomRange');\n instance.coordinator.setZoomRange(start, end);\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'setZoomRange', stack);\n }\n }\n\n /**\n * Sets the interaction X coordinate for synchronized crosshair display.\n * \n * @param chartId - Chart instance identifier\n * @param x - X coordinate in CSS pixels, or null to clear\n * @param source - Optional source identifier to prevent echo\n */\n private handleSetInteractionX(chartId: string, x: number | null, source?: string): void {\n try {\n const instance = this.getChartInstance(chartId, 'setInteractionX');\n instance.coordinator.setInteractionX(x, source);\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'setInteractionX', stack);\n }\n }\n\n /**\n * Enables or disables animation, optionally updating animation configuration.\n * \n * @param chartId - Chart instance identifier\n * @param enabled - Whether animation should be enabled\n * @param config - Optional animation configuration\n */\n private handleSetAnimation(\n chartId: string,\n enabled: boolean,\n _config?: import('../config/types').AnimationConfig\n ): void {\n try {\n const instance = this.getChartInstance(chartId, 'setAnimation');\n // Animation config would be handled through setOptions\n // This is a placeholder for future animation control\n // For now, just trigger a render through MessageChannel to track performance metrics\n if (enabled && !instance.state.renderPending && !instance.state.disposed) {\n instance.state.renderPending = true;\n instance.renderChannel.port2.postMessage(null);\n }\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'setAnimation', stack);\n }\n }\n\n /**\n * Enables or disables GPU timing for performance metrics.\n * \n * @param chartId - Chart instance identifier\n * @param enabled - Whether GPU timing should be enabled\n */\n private handleSetGPUTiming(chartId: string, enabled: boolean): void {\n try {\n const instance = this.getChartInstance(chartId, 'setGPUTiming');\n instance.state.performance.gpuTimingEnabled = enabled;\n \n // Note: Actual GPU timing implementation requires timestamp-query feature\n // and queue.onSubmittedWorkDone() tracking. For now, we just toggle the flag.\n // Full GPU timing implementation can be added later.\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'setGPUTiming', stack);\n }\n }\n\n /**\n * Calculates performance metrics from performance tracking state.\n * \n * @param perfState - Performance tracking state\n * @returns Complete performance metrics\n */\n private calculatePerformanceMetrics(perfState: PerformanceTrackingState): PerformanceMetrics {\n // Calculate exact FPS from timestamp deltas\n const fps = this.calculateExactFPS(perfState);\n \n // Calculate frame time statistics\n const frameTimeStats = this.calculateFrameTimeStats(perfState);\n \n // GPU timing stats (placeholder - requires timestamp-query feature)\n const gpuTiming: GPUTimingStats = {\n enabled: perfState.gpuTimingEnabled,\n cpuTime: perfState.lastCPUTime as Milliseconds,\n gpuTime: perfState.lastGPUTime as Milliseconds,\n };\n \n // Memory stats (placeholder - would require tracking buffer allocations)\n const memory: MemoryStats = {\n used: 0 as Bytes,\n peak: 0 as Bytes,\n allocated: 0 as Bytes,\n };\n \n // Frame drop stats\n const frameDrops: FrameDropStats = {\n totalDrops: perfState.totalDroppedFrames,\n consecutiveDrops: perfState.consecutiveDroppedFrames,\n lastDropTimestamp: perfState.lastDropTimestamp as Milliseconds,\n };\n \n const elapsedTime = performance.now() - perfState.startTime;\n \n return {\n fps,\n frameTimeStats,\n gpuTiming,\n memory,\n frameDrops,\n totalFrames: perfState.totalFrames,\n elapsedTime: elapsedTime as Milliseconds,\n };\n }\n\n /**\n * Calculates exact FPS from frame timestamp deltas.\n * \n * @param perfState - Performance tracking state\n * @returns Exact FPS measurement\n */\n private calculateExactFPS(perfState: PerformanceTrackingState): ExactFPS {\n const count = perfState.frameTimestampCount;\n if (count < 2) {\n return 0 as ExactFPS;\n }\n\n const timestamps = perfState.frameTimestamps;\n const startIndex = (perfState.frameTimestampIndex - count + FRAME_BUFFER_SIZE) % FRAME_BUFFER_SIZE;\n \n let totalDelta = 0;\n for (let i = 1; i < count; i++) {\n const prevIndex = (startIndex + i - 1) % FRAME_BUFFER_SIZE;\n const currIndex = (startIndex + i) % FRAME_BUFFER_SIZE;\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.\n * \n * @param perfState - Performance tracking state\n * @returns Frame time statistics\n */\n private calculateFrameTimeStats(perfState: PerformanceTrackingState): FrameTimeStats {\n const count = perfState.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 const timestamps = perfState.frameTimestamps;\n const startIndex = (perfState.frameTimestampIndex - count + FRAME_BUFFER_SIZE) % FRAME_BUFFER_SIZE;\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) % FRAME_BUFFER_SIZE;\n const currIndex = (startIndex + i) % FRAME_BUFFER_SIZE;\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 * Disposes a chart instance and cleans up all resources.\n * \n * @param chartId - Chart instance identifier\n */\n private disposeChart(chartId: string): void {\n const cleanupErrors: string[] = [];\n\n try {\n const instance = this.charts.get(chartId);\n if (!instance) {\n this.emitError(chartId, 'UNKNOWN', `Chart \"${chartId}\" not found`, 'dispose');\n return;\n }\n\n // Check if already disposed\n if (instance.state.disposed) {\n this.emitError(chartId, 'UNKNOWN', `Chart \"${chartId}\" is already disposed`, 'dispose');\n return;\n }\n\n // Mark as disposed to prevent further operations\n instance.state.disposed = true;\n\n // Close render channel\n try {\n instance.renderChannel.port1.close();\n instance.renderChannel.port2.close();\n } catch (error) {\n cleanupErrors.push(`Failed to close render channel: ${error}`);\n }\n\n // Dispose coordinator (this cleans up all GPU buffers via dataStore.dispose())\n try {\n instance.coordinator.dispose();\n } catch (error) {\n cleanupErrors.push(`Failed to dispose coordinator: ${error}`);\n }\n\n // Destroy GPU context using proper functional API\n // This calls device.destroy() with error handling and returns a reset state\n try {\n instance.gpuContext = destroyGPUContext(instance.gpuContext);\n } catch (error) {\n cleanupErrors.push(`Failed to destroy GPU context: ${error}`);\n }\n\n // Remove from registry\n this.charts.delete(chartId);\n\n // Emit disposed message\n this.emit({\n type: 'disposed',\n chartId,\n cleanupErrors: cleanupErrors.length > 0 ? cleanupErrors : undefined,\n });\n } catch (error) {\n // Performance: Use shared error extraction helper\n const [message, stack] = extractErrorInfo(error);\n this.emitError(chartId, 'UNKNOWN', message, 'dispose', stack);\n }\n }\n\n /**\n * Disposes all chart instances and cleans up controller resources.\n * Should be called when the worker is being terminated.\n * \n * Performance: Uses spread operator instead of Array.from() for slight efficiency gain.\n */\n dispose(): void {\n // Performance: Spread operator is slightly faster than Array.from()\n const chartIds = [...this.charts.keys()];\n for (const chartId of chartIds) {\n this.disposeChart(chartId);\n }\n this.messageHandler = null;\n }\n\n /**\n * Gets a chart instance by ID, throwing if not found, disposed, or device lost.\n * \n * @param chartId - Chart instance identifier\n * @param operation - Operation name for error reporting\n * @returns Chart instance\n * @throws {Error} If chart not found, disposed, or device lost\n */\n private getChartInstance(chartId: string, operation: string): ChartInstance {\n const instance = this.charts.get(chartId);\n \n if (!instance) {\n throw new Error(`Chart \"${chartId}\" not found for operation \"${operation}\"`);\n }\n \n if (instance.state.disposed) {\n throw new Error(`Chart \"${chartId}\" is disposed and cannot perform \"${operation}\"`);\n }\n \n if (instance.state.deviceLost) {\n throw new Error(`Chart \"${chartId}\" GPU device is lost and cannot perform \"${operation}\". Re-initialize the chart.`);\n }\n \n return instance;\n }\n\n /**\n * Emits an outbound message to the main thread.\n * \n * @param msg - Outbound message to send\n */\n private emit(msg: WorkerOutboundMessage): void {\n if (this.messageHandler) {\n this.messageHandler(msg);\n } else {\n console.warn('No message handler registered, dropping message:', msg);\n }\n }\n\n /**\n * Emits an error message to the main thread.\n * \n * @param chartId - Chart instance identifier\n * @param code - Error code for categorization\n * @param message - Error message\n * @param operation - Operation that failed\n * @param stack - Optional stack trace\n * @param messageId - Optional message ID for correlation\n */\n private emitError(\n chartId: string,\n code: ErrorCode,\n message: string,\n operation: string,\n stack?: string,\n messageId?: string\n ): void {\n const errorMsg: ErrorMessage = {\n type: 'error',\n chartId,\n code,\n message,\n operation,\n stack,\n messageId,\n };\n this.emit(errorMsg);\n }\n}\n\n/**\n * Deserializes ArrayBuffer data into DataPoint or OHLCDataPoint arrays.\n * \n * Performance optimizations (critical hot path for streaming data):\n * - Pre-allocates array to exact size to avoid dynamic resizing\n * - Uses indexed assignment instead of push() for better performance\n * - Validates inputs early to fail fast\n * - Creates read-only tuple arrays for type safety with minimal overhead\n * \n * Note: We create tuple arrays rather than returning TypedArray views directly because:\n * 1. Type safety: coordinator.appendData expects DataPoint[] or OHLCDataPoint[] tuples\n * 2. API contract: Tuples are the documented format\n * 3. Minimal overhead: Modern engines optimize small tuple creation\n * \n * @param buffer - ArrayBuffer containing interleaved Float32 point data\n * @param pointCount - Number of points in the buffer\n * @param stride - Bytes per point (8 for DataPoint, 20 for OHLCDataPoint)\n * @returns Array of data points\n * @throws {Error} If stride is invalid or buffer size doesn't match\n */\nfunction deserializeDataPoints(\n buffer: ArrayBuffer,\n pointCount: number,\n stride: number\n): ReadonlyArray<DataPoint> | ReadonlyArray<OHLCDataPoint> {\n // Validate inputs early (fail fast)\n if (!buffer) {\n throw new Error('Buffer is null or undefined');\n }\n \n if (!Number.isInteger(pointCount) || pointCount < 0) {\n throw new Error(`Invalid pointCount: ${pointCount}. Must be a non-negative integer.`);\n }\n \n if (!Number.isInteger(stride) || stride <= 0) {\n throw new Error(`Invalid stride: ${stride}. Must be a positive integer.`);\n }\n \n // Validate buffer is detached (hasn't been transferred twice)\n if (buffer.byteLength === 0 && pointCount > 0) {\n throw new Error(\n 'Buffer is detached (byteLength = 0). The ArrayBuffer may have been transferred multiple times. ' +\n 'Each ArrayBuffer can only be transferred once via postMessage.'\n );\n }\n \n // Validate 4-byte alignment (WebGPU requirement)\n if (buffer.byteLength % 4 !== 0) {\n throw new Error(\n `Buffer size (${buffer.byteLength} bytes) is not 4-byte aligned. ` +\n `WebGPU requires all buffer sizes to be multiples of 4 bytes.`\n );\n }\n \n // Validate stride alignment (must be multiple of 4 for Float32 data)\n if (stride % 4 !== 0) {\n throw new Error(\n `Stride (${stride} bytes) is not 4-byte aligned. ` +\n `Float32 data requires stride to be a multiple of 4 bytes.`\n );\n }\n \n // Validate buffer size matches expected size\n const expectedSize = pointCount * stride;\n if (buffer.byteLength !== expectedSize) {\n throw new Error(\n `Buffer size mismatch: expected ${expectedSize} bytes (${pointCount} points × ${stride} bytes), ` +\n `got ${buffer.byteLength} bytes. Difference: ${buffer.byteLength - expectedSize} bytes.`\n );\n }\n\n // Create Float32Array view once (reused for all points)\n // GPU buffers use Float32 precision, so we deserialize as Float32\n const view = new Float32Array(buffer);\n \n // Validate view length matches expected element count\n const floatsPerPoint = stride / 4;\n const expectedLength = pointCount * floatsPerPoint;\n if (view.length !== expectedLength) {\n throw new Error(\n `Float32Array length mismatch: expected ${expectedLength} elements, got ${view.length} elements`\n );\n }\n\n if (stride === 8) {\n // DataPoint: [x, y] pairs (2 × 4 bytes = 8 bytes)\n // PERFORMANCE: Pre-allocate to exact size, use indexed assignment\n const points = new Array<DataPoint>(pointCount);\n for (let i = 0, offset = 0; i < pointCount; i++, offset += 2) {\n // Unrolled offset calculation in loop increment for slight perf gain\n points[i] = [view[offset], view[offset + 1]];\n }\n return points;\n } else if (stride === 20) {\n // OHLCDataPoint: [timestamp, open, close, low, high] (5 × 4 bytes = 20 bytes)\n // PERFORMANCE: Pre-allocate to exact size, use indexed assignment\n const points = new Array<OHLCDataPoint>(pointCount);\n for (let i = 0, offset = 0; i < pointCount; i++, offset += 5) {\n // Unrolled offset calculation in loop increment for slight perf gain\n \n // CRITICAL: OHLC data reordering\n // Storage format (Float32Array): [t, o, h, l, c]\n // ECharts tuple format: [t, o, c, l, h]\n // \n // packOHLCDataPoints stores data as [t, o, h, l, c] for GPU rendering efficiency\n // (high/low are adjacent for min/max operations). We must reorder back to ECharts\n // convention [t, o, c, l, h] for API consistency.\n points[i] = [\n view[offset], // timestamp (index 0 → 0)\n view[offset + 1], // open (index 1 → 1)\n view[offset + 4], // close (index 4 → 2) ← reordered\n view[offset + 3], // low (index 3 → 3)\n view[offset + 2], // high (index 2 → 4) ← reordered\n ];\n }\n return points;\n } else {\n throw new Error(\n `Invalid stride: ${stride} bytes. Expected 8 (DataPoint) or 20 (OHLCDataPoint). ` +\n `Received stride corresponds to ${stride / 4} floats per point.`\n );\n }\n}\n","/**\n * Built-in worker entry point for ChartGPU worker-based rendering.\n * \n * This file runs in a Web Worker context and handles all chart rendering\n * using OffscreenCanvas. It communicates with the main thread via the\n * ChartGPUWorkerController.\n * \n * Usage:\n * This file is automatically used when calling ChartGPU.createInWorker()\n * without providing a custom worker URL or instance.\n */\n\nimport { ChartGPUWorkerController } from './ChartGPUWorkerController';\nimport type { WorkerInboundMessage } from './protocol';\n\n// Create worker controller instance\nconst controller = new ChartGPUWorkerController();\n\n// Register message handler to send messages to main thread\ncontroller.onMessage((msg) => {\n self.postMessage(msg);\n});\n\n// Handle messages from main thread\nself.onmessage = async (event: MessageEvent<WorkerInboundMessage>) => {\n try {\n await controller.handleMessage(event.data);\n } catch (error) {\n // Send error message to main thread\n self.postMessage({\n type: 'error',\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n chartId: event.data.chartId,\n });\n }\n};\n\n// Handle worker errors\nself.onerror = (event) => {\n const error = event instanceof ErrorEvent ? event.error : event;\n console.error('[ChartGPU Worker] Uncaught error:', error);\n self.postMessage({\n type: 'error',\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n chartId: 'unknown',\n });\n};\n\n// Handle unhandled promise rejections\nself.onunhandledrejection = (event) => {\n console.error('[ChartGPU Worker] Unhandled promise rejection:', event.reason);\n self.postMessage({\n type: 'error',\n message: event.reason instanceof Error ? event.reason.message : String(event.reason),\n stack: event.reason instanceof Error ? event.reason.stack : undefined,\n chartId: 'unknown',\n });\n};\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","destroyGPUContext","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","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","a","out","lastX","lastY","bucket","rangeStart","rangeEndExclusive","nextRangeStart","nextRangeEndExclusive","avgX","avgY","sumX","sumY","avgCount","ax","ay","maxArea","maxIndex","bx","by","area2","absArea2","lttbIndicesForDataPoints","pLast","p","pa","pb","lttbSample","threshold","idx","getXY","getSize","clampTargetPoints","sampleByBuckets","mode","chosen","sumSize","count","sizeCount","size","bestY","sampleSeriesDataPoints","sampling","samplingThreshold","isTupleOHLCDataPoint","ohlcSample","isTuple","dataAsTuples","firstCandle","lastCandle","timestamp","open","close","high","low","candle","candleLow","candleHigh","dataAsObjects","gridWgsl","DEFAULT_VERTEX_ENTRY","DEFAULT_FRAGMENT_ENTRY","isPowerOfTwo","alignTo","value","alignment","getStageModule","stage","createShaderModule","code","label","createRenderPipeline","config","layout","vertexStage","vertexEntryPoint","fragment","fragmentStage","fragmentEntryPoint","targets","formats","format","primitive","multisample","createUniformBuffer","alignedSize","maxSize","writeUniformBuffer","src","clamp01","v","clamp255","parseHexNibble","hex","parseHexByte","parseHexColorToRgba01","color","c","r","g","b","parseRgbNumberOrPercent","token","parseAlphaNumberOrPercent","parseRgbFuncToRgba01","m","fn","parts","parseCssColorToRgba01","rgb","parseCssColorToGPUColor","fallback","rgba","DEFAULT_TARGET_FORMAT","DEFAULT_TICK_COUNT","DEFAULT_TICK_LENGTH_CSS_PX","DEFAULT_AXIS_RGBA","createIdentityMat4Buffer","isFiniteGridArea","gridArea","finiteOrUndefined","normalizeDomain","minCandidate","maxCandidate","min","max","t","generateAxisVertices","axisConfig","scale","orientation","tickCountOverride","left","right","top","bottom","canvasWidth","canvasHeight","devicePixelRatio","plotLeft","plotRight","plotTop","plotBottom","plotLeftClip","plotRightClip","plotTopClip","plotBottomClip","tickLengthCssPx","tickCountRaw","tickCount","tickLengthDevicePx","tickDeltaClipX","tickDeltaClipY","domainMinRaw","domainMaxRaw","domain","domainMin","domainMax","totalSegments","vertices","y0","y1","x0","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","yClip","xClip","yClipTop","yClipBottom","createGridRenderer","fsUniformBuffer","bindGroup","lineCountOrOptions","isOptionsObject","lineCount","colorString","transformBuffer","colorBuffer","areaWgsl","parseSeriesColorToRgba01","getPointXY","computeDataBounds","xMin","xMax","yMin","yMax","computeClipAffineFromScale","v0","v1","p0","p1","writeTransformMat4F32","createAreaVertices","createAreaRenderer","vsUniformScratchBuffer","vsUniformScratchF32","fsUniformScratchF32","writeVsUniforms","baseline","seriesConfig","xScale","yScale","baselineValue","opacity","lineWgsl","createLineRenderer","currentVertexBuffer","currentVertexCount","dataBuffer","barWgsl","DEFAULT_BAR_GAP","DEFAULT_BAR_CATEGORY_GAP","INSTANCE_STRIDE_BYTES","INSTANCE_STRIDE_FLOATS","parsePercent","normalizeStackId","stack","trimmed","computePlotSizeCssPx","canvasCssWidth","canvasCssHeight","plotWidthCss","plotHeightCss","computePlotClipRect","computeCategoryWidthClip","categoryStep","plotClipRect","fallbackCategoryCount","w","clipWidth","createBarRenderer","instanceBuffer","instanceCount","cpuInstanceStagingBuffer","cpuInstanceStagingF32","categoryXScratch","ensureCpuInstanceCapacityFloats","requiredFloats","nextFloats","computeBarCategoryStep","seriesConfigs","s","minStep","d","computeSharedBarLayout","barWidth","barGap","barCategoryGap","computeBaselineForBarsFromData","computeBaselineForBarsFromAxis","yDomainA","yDomainB","dataStore","plotSize","plotClipWidth","clipPerCssX","stackIdToClusterIndex","clusterIndexBySeries","clusterCount","stackId","categoryWidthClip","categoryInnerWidthClip","denom","maxBarWidthClip","barWidthClip","rawBarWidth","gapClip","clusterWidthClip","baselineDomain","baselineClip","fallbackBaselineDomain","maxBars","outFloats","stackSumsByStackId","seriesIndex","clusterIndex","xClipCenter","baseClip","sumsForX","xKey","sums","baseDomain","topDomain","bClip","tClip","grownBytes","scatterWgsl","DEFAULT_SCATTER_RADIUS_CSS_PX","clampInt","lo","hi","getPointSizeCssPx","toScatterTuple","computePlotScissorDevicePx","plotLeftDevice","plotRightDevice","plotTopDevice","plotBottomDevice","scissorX","scissorY","scissorR","scissorB","scissorW","scissorH","createScatterRenderer","lastCanvasWidth","lastCanvasHeight","lastViewportPx","lastScissor","viewportW","viewportH","hasValidDpr","seriesSymbolSize","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","key","ensureBins","binCountX","binCountY","requiredU32","ensureBindGroups","pointBuffer","visibleStartIndex","visibleEndIndex","rawBounds","plotScissor","binSizeCss","binSizePx","normU32","rb","encoder","binTotal","visibleCount","pass","wg","groupsPoints","groupsBins","pieWgsl","TAU","wrapToTau","thetaRad","parseColor","cssColor","fallbackCssColor","parsed","fb","parseNumberOrPercent","basis","pct","resolveCenterPlotCss","center","xRaw","yRaw","isRadiusTuple","radius","resolveRadiiCss","maxRadiusCss","inner","outer","innerCss","outerCss","IDENTITY_MAT4_F32","createPieRenderer","viewportWDevicePx","viewportHDevicePx","centerPlotCss","centerCanvasCssX","centerCanvasCssY","centerClipX","centerClipY","radiiCss","innerPx","outerPx","total","validCount","startDeg","current","accumulated","emitted","item","isLast","span","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","bgColor","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","start","end","byteSize","nextVertexCount","nextIndex","DEFAULT_CROSSHAIR_RGBA","MAX_THICKNESS_DEVICE_PX","DASH_ON_DEVICE_PX","DASH_OFF_DEVICE_PX","MAX_VERTICES","computeThicknessOffsetsDevicePx","lineWidthCssPx","widthDevicePx","thickness","mid","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","visible","stream","renderOptions","scissor","highlightWgsl","DEFAULT_RGBA","isFiniteScissor","brighten","factor","f","luminance","createHighlightRenderer","uniformBuffer","sizeCssPx","baseRadiusDevicePx","seriesRgba","ringRgba","outlineRgba","buf","DEFAULT_TAP_MAX_DISTANCE_CSS_PX","DEFAULT_TAP_MAX_TIME_MS","createEventManager","initialGridArea","listeners","tapCandidate","suppressNextLostPointerCaptureId","toPayload","e","rect","plotLeftCss","plotTopCss","gridX","gridY","isInGrid","emit","eventName","payload","cb","clearTapCandidateIfMatches","onPointerMove","onPointerLeave","onPointerCancel","onLostPointerCapture","onPointerDown","onPointerUp","dt","dx","dy","distSq","maxDist","callback","nextGridArea","clamp","normalizeWheelDelta","basisCssPx","raw","normalizeWheelDeltaX","wheelDeltaToZoomFactor","deltaCssPx","abs","capped","isMiddleButtonDrag","isShiftLeftDrag","createInsideZoom","eventManager","zoomState","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","anchor","nextMinSpan","nextMaxSpan","nextMin","nextMax","eps","nextSpan","delta","DEFAULT_MAX_DISTANCE_PX","scatterMaxRadiusCache","isPointInBar","barBounds","safeCallSymbolSize","getScatterRadiusCssPx","seriesCfg","perPoint","getMaxScatterRadiusCssPx","cached","maxRadius","seriesFallback","maxPerPoint","anyPointWithoutSize","pSize","computeBarClusterSlots","stackIdBySeries","xs","computeCategoryWidthPx","sx","px","minDx","computeBarLayoutPx","clusterSlots","categoryWidthPx","categoryInnerWidthPx","maxBarWidthPx","barWidthPx","gapPx","clusterWidthPx","inferPlotHeightPxForBarHitTesting","maxY","py","computeBaselineDomainAndPx","plotHeightPx","baselinePx","bucketStackedXKey","xCenterPx","xDomain","lowerBoundTuple","xTarget","lowerBoundObject","findNearestPoint","maxDistance","md","maxDistSq","bestSeriesIndex","bestDataIndex","bestPoint","bestDistSq","barSeriesConfigs","barSeriesIndexByBar","cfg","layoutPx","bestBarHit","originalSeriesIndex","yDomain","basePx","topPx","bounds","isScatter","scatterCfg","maxRadiusInSeries","seriesCutoffSq","first","tupleData","insertionIndex","pruneSq","dxSqLeft","dxSqRight","sy","allowedSq","allowed","objectData","hasNaNXCache","seriesHasNaNX","hasNaN","computeBarHitTestLayout","barSeries","barWidthRange","gap","clusterWidth","clusterIndexByGlobalSeriesIndex","globalSeriesIndex","findPointsAtX","xValue","tolerance","maxDx","maxDxSq","matches","barLayout","offsetLeftFromCategoryCenter","hitTol","hitIndex","isHit","xCenterRange","xCenter","xTargetAdjusted","getXCenterAt","bestDxSq","tryUpdate","dxSq","dxSqAt","getTimestamp","getOpen","getClose","categoryStepCache","step","computeCandlestickBodyWidthRange","plotWidthFallback","categoryWidthRange","t0","minW","maxWCandidate","maxW","monotonicTimestampCache","isMonotonicNonDecreasingFiniteTimestamps","prev","lowerBoundByTimestamp","findCandlestick","halfW","best","bestDx","dataIndex","isBodyHitAt","yOpen","yClose","findPieSlice","pieConfig","dyUp","angle","slice","wedgeSpan","rel","assertFinite","createLinearScale","rangeMin","rangeMax","self","pixel","getAnchorTransform","createTextOverlay","container","computedStyle","computedPosition","computedOverflow","didSetRelative","didSetOverflowVisible","previousInlinePosition","previousInlineOverflow","overlay","text","rotation","translateX","originX","getAxisTitleFontSize","baseFontSize","styleAxisLabelSpan","theme","getSeriesName","candidate","getSeriesColor","explicit","palette","getPieSliceLabel","sliceName","sliceIndex","getPieSliceColor","sliceColor","len","createLegend","position","root","list","items","swatch","createTooltip","fadeMs","transitionToken","hideTimeoutId","rafId","clearPendingTransitions","isCurrentlyHidden","measureSize","prevVisibility","content","wasHidden","pad","containerW","containerH","myToken","EM_DASH","escapeHtml","formatNumber","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","getCanvasCssWidth","getCanvasCssHeight","LABEL_PADDING_CSS_PX","DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX","DEFAULT_HIGHLIGHT_SIZE_CSS_PX","MS_PER_DAY","MS_PER_MONTH_APPROX","MS_PER_YEAR_APPROX","MAX_TIME_X_TICK_COUNT","MIN_TIME_X_TICK_COUNT","MIN_X_LABEL_GAP_CSS_PX","finiteOrNull","MAX_ANIMATED_POINTS_PER_SERIES","assertUnreachable","computeRawBoundsFromData","extendBoundsWithDataPoints","seeded","extendBoundsWithOHLCDataPoints","computeGlobalBounds","runtimeRawBoundsByIndex","runtimeBoundsCandidate","rawBoundsCandidate","rawOHLC","yLow","yHigh","computeGridArea","gpuContext","rawCanvasWidth","rawCanvasHeight","sanitizedLeft","sanitizedRight","sanitizedTop","sanitizedBottom","rgba01ToCssRgba","withAlpha","alphaMultiplier","estimateMaxYTickLabelWidth","yLabels","fontSize","maxChars","t01","lerpDomain","clipXToCanvasCssPx","clipYToCanvasCssPx","isTuplePoint","isTupleDataArray","monotonicXCache","isMonotonicNonDecreasingFiniteX","prevX","lowerBoundXTuple","upperBoundXTuple","lowerBoundXObject","upperBoundXObject","sliceVisibleRangeByX","findVisibleRangeIndicesByX","isMonotonicNonDecreasingFiniteTimestamp","prevTimestamp","lowerBoundTimestampTuple","timestampTarget","upperBoundTimestampTuple","lowerBoundTimestampObject","upperBoundTimestampObject","sliceVisibleRangeByOHLC","canBinarySearch","resolvePieCenterPlotCss","isPieRadiusTuple","resolvePieRadiiCss","DEFAULT_MAX_TICK_FRACTION_DIGITS","computeMaxFractionDigitsFromStep","tickStep","cap","stepAbs","scaled","rounded","err","tol","createTickFormatter","maximumFractionDigits","formatTickValue","nf","normalized","formatted","pad2","MONTH_SHORT_EN","formatTimeTickValue","timestampMs","visibleRangeMs","yyyy","mm","dd","hh","generateLinearTicks","ticks","computeAdaptiveTimeXAxisTicks","axisMin","axisMax","plotClipLeft","plotClipRight","measureCtx","measureCache","fontFamily","cacheKeyPrefix","tickValues","prevRight","ok","measured","xCss","computeBaseXDomain","baseMin","baseMax","computeBaseYDomain","computeVisibleXDomain","baseXDomain","zoomRange","fractionRaw","spanFraction","resolveAnimationConfig","animation","durationMsRaw","delayMsRaw","delayMs","resolveIntroAnimationConfig","resolveUpdateAnimationConfig","computeCandlestickTooltipAnchor","match","bodyMidY","xGridCss","yGridCss","xCanvasCss","yCanvasCss","xContainerCss","yContainerCss","createAnimatedBarYScale","baseYScale","progress01","wrapper","createRenderCoordinator","callbacks","info","domOverlaysEnabled","overlayContainer","legend","tickMeasureCtx","tickMeasureCache","currentOptions","lastSeriesCount","introPhase","introProgress01","introAnimController","introAnimId","hasRenderedOnce","updateAnimController","updateAnimId","updateProgress01","updateTransition","updateInterpolationCaches","resetUpdateInterpolationCaches","interpolateCartesianSeriesDataByIndex","fromData","toData","cache","created","pTo","yFrom","yTo","interpolatePieSeriesByIndex","fromSeries","toSeries","vFrom","vTo","interpolateSeriesForUpdate","caches","animated","aAny","bAny","aData","bData","animatedData","computeUpdateSnapshotAtProgress","transition","xBase","xVisible","yBase","warnedPieAppendSeries","runtimeRawDataByIndex","runtimeBaseSeries","renderSeries","lastSampledData","flushScheduled","flushRafId","flushTimeoutId","zoomResampleDebounceTimer","zoomResampleDue","pendingAppendByIndex","gpuSeriesKindByIndex","appendedGpuThisFrame","tooltip","lastTooltipContent","lastTooltipX","lastTooltipY","showTooltipInternal","paramsArray","hideTooltipInternal","hideTooltip","emitCrosshairCallback","emitHoverCallback","gridRenderer","xAxisRenderer","yAxisRenderer","crosshairRenderer","highlightRenderer","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","result","buildTooltipParams","buildCandlestickTooltipParams","findPieSliceAtPointer","pieSeries","radii","findCandlestickAtPointer","interactionScales","cs","insideZoom","unsubscribeZoom","lastOptionsZoomRange","zoomRangeListeners","emitZoomRange","getZoomOptionsConfig","opts","insideCfg","z","sliderCfg","clampPercent","getZoomSpanConstraintsFromOptions","computeDatasetAwareDefaultMinSpan","maxPoints","fromOptions","datasetMin","updateZoom","sliceRenderSeriesToVisibleRange","initRuntimeSeriesFromOptions","owned","baselineSampled","visibleX","bufferedMin","bufferedMax","MIN_TARGET_POINTS","MAX_TARGET_POINTS_ABS","MAX_TARGET_MULTIPLIER","spanFracSafe","bufferedOHLC","baseThreshold","baseT","maxTarget","target","sampled","visibleSampled","rawData","bufferedRaw","areaRenderers","lineRenderers","scatterRenderers","scatterDensityRenderers","pieRenderers","candlestickRenderers","barRenderer","ensureAreaRendererCount","ensureLineRendererCount","ensureScatterRendererCount","ensureScatterDensityRendererCount","ensurePieRendererCount","ensureCandlestickRendererCount","cancelUpdateTransition","isDomainEqual","didSeriesDataLikelyChange","aPie","bPie","aRaw","bRaw","setOptions","resolvedOptions","fromZoomRange","fromSnapshot","fromXBase","fromXVisible","fromYBase","likelyDataChanged","shouldHaveTooltip","nextCount","toZoomRange","toXBase","toXVisible","toYBase","toSeriesForTransition","domainChanged","updateCfg","totalMs","easingWithDelay","elapsedMs","innerT","appendData","shouldRenderArea","type","nearest","pieSlice","candlestick","candlestickResult","deltaX","deltaY","deltaMode","hasCartesianSeries","seriesForIntro","introCfg","hasDrawableSeriesMarks","it","updateP","yBaseDomain","visibleXDomain","visibleXRangeMs","xTickCount","xTickValues","computed","seriesForRender","effectivePointer","crosshairOptions","centerCssX","centerCssY","seriesColor","formatter","_c","trigger","_d","containerX","containerY","m0","pieMatch","tooltipX","tooltipY","defaultBaseline","introP","areaLike","_e","_f","yScaleForBars","textureView","clearValue","offsetX","offsetY","plotRightCss","plotBottomCss","collectedXLabels","collectedYLabels","xTickLengthCssPx","xLabelY","isTimeXAxis","xFormatter","xDomainMin","xDomainMax","xTickStep","axisLabel","yTickCount","yTickLengthCssPx","yDomainMin","yDomainMax","yTickStep","yFormatter","yLabelX","ySpans","yCss","axisNameFontSize","xAxisName","_g","xTickLabelsBottom","bottomLimitCss","_h","xTitleY","yAxisName","_i","maxTickLabelWidth","yCenter","yTitleX","defaultGrid","defaultPalette","defaultLineStyle","defaultAreaStyle","candlestickDefaults","scatterDefaults","defaultOptions","darkTheme","lightTheme","getTheme","sanitizeDataZoom","input","record","xAxisIndexRaw","startRaw","endRaw","minSpanRaw","maxSpanRaw","xAxisIndex","sanitizePalette","resolveTheme","themeInput","base","takeString","fontSizeRaw","colorPaletteCandidate","normalizeOptionalColor","normalizeSampling","normalizeScatterMode","normalizeDensityNormalization","normalizeDensityBinSize","normalizeDensityColormap","arr","sanitized","normalizeCandlestickSampling","normalizeSamplingThreshold","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","resolvedSampling","resolvedSamplingThreshold","resolvedItemStyle","_j","DATA_ZOOM_SLIDER_RESERVE_CSS_PX","hasSliderDataZoom","resolveOptionsForChart","FRAME_BUFFER_SIZE","EXPECTED_FRAME_TIME_MS","FRAME_DROP_THRESHOLD_MULTIPLIER","validateSeriesIndex","validatePointCount","extractErrorInfo","ChartGPUWorkerController","handler","msg","exhaustive","chartId","message","renderChannel","gpuOptions","initializedContext","state","errorMessage","coordinator","firstParam","xLabels","reason","instance","initialZoomRange","cachedCoordinator","cachedState","perfState","frameStartTime","cpuTime","metrics","capabilities","performanceCapabilities","stride","deserializeDataPoints","itemsLength","configError","_config","fps","frameTimeStats","gpuTiming","memory","frameDrops","elapsedTime","startIndex","totalDelta","prevIndex","currIndex","avgFrameTime","deltas","sum","avg","p50Index","p95Index","p99Index","cleanupErrors","chartIds","operation","messageId","errorMsg","expectedSize","view","floatsPerPoint","expectedLength","offset","controller"],"mappings":"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"}
|