* Creates DOM overlays for tooltip, legend, text labels, and data zoom slider. * Called after canvas is appended to container.
()
| 836 | * Called after canvas is appended to container. |
| 837 | */ |
| 838 | private createOverlays(): void { |
| 839 | if (this.isDisposed) return; |
| 840 | |
| 841 | // Always create tooltip (for hover interactions) |
| 842 | this.tooltip = createTooltip(this.container); |
| 843 | |
| 844 | // Always create text overlay (for axis labels) |
| 845 | this.textOverlay = createTextOverlay(this.container); |
| 846 | |
| 847 | // Dedicated annotation overlay (separate from axis labels) |
| 848 | // so clearing/updating annotations never affects axis label rendering. |
| 849 | this.annotationTextOverlay = createTextOverlay(this.container); |
| 850 | |
| 851 | // Always create legend (worker will send updates if needed) |
| 852 | // Default position is 'right' - worker may override via messages |
| 853 | this.legend = createLegend(this.container, 'right'); |
| 854 | |
| 855 | // Create data zoom slider if configured |
| 856 | const hasSliderZoom = this.cachedOptions.dataZoom?.some(z => z?.type === 'slider') ?? false; |
| 857 | |
| 858 | if (hasSliderZoom) { |
| 859 | // Create zoom state that delegates to worker via setZoomRange |
| 860 | const initialStart = this.cachedZoomRange?.start ?? 0; |
| 861 | const initialEnd = this.cachedZoomRange?.end ?? 100; |
| 862 | const constraints = this.computeZoomSpanConstraints(this.cachedOptions); |
| 863 | this.zoomState = createZoomState(initialStart, initialEnd, constraints); |
| 864 | |
| 865 | // Sync zoom state changes to worker |
| 866 | // CRITICAL: Echo suppression - only send changes to worker if they originated from UI |
| 867 | // (slider drag, programmatic setZoomRange calls), NOT from worker zoom messages |
| 868 | this.zoomState.onChange((range) => { |
| 869 | if (this.isDisposed) return; |
| 870 | |
| 871 | // Prevent echo: Don't send zoom changes back to worker if they came FROM the worker |
| 872 | if (this.isProcessingWorkerZoomUpdate) return; |
| 873 | |
| 874 | this.setZoomRange(range.start, range.end); |
| 875 | }); |
| 876 | |
| 877 | // Create slider host element with absolute positioning at bottom |
| 878 | // This matches the non-worker ChartGPU implementation |
| 879 | this.dataZoomSliderHost = this.createDataZoomSliderHost(); |
| 880 | |
| 881 | // Create slider inside host with marginTop: 0 (host provides padding) |
| 882 | const DATA_ZOOM_SLIDER_HEIGHT_CSS_PX = 32; |
| 883 | this.dataZoomSlider = createDataZoomSlider(this.dataZoomSliderHost, this.zoomState, { |
| 884 | height: DATA_ZOOM_SLIDER_HEIGHT_CSS_PX, |
| 885 | marginTop: 0, // host provides vertical spacing |
| 886 | }); |
| 887 | |
| 888 | // Apply theme to slider |
| 889 | const themeConfig = this.resolveThemeConfig(); |
| 890 | this.dataZoomSlider.update(themeConfig); |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | /** |
| 895 | * Creates and configures the data zoom slider host element. |
no test coverage detected