@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,1224 @@
|
|
|
1
|
+
import { w as X, x as G, y as N, z as q, A as B } from "./OptionResolver-R_gJDRSD.js";
|
|
2
|
+
const Z = (f, e, t) => Math.min(t, Math.max(e, f)), Y = (f) => {
|
|
3
|
+
let { start: e, end: t } = f;
|
|
4
|
+
if (e > t) {
|
|
5
|
+
const s = e;
|
|
6
|
+
e = t, t = s;
|
|
7
|
+
}
|
|
8
|
+
return { start: Z(e, 0, 100), end: Z(t, 0, 100) };
|
|
9
|
+
};
|
|
10
|
+
function Q(f, e, t) {
|
|
11
|
+
const s = (t == null ? void 0 : t.height) ?? 32, i = (t == null ? void 0 : t.marginTop) ?? 8, n = (t == null ? void 0 : t.zIndex) ?? 4, a = (t == null ? void 0 : t.showPreview) ?? !1, r = document.createElement("div");
|
|
12
|
+
r.style.display = "block", r.style.width = "100%", r.style.height = `${s}px`, r.style.marginTop = `${i}px`, r.style.boxSizing = "border-box", r.style.position = "relative", r.style.zIndex = `${n}`, r.style.userSelect = "none", r.style.touchAction = "none";
|
|
13
|
+
const o = document.createElement("div");
|
|
14
|
+
o.style.position = "relative", o.style.height = "100%", o.style.width = "100%", o.style.boxSizing = "border-box", o.style.borderRadius = "8px", o.style.borderStyle = "solid", o.style.borderWidth = "1px", o.style.overflow = "hidden", r.appendChild(o);
|
|
15
|
+
const l = document.createElement("div");
|
|
16
|
+
l.style.position = "absolute", l.style.inset = "0", l.style.pointerEvents = "none", l.style.opacity = "0.4", l.style.display = a ? "block" : "none", o.appendChild(l);
|
|
17
|
+
const d = document.createElement("div");
|
|
18
|
+
d.style.position = "absolute", d.style.top = "0", d.style.bottom = "0", d.style.left = "0%", d.style.width = "100%", d.style.boxSizing = "border-box", d.style.cursor = "grab", o.appendChild(d);
|
|
19
|
+
const p = document.createElement("div");
|
|
20
|
+
p.style.position = "absolute", p.style.left = "0", p.style.top = "0", p.style.bottom = "0", p.style.width = "10px", p.style.cursor = "ew-resize", d.appendChild(p);
|
|
21
|
+
const u = document.createElement("div");
|
|
22
|
+
u.style.position = "absolute", u.style.right = "0", u.style.top = "0", u.style.bottom = "0", u.style.width = "10px", u.style.cursor = "ew-resize", d.appendChild(u);
|
|
23
|
+
const h = document.createElement("div");
|
|
24
|
+
h.style.position = "absolute", h.style.left = "10px", h.style.right = "10px", h.style.top = "0", h.style.bottom = "0", h.style.cursor = "grab", d.appendChild(h), f.appendChild(r);
|
|
25
|
+
let g = !1, m = null;
|
|
26
|
+
const b = (c) => {
|
|
27
|
+
const y = Y(c), R = Z(y.end - y.start, 0, 100);
|
|
28
|
+
d.style.left = `${y.start}%`, d.style.width = `${R}%`;
|
|
29
|
+
}, C = () => {
|
|
30
|
+
const c = o.getBoundingClientRect().width;
|
|
31
|
+
return Number.isFinite(c) && c > 0 ? c : null;
|
|
32
|
+
}, w = (c) => {
|
|
33
|
+
const y = C();
|
|
34
|
+
if (y === null) return null;
|
|
35
|
+
const R = c / y * 100;
|
|
36
|
+
return Number.isFinite(R) ? R : null;
|
|
37
|
+
}, E = (c, y) => {
|
|
38
|
+
try {
|
|
39
|
+
c.setPointerCapture(y);
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
}, S = (c, y) => {
|
|
43
|
+
try {
|
|
44
|
+
c.releasePointerCapture(y);
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
}, I = (c, y) => {
|
|
48
|
+
if (g || c.button !== 0) return;
|
|
49
|
+
c.preventDefault(), m == null || m(), m = null;
|
|
50
|
+
const R = c.clientX, M = e.getRange(), _ = c.currentTarget instanceof Element ? c.currentTarget : d;
|
|
51
|
+
E(_, c.pointerId), y === "pan-window" && (d.style.cursor = "grabbing", h.style.cursor = "grabbing");
|
|
52
|
+
const z = (P) => {
|
|
53
|
+
if (g || P.pointerId !== c.pointerId) return;
|
|
54
|
+
P.preventDefault();
|
|
55
|
+
const D = w(P.clientX - R);
|
|
56
|
+
if (D !== null)
|
|
57
|
+
switch (y) {
|
|
58
|
+
case "left-handle": {
|
|
59
|
+
const k = Math.min(M.end, M.start + D), L = e;
|
|
60
|
+
L.setRangeAnchored ? L.setRangeAnchored(k, M.end, "end") : e.setRange(k, M.end);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
case "right-handle": {
|
|
64
|
+
const k = Math.max(M.start, M.end + D), L = e;
|
|
65
|
+
L.setRangeAnchored ? L.setRangeAnchored(M.start, k, "start") : e.setRange(M.start, k);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
case "pan-window": {
|
|
69
|
+
e.setRange(M.start + D, M.end + D);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
let W = !1;
|
|
75
|
+
const O = () => {
|
|
76
|
+
W || (W = !0, window.removeEventListener("pointermove", z), window.removeEventListener("pointerup", T), window.removeEventListener("pointercancel", T), y === "pan-window" && (d.style.cursor = "grab", h.style.cursor = "grab"), S(_, c.pointerId), m === O && (m = null));
|
|
77
|
+
}, T = (P) => {
|
|
78
|
+
P.pointerId === c.pointerId && O();
|
|
79
|
+
};
|
|
80
|
+
m = O, window.addEventListener("pointermove", z, { passive: !1 }), window.addEventListener("pointerup", T, { passive: !0 }), window.addEventListener("pointercancel", T, { passive: !0 });
|
|
81
|
+
}, x = (c) => I(c, "left-handle"), U = (c) => I(c, "right-handle"), H = (c) => I(c, "pan-window");
|
|
82
|
+
p.addEventListener("pointerdown", x, { passive: !1 }), u.addEventListener("pointerdown", U, { passive: !1 }), h.addEventListener("pointerdown", H, { passive: !1 });
|
|
83
|
+
const F = e.onChange((c) => {
|
|
84
|
+
g || b(c);
|
|
85
|
+
});
|
|
86
|
+
return b(e.getRange()), { update: (c) => {
|
|
87
|
+
if (g) return;
|
|
88
|
+
o.style.background = c.backgroundColor, o.style.borderColor = c.axisLineColor, l.style.background = c.gridLineColor, d.style.background = c.gridLineColor, d.style.border = `1px solid ${c.axisTickColor}`, d.style.borderRadius = "8px", d.style.boxSizing = "border-box";
|
|
89
|
+
const y = `1px solid ${c.axisLineColor}`;
|
|
90
|
+
p.style.background = c.axisTickColor, p.style.borderRight = y, u.style.background = c.axisTickColor, u.style.borderLeft = y, h.style.background = "transparent", h.style.backgroundImage = "linear-gradient(90deg, rgba(255,255,255,0.0) 0, rgba(255,255,255,0.0) 42%, rgba(255,255,255,0.18) 42%, rgba(255,255,255,0.18) 46%, rgba(255,255,255,0.0) 46%, rgba(255,255,255,0.0) 54%, rgba(255,255,255,0.18) 54%, rgba(255,255,255,0.18) 58%, rgba(255,255,255,0.0) 58%, rgba(255,255,255,0.0) 100%)", h.style.mixBlendMode = "normal";
|
|
91
|
+
}, dispose: () => {
|
|
92
|
+
if (!g) {
|
|
93
|
+
g = !0, m == null || m(), m = null;
|
|
94
|
+
try {
|
|
95
|
+
F();
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
p.removeEventListener("pointerdown", x), u.removeEventListener("pointerdown", U), h.removeEventListener("pointerdown", H), r.remove();
|
|
99
|
+
}
|
|
100
|
+
} };
|
|
101
|
+
}
|
|
102
|
+
const V = 8, j = 20;
|
|
103
|
+
class v extends Error {
|
|
104
|
+
constructor(e, t, s, i) {
|
|
105
|
+
super(e), this.code = t, this.operation = s, this.chartId = i, this.name = "ChartGPUWorkerError";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
let K = 0;
|
|
109
|
+
function J() {
|
|
110
|
+
return `msg_${Date.now()}_${++K}`;
|
|
111
|
+
}
|
|
112
|
+
function ee() {
|
|
113
|
+
return `chart_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
114
|
+
}
|
|
115
|
+
const $ = 40;
|
|
116
|
+
function te(f) {
|
|
117
|
+
if (f.length === 0)
|
|
118
|
+
return [new ArrayBuffer(0), 0];
|
|
119
|
+
const e = f[0];
|
|
120
|
+
if (Array.isArray(e) ? e.length === 5 : "timestamp" in e && "open" in e) {
|
|
121
|
+
const i = new ArrayBuffer(f.length * 20), n = new Float32Array(i);
|
|
122
|
+
for (let a = 0, r = 0; a < f.length; a++, r += 5) {
|
|
123
|
+
const o = f[a];
|
|
124
|
+
if (Array.isArray(o))
|
|
125
|
+
n[r] = o[0], n[r + 1] = o[1], n[r + 2] = o[2], n[r + 3] = o[3], n[r + 4] = o[4];
|
|
126
|
+
else {
|
|
127
|
+
const l = o;
|
|
128
|
+
n[r] = l.timestamp, n[r + 1] = l.open, n[r + 2] = l.close, n[r + 3] = l.low, n[r + 4] = l.high;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [i, 20];
|
|
132
|
+
} else {
|
|
133
|
+
const i = new ArrayBuffer(f.length * 8), n = new Float32Array(i);
|
|
134
|
+
for (let a = 0, r = 0; a < f.length; a++, r += 2) {
|
|
135
|
+
const o = f[a];
|
|
136
|
+
if (Array.isArray(o))
|
|
137
|
+
n[r] = o[0], n[r + 1] = o[1];
|
|
138
|
+
else {
|
|
139
|
+
const l = o;
|
|
140
|
+
n[r] = l.x, n[r + 1] = l.y;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return [i, 8];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function A(f, e, t) {
|
|
147
|
+
var b, C, w, E, S;
|
|
148
|
+
const s = e.getBoundingClientRect(), i = f.clientX - s.left, n = f.clientY - s.top, a = ((b = t.grid) == null ? void 0 : b.left) ?? 60, r = ((C = t.grid) == null ? void 0 : C.top) ?? 40, o = ((w = t.grid) == null ? void 0 : w.right) ?? 20;
|
|
149
|
+
let l = ((E = t.grid) == null ? void 0 : E.bottom) ?? 40;
|
|
150
|
+
(((S = t.dataZoom) == null ? void 0 : S.some((I) => (I == null ? void 0 : I.type) === "slider")) ?? !1) && (l += $);
|
|
151
|
+
const p = s.width - a - o, u = s.height - r - l, h = i - a, g = n - r, m = h >= 0 && h <= p && g >= 0 && g <= u;
|
|
152
|
+
return {
|
|
153
|
+
x: i,
|
|
154
|
+
y: n,
|
|
155
|
+
gridX: h,
|
|
156
|
+
gridY: g,
|
|
157
|
+
plotWidthCss: p,
|
|
158
|
+
plotHeightCss: u,
|
|
159
|
+
isInGrid: m,
|
|
160
|
+
timestamp: f.timeStamp
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
class se {
|
|
164
|
+
/**
|
|
165
|
+
* Creates a new worker-based chart proxy.
|
|
166
|
+
*
|
|
167
|
+
* @param config - Worker configuration
|
|
168
|
+
* @param container - HTML element to attach canvas to
|
|
169
|
+
* @param options - Chart options
|
|
170
|
+
*/
|
|
171
|
+
constructor(e, t, s) {
|
|
172
|
+
this.container = t, this.isDisposed = !1, this.isInitialized = !1, this.cachedInteractionX = null, this.cachedZoomRange = null, this.cachedSeriesPointCountsForZoom = [], this.cachedPerformanceMetrics = null, this.cachedPerformanceCapabilities = null, this.performanceUpdateCallbacks = /* @__PURE__ */ new Set(), this.pendingRequests = /* @__PURE__ */ new Map(), this.listeners = /* @__PURE__ */ new Map(), this.tooltip = null, this.legend = null, this.textOverlay = null, this.dataZoomSlider = null, this.dataZoomSliderHost = null, this.zoomState = null, this.pendingOverlayUpdates = {}, this.overlayUpdateRafId = null, this.isProcessingWorkerZoomUpdate = !1, this.boundEventHandlers = {
|
|
173
|
+
pointerdown: null,
|
|
174
|
+
pointermove: null,
|
|
175
|
+
pointerup: null,
|
|
176
|
+
pointerleave: null,
|
|
177
|
+
wheel: null
|
|
178
|
+
}, this.pendingMoveEvent = null, this.moveThrottleRafId = null, this.tapCandidate = null, this.TAP_MAX_DISTANCE_PX = 6, this.TAP_MAX_TIME_MS = 500, this.resizeObserver = null, this.currentDpr = 1, this.dprMediaQuery = null, this.boundDprChangeHandler = null, this.pendingResize = null, this.resizeRafId = null, this.worker = e.worker, this.chartId = e.chartId ?? ee(), this.messageTimeout = e.messageTimeout ?? 3e4, this.cachedOptions = s, this.recomputeCachedSeriesPointCountsForZoom(s), this.listeners.set("click", /* @__PURE__ */ new Set()), this.listeners.set("mouseover", /* @__PURE__ */ new Set()), this.listeners.set("mouseout", /* @__PURE__ */ new Set()), this.listeners.set("crosshairMove", /* @__PURE__ */ new Set()), this.boundMessageHandler = this.handleWorkerMessage.bind(this), this.worker.addEventListener("message", this.boundMessageHandler);
|
|
179
|
+
}
|
|
180
|
+
recomputeCachedSeriesPointCountsForZoom(e) {
|
|
181
|
+
const t = e.series ?? [], s = new Array(t.length);
|
|
182
|
+
for (let i = 0; i < t.length; i++) {
|
|
183
|
+
const n = t[i];
|
|
184
|
+
if (!n || n.type === "pie") {
|
|
185
|
+
s[i] = 0;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const a = n.rawData ?? n.data;
|
|
189
|
+
s[i] = Array.isArray(a) ? a.length : 0;
|
|
190
|
+
}
|
|
191
|
+
this.cachedSeriesPointCountsForZoom = s;
|
|
192
|
+
}
|
|
193
|
+
incrementCachedSeriesPointCountForZoom(e, t) {
|
|
194
|
+
if (!Number.isFinite(t) || t <= 0) return;
|
|
195
|
+
const s = Math.floor(t);
|
|
196
|
+
if (s <= 0) return;
|
|
197
|
+
const i = this.cachedSeriesPointCountsForZoom;
|
|
198
|
+
if (e >= i.length)
|
|
199
|
+
for (let n = i.length; n <= e; n++) i[n] = 0;
|
|
200
|
+
i[e] = (i[e] ?? 0) + s;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Initializes the worker chart instance.
|
|
204
|
+
* Must be called before using the chart.
|
|
205
|
+
*
|
|
206
|
+
* @returns Promise that resolves when worker is ready
|
|
207
|
+
*/
|
|
208
|
+
async init() {
|
|
209
|
+
const e = document.createElement("canvas");
|
|
210
|
+
e.style.display = "block", e.style.width = "100%", e.style.height = "100%", this.container.appendChild(e);
|
|
211
|
+
const t = e.getBoundingClientRect(), s = window.devicePixelRatio || 1, i = Math.max(1, Math.round(t.width * s)), n = Math.max(1, Math.round(t.height * s));
|
|
212
|
+
e.width = i, e.height = n, this.setupEventListeners(e), this.setupResizeObserver(e), this.setupDevicePixelRatioMonitoring(), this.createOverlays();
|
|
213
|
+
const a = e.transferControlToOffscreen();
|
|
214
|
+
await this.sendMessageWithResponse({
|
|
215
|
+
type: "init",
|
|
216
|
+
chartId: this.chartId,
|
|
217
|
+
messageId: J(),
|
|
218
|
+
canvas: a,
|
|
219
|
+
devicePixelRatio: s,
|
|
220
|
+
options: this.cachedOptions
|
|
221
|
+
}, [a]);
|
|
222
|
+
}
|
|
223
|
+
// =============================================================================
|
|
224
|
+
// Event Forwarding to Worker
|
|
225
|
+
// =============================================================================
|
|
226
|
+
/**
|
|
227
|
+
* Sets up pointer and wheel event listeners on the canvas.
|
|
228
|
+
* Forwards events to worker for interaction handling (hover, click, zoom, pan).
|
|
229
|
+
*
|
|
230
|
+
* @param canvas - Canvas element to attach listeners to
|
|
231
|
+
*/
|
|
232
|
+
setupEventListeners(e) {
|
|
233
|
+
this.isDisposed || (this.boundEventHandlers.pointerdown = (t) => {
|
|
234
|
+
this.isDisposed || !this.isInitialized || t.isPrimary && t.button === 0 && (this.tapCandidate = {
|
|
235
|
+
startX: t.clientX,
|
|
236
|
+
startY: t.clientY,
|
|
237
|
+
startTime: t.timeStamp
|
|
238
|
+
});
|
|
239
|
+
}, this.boundEventHandlers.pointermove = (t) => {
|
|
240
|
+
this.isDisposed || !this.isInitialized || (this.pendingMoveEvent = t, this.moveThrottleRafId === null && (this.moveThrottleRafId = requestAnimationFrame(() => {
|
|
241
|
+
if (this.moveThrottleRafId = null, this.isDisposed || !this.isInitialized || !this.pendingMoveEvent) return;
|
|
242
|
+
const s = this.container.querySelector("canvas");
|
|
243
|
+
if (!s) return;
|
|
244
|
+
const i = A(this.pendingMoveEvent, s, this.cachedOptions);
|
|
245
|
+
this.pendingMoveEvent = null, console.log("[ChartGPUWorkerProxy] Sending move event:", {
|
|
246
|
+
gridX: i.gridX,
|
|
247
|
+
gridY: i.gridY,
|
|
248
|
+
isInGrid: i.isInGrid
|
|
249
|
+
}), this.sendMessage({
|
|
250
|
+
type: "forwardPointerEvent",
|
|
251
|
+
chartId: this.chartId,
|
|
252
|
+
event: {
|
|
253
|
+
...i,
|
|
254
|
+
type: "move"
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
})));
|
|
258
|
+
}, this.boundEventHandlers.pointerup = (t) => {
|
|
259
|
+
if (!(this.isDisposed || !this.isInitialized) && t.isPrimary && this.tapCandidate) {
|
|
260
|
+
const s = t.timeStamp - this.tapCandidate.startTime, i = t.clientX - this.tapCandidate.startX, n = t.clientY - this.tapCandidate.startY, a = Math.sqrt(i * i + n * n);
|
|
261
|
+
if (this.tapCandidate = null, s <= this.TAP_MAX_TIME_MS && a <= this.TAP_MAX_DISTANCE_PX) {
|
|
262
|
+
const r = this.container.querySelector("canvas");
|
|
263
|
+
if (!r) return;
|
|
264
|
+
const o = A(t, r, this.cachedOptions);
|
|
265
|
+
console.log("[ChartGPUWorkerProxy] Sending click event:", {
|
|
266
|
+
gridX: o.gridX,
|
|
267
|
+
gridY: o.gridY,
|
|
268
|
+
isInGrid: o.isInGrid
|
|
269
|
+
}), this.sendMessage({
|
|
270
|
+
type: "forwardPointerEvent",
|
|
271
|
+
chartId: this.chartId,
|
|
272
|
+
event: {
|
|
273
|
+
...o,
|
|
274
|
+
type: "click"
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}, this.boundEventHandlers.pointerleave = (t) => {
|
|
280
|
+
if (this.isDisposed || !this.isInitialized) return;
|
|
281
|
+
this.tapCandidate = null;
|
|
282
|
+
const s = this.container.querySelector("canvas");
|
|
283
|
+
if (!s) return;
|
|
284
|
+
const i = A(t, s, this.cachedOptions);
|
|
285
|
+
this.sendMessage({
|
|
286
|
+
type: "forwardPointerEvent",
|
|
287
|
+
chartId: this.chartId,
|
|
288
|
+
event: {
|
|
289
|
+
...i,
|
|
290
|
+
type: "leave"
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}, this.boundEventHandlers.wheel = (t) => {
|
|
294
|
+
var C, w, E, S, I;
|
|
295
|
+
if (this.isDisposed || !this.isInitialized) return;
|
|
296
|
+
const s = e.getBoundingClientRect(), i = t.clientX - s.left, n = t.clientY - s.top, a = ((C = this.cachedOptions.grid) == null ? void 0 : C.left) ?? 60, r = ((w = this.cachedOptions.grid) == null ? void 0 : w.top) ?? 40, o = ((E = this.cachedOptions.grid) == null ? void 0 : E.right) ?? 20;
|
|
297
|
+
let l = ((S = this.cachedOptions.grid) == null ? void 0 : S.bottom) ?? 40;
|
|
298
|
+
(((I = this.cachedOptions.dataZoom) == null ? void 0 : I.some((x) => (x == null ? void 0 : x.type) === "slider")) ?? !1) && (l += $);
|
|
299
|
+
const p = s.width - a - o, u = s.height - r - l, h = i - a, g = n - r, m = h >= 0 && h <= p && g >= 0 && g <= u, b = {
|
|
300
|
+
type: "wheel",
|
|
301
|
+
x: i,
|
|
302
|
+
y: n,
|
|
303
|
+
gridX: h,
|
|
304
|
+
gridY: g,
|
|
305
|
+
plotWidthCss: p,
|
|
306
|
+
plotHeightCss: u,
|
|
307
|
+
isInGrid: m,
|
|
308
|
+
timestamp: t.timeStamp,
|
|
309
|
+
deltaX: t.deltaX,
|
|
310
|
+
deltaY: t.deltaY,
|
|
311
|
+
deltaZ: t.deltaZ,
|
|
312
|
+
deltaMode: t.deltaMode
|
|
313
|
+
};
|
|
314
|
+
this.sendMessage({
|
|
315
|
+
type: "forwardPointerEvent",
|
|
316
|
+
chartId: this.chartId,
|
|
317
|
+
event: b
|
|
318
|
+
}), m && t.preventDefault();
|
|
319
|
+
}, e.addEventListener("pointerdown", this.boundEventHandlers.pointerdown), e.addEventListener("pointermove", this.boundEventHandlers.pointermove), e.addEventListener("pointerup", this.boundEventHandlers.pointerup), e.addEventListener("pointerleave", this.boundEventHandlers.pointerleave), e.addEventListener("wheel", this.boundEventHandlers.wheel, { passive: !1 }));
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Removes all event listeners from the canvas and cleans up RAF throttling.
|
|
323
|
+
*/
|
|
324
|
+
cleanupEventListeners() {
|
|
325
|
+
const e = this.container.querySelector("canvas");
|
|
326
|
+
e && (this.moveThrottleRafId !== null && (cancelAnimationFrame(this.moveThrottleRafId), this.moveThrottleRafId = null), this.pendingMoveEvent = null, this.tapCandidate = null, this.boundEventHandlers.pointerdown && (e.removeEventListener("pointerdown", this.boundEventHandlers.pointerdown), this.boundEventHandlers.pointerdown = null), this.boundEventHandlers.pointermove && (e.removeEventListener("pointermove", this.boundEventHandlers.pointermove), this.boundEventHandlers.pointermove = null), this.boundEventHandlers.pointerup && (e.removeEventListener("pointerup", this.boundEventHandlers.pointerup), this.boundEventHandlers.pointerup = null), this.boundEventHandlers.pointerleave && (e.removeEventListener("pointerleave", this.boundEventHandlers.pointerleave), this.boundEventHandlers.pointerleave = null), this.boundEventHandlers.wheel && (e.removeEventListener("wheel", this.boundEventHandlers.wheel), this.boundEventHandlers.wheel = null));
|
|
327
|
+
}
|
|
328
|
+
// =============================================================================
|
|
329
|
+
// ResizeObserver and Device Pixel Ratio Monitoring
|
|
330
|
+
// =============================================================================
|
|
331
|
+
/**
|
|
332
|
+
* Sets up ResizeObserver to monitor container size changes.
|
|
333
|
+
* Uses RAF batching to throttle rapid resize events (e.g., during window drag-resize).
|
|
334
|
+
*
|
|
335
|
+
* @param canvas - Canvas element to measure dimensions from
|
|
336
|
+
*/
|
|
337
|
+
setupResizeObserver(e) {
|
|
338
|
+
if (this.isDisposed) return;
|
|
339
|
+
let t = e.clientWidth, s = e.clientHeight;
|
|
340
|
+
this.resizeObserver = new ResizeObserver((i) => {
|
|
341
|
+
var o;
|
|
342
|
+
if (this.isDisposed || !i[0]) return;
|
|
343
|
+
const n = (o = i[0].contentBoxSize) == null ? void 0 : o[0];
|
|
344
|
+
if (!n) return;
|
|
345
|
+
const a = n.inlineSize, r = n.blockSize;
|
|
346
|
+
a === t && r === s || (t = a, s = r, this.pendingResize = { width: a, height: r }, this.resizeRafId === null && (this.resizeRafId = requestAnimationFrame(() => {
|
|
347
|
+
if (this.resizeRafId = null, this.isDisposed || !this.pendingResize) return;
|
|
348
|
+
const { width: l, height: d } = this.pendingResize;
|
|
349
|
+
this.pendingResize = null;
|
|
350
|
+
const p = this.currentDpr;
|
|
351
|
+
this.sendMessage({
|
|
352
|
+
type: "resize",
|
|
353
|
+
chartId: this.chartId,
|
|
354
|
+
width: Math.max(1, l),
|
|
355
|
+
// CSS pixels, minimum 1
|
|
356
|
+
height: Math.max(1, d),
|
|
357
|
+
// CSS pixels, minimum 1
|
|
358
|
+
devicePixelRatio: p,
|
|
359
|
+
requestRender: !0
|
|
360
|
+
});
|
|
361
|
+
})));
|
|
362
|
+
}), this.resizeObserver.observe(e);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Sets up device pixel ratio monitoring using matchMedia.
|
|
366
|
+
* Handles window zoom, moving between displays, and OS display scaling changes.
|
|
367
|
+
*/
|
|
368
|
+
setupDevicePixelRatioMonitoring() {
|
|
369
|
+
this.isDisposed || (this.currentDpr = window.devicePixelRatio || 1, this.dprMediaQuery = window.matchMedia(`(resolution: ${this.currentDpr}dppx)`), this.boundDprChangeHandler = (e) => {
|
|
370
|
+
if (this.isDisposed) return;
|
|
371
|
+
const t = window.devicePixelRatio || 1;
|
|
372
|
+
if (t === this.currentDpr) return;
|
|
373
|
+
this.currentDpr = t, this.dprMediaQuery && this.boundDprChangeHandler && this.dprMediaQuery.removeEventListener("change", this.boundDprChangeHandler), this.dprMediaQuery = window.matchMedia(`(resolution: ${this.currentDpr}dppx)`), this.boundDprChangeHandler && this.dprMediaQuery.addEventListener("change", this.boundDprChangeHandler);
|
|
374
|
+
const s = this.container.querySelector("canvas");
|
|
375
|
+
if (!s) return;
|
|
376
|
+
const i = s.clientWidth, n = s.clientHeight;
|
|
377
|
+
this.sendMessage({
|
|
378
|
+
type: "resize",
|
|
379
|
+
chartId: this.chartId,
|
|
380
|
+
width: Math.max(1, i),
|
|
381
|
+
// CSS pixels
|
|
382
|
+
height: Math.max(1, n),
|
|
383
|
+
// CSS pixels
|
|
384
|
+
devicePixelRatio: this.currentDpr,
|
|
385
|
+
requestRender: !0
|
|
386
|
+
});
|
|
387
|
+
}, this.dprMediaQuery.addEventListener("change", this.boundDprChangeHandler));
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Cleans up ResizeObserver and device pixel ratio monitoring.
|
|
391
|
+
*/
|
|
392
|
+
cleanupResizeMonitoring() {
|
|
393
|
+
this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.resizeRafId !== null && (cancelAnimationFrame(this.resizeRafId), this.resizeRafId = null), this.pendingResize = null, this.dprMediaQuery && this.boundDprChangeHandler && (this.dprMediaQuery.removeEventListener("change", this.boundDprChangeHandler), this.dprMediaQuery = null, this.boundDprChangeHandler = null);
|
|
394
|
+
}
|
|
395
|
+
// =============================================================================
|
|
396
|
+
// DOM Overlay Management
|
|
397
|
+
// =============================================================================
|
|
398
|
+
/**
|
|
399
|
+
* Creates DOM overlays for tooltip, legend, text labels, and data zoom slider.
|
|
400
|
+
* Called after canvas is appended to container.
|
|
401
|
+
*/
|
|
402
|
+
createOverlays() {
|
|
403
|
+
var t, s, i;
|
|
404
|
+
if (this.isDisposed) return;
|
|
405
|
+
if (this.tooltip = X(this.container), this.textOverlay = G(this.container), this.legend = N(this.container, "right"), ((t = this.cachedOptions.dataZoom) == null ? void 0 : t.some((n) => (n == null ? void 0 : n.type) === "slider")) ?? !1) {
|
|
406
|
+
const n = ((s = this.cachedZoomRange) == null ? void 0 : s.start) ?? 0, a = ((i = this.cachedZoomRange) == null ? void 0 : i.end) ?? 100, r = this.computeZoomSpanConstraints(this.cachedOptions);
|
|
407
|
+
this.zoomState = q(n, a, r), this.zoomState.onChange((d) => {
|
|
408
|
+
this.isDisposed || this.isProcessingWorkerZoomUpdate || this.setZoomRange(d.start, d.end);
|
|
409
|
+
}), this.dataZoomSliderHost = this.createDataZoomSliderHost();
|
|
410
|
+
const o = 32;
|
|
411
|
+
this.dataZoomSlider = Q(this.dataZoomSliderHost, this.zoomState, {
|
|
412
|
+
height: o,
|
|
413
|
+
marginTop: 0
|
|
414
|
+
// host provides vertical spacing
|
|
415
|
+
});
|
|
416
|
+
const l = this.resolveThemeConfig();
|
|
417
|
+
this.dataZoomSlider.update(l);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Creates and configures the data zoom slider host element.
|
|
422
|
+
* The host is absolutely positioned at the bottom of the container.
|
|
423
|
+
*
|
|
424
|
+
* @returns Host element for the data zoom slider
|
|
425
|
+
*/
|
|
426
|
+
createDataZoomSliderHost() {
|
|
427
|
+
try {
|
|
428
|
+
window.getComputedStyle(this.container).position === "static" && (this.container.style.position = "relative");
|
|
429
|
+
} catch {
|
|
430
|
+
}
|
|
431
|
+
const e = 32, t = 8, s = e + t, i = document.createElement("div");
|
|
432
|
+
return i.style.position = "absolute", i.style.left = "0", i.style.right = "0", i.style.bottom = "0", i.style.height = `${s}px`, i.style.paddingTop = `${t}px`, i.style.boxSizing = "border-box", i.style.pointerEvents = "auto", i.style.zIndex = "10", this.container.appendChild(i), i;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Computes effective zoom span constraints for the local slider zoomState.
|
|
436
|
+
*
|
|
437
|
+
* This must match the worker coordinator's clamping behavior so that:
|
|
438
|
+
* - slider drags clamp identically to wheel zoom in the worker
|
|
439
|
+
* - UI stays perfectly in sync with worker zoomChange messages
|
|
440
|
+
*/
|
|
441
|
+
computeZoomSpanConstraints(e) {
|
|
442
|
+
var l;
|
|
443
|
+
const t = (d) => Math.min(100, Math.max(0, d));
|
|
444
|
+
let s = null, i = null;
|
|
445
|
+
for (const d of e.dataZoom ?? [])
|
|
446
|
+
if (d && !(d.type !== "inside" && d.type !== "slider")) {
|
|
447
|
+
if (Number.isFinite(d.minSpan)) {
|
|
448
|
+
const p = t(d.minSpan);
|
|
449
|
+
s = s == null ? p : Math.max(s, p);
|
|
450
|
+
}
|
|
451
|
+
if (Number.isFinite(d.maxSpan)) {
|
|
452
|
+
const p = t(d.maxSpan);
|
|
453
|
+
i = i == null ? p : Math.min(i, p);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const n = ((l = e.xAxis) == null ? void 0 : l.type) ?? "value";
|
|
457
|
+
let a = null;
|
|
458
|
+
if (n !== "category") {
|
|
459
|
+
let d = 0;
|
|
460
|
+
const p = e.series ?? [];
|
|
461
|
+
for (let u = 0; u < p.length; u++) {
|
|
462
|
+
const h = p[u];
|
|
463
|
+
if (!h || h.type === "pie") continue;
|
|
464
|
+
const g = this.cachedSeriesPointCountsForZoom[u] ?? 0;
|
|
465
|
+
d = Math.max(d, g);
|
|
466
|
+
}
|
|
467
|
+
if (d >= 2) {
|
|
468
|
+
const u = 100 / (d - 1);
|
|
469
|
+
a = Number.isFinite(u) ? t(u) : null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return { minSpan: s ?? a ?? 0.5, maxSpan: i ?? 100 };
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Resolves ThemeConfig from options, handling both string presets and custom configs.
|
|
476
|
+
*/
|
|
477
|
+
resolveThemeConfig() {
|
|
478
|
+
const e = this.cachedOptions.theme, t = {
|
|
479
|
+
colorPalette: [],
|
|
480
|
+
backgroundColor: "#1a1a2e",
|
|
481
|
+
textColor: "#e0e0e0",
|
|
482
|
+
axisLineColor: "rgba(224,224,224,0.2)",
|
|
483
|
+
axisTickColor: "rgba(224,224,224,0.4)",
|
|
484
|
+
gridLineColor: "rgba(224,224,224,0.1)",
|
|
485
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
486
|
+
fontSize: 12
|
|
487
|
+
};
|
|
488
|
+
return !e || typeof e == "string" ? t : {
|
|
489
|
+
colorPalette: e.colorPalette ?? t.colorPalette,
|
|
490
|
+
backgroundColor: e.backgroundColor ?? t.backgroundColor,
|
|
491
|
+
textColor: e.textColor ?? t.textColor,
|
|
492
|
+
axisLineColor: e.axisLineColor ?? t.axisLineColor,
|
|
493
|
+
axisTickColor: e.axisTickColor ?? t.axisTickColor,
|
|
494
|
+
gridLineColor: e.gridLineColor ?? t.gridLineColor,
|
|
495
|
+
fontFamily: e.fontFamily ?? t.fontFamily,
|
|
496
|
+
fontSize: e.fontSize ?? t.fontSize
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Disposes all DOM overlays and cleans up RAF batching.
|
|
501
|
+
*/
|
|
502
|
+
disposeOverlays() {
|
|
503
|
+
var e, t, s, i, n;
|
|
504
|
+
this.overlayUpdateRafId !== null && (cancelAnimationFrame(this.overlayUpdateRafId), this.overlayUpdateRafId = null), this.pendingOverlayUpdates = {}, (e = this.tooltip) == null || e.dispose(), this.tooltip = null, (t = this.legend) == null || t.dispose(), this.legend = null, (s = this.textOverlay) == null || s.dispose(), this.textOverlay = null, (i = this.dataZoomSlider) == null || i.dispose(), this.dataZoomSlider = null, (n = this.dataZoomSliderHost) == null || n.remove(), this.dataZoomSliderHost = null, this.zoomState = null;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Schedules overlay updates in the next RAF to batch multiple updates.
|
|
508
|
+
*
|
|
509
|
+
* **Batching strategy**: Worker can send multiple overlay update messages per frame
|
|
510
|
+
* (tooltip + legend + axis labels). By batching them in RAF, we:
|
|
511
|
+
* 1. Reduce layout thrashing (DOM reads/writes grouped)
|
|
512
|
+
* 2. Ensure visual consistency (all overlays update simultaneously)
|
|
513
|
+
* 3. Prevent redundant style calculations (browser optimizes batched changes)
|
|
514
|
+
*
|
|
515
|
+
* **Concurrency safety**: Uses overlayUpdateRafId guard to prevent duplicate RAF scheduling.
|
|
516
|
+
* Multiple calls within the same frame will coalesce into a single RAF callback.
|
|
517
|
+
*/
|
|
518
|
+
scheduleOverlayUpdates() {
|
|
519
|
+
this.isDisposed || this.overlayUpdateRafId === null && (this.overlayUpdateRafId = requestAnimationFrame(() => {
|
|
520
|
+
this.overlayUpdateRafId = null, !this.isDisposed && this.applyPendingOverlayUpdates();
|
|
521
|
+
}));
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Applies all pending overlay updates in a single batch.
|
|
525
|
+
*/
|
|
526
|
+
applyPendingOverlayUpdates() {
|
|
527
|
+
const { tooltip: e, legend: t, axisLabels: s } = this.pendingOverlayUpdates;
|
|
528
|
+
if (e && this.tooltip && (e.data ? this.tooltip.show(e.data.x, e.data.y, e.data.content) : this.tooltip.hide()), t && this.legend) {
|
|
529
|
+
const i = t.items.map((a) => ({
|
|
530
|
+
type: "line",
|
|
531
|
+
name: a.name,
|
|
532
|
+
color: a.color,
|
|
533
|
+
data: []
|
|
534
|
+
})), n = this.resolveThemeConfig();
|
|
535
|
+
this.legend.update(i, n);
|
|
536
|
+
}
|
|
537
|
+
if (s && this.textOverlay) {
|
|
538
|
+
const i = this.resolveThemeConfig();
|
|
539
|
+
B(
|
|
540
|
+
this.textOverlay,
|
|
541
|
+
s.xLabels,
|
|
542
|
+
s.yLabels,
|
|
543
|
+
i
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
this.pendingOverlayUpdates = {};
|
|
547
|
+
}
|
|
548
|
+
// =============================================================================
|
|
549
|
+
// ChartGPUInstance Interface Implementation
|
|
550
|
+
// =============================================================================
|
|
551
|
+
get options() {
|
|
552
|
+
return this.cachedOptions;
|
|
553
|
+
}
|
|
554
|
+
get disposed() {
|
|
555
|
+
return this.isDisposed;
|
|
556
|
+
}
|
|
557
|
+
setOption(e) {
|
|
558
|
+
var n, a, r;
|
|
559
|
+
if (this.isDisposed)
|
|
560
|
+
throw new v(
|
|
561
|
+
"Cannot setOption on disposed chart",
|
|
562
|
+
"DISPOSED",
|
|
563
|
+
"setOption",
|
|
564
|
+
this.chartId
|
|
565
|
+
);
|
|
566
|
+
const s = ((n = this.cachedOptions.dataZoom) == null ? void 0 : n.some((o) => (o == null ? void 0 : o.type) === "slider")) ?? !1, i = ((a = e.dataZoom) == null ? void 0 : a.some((o) => (o == null ? void 0 : o.type) === "slider")) ?? !1;
|
|
567
|
+
if (this.cachedOptions = e, this.recomputeCachedSeriesPointCountsForZoom(e), s !== i)
|
|
568
|
+
this.disposeOverlays(), this.createOverlays();
|
|
569
|
+
else if (i && this.zoomState) {
|
|
570
|
+
const o = this.computeZoomSpanConstraints(e), l = this.zoomState;
|
|
571
|
+
(r = l.setSpanConstraints) == null || r.call(
|
|
572
|
+
l,
|
|
573
|
+
o.minSpan ?? 0.5,
|
|
574
|
+
o.maxSpan ?? 100
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
this.sendMessage({
|
|
578
|
+
type: "setOption",
|
|
579
|
+
chartId: this.chartId,
|
|
580
|
+
options: e
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
// Implementation
|
|
584
|
+
appendData(e, t, s) {
|
|
585
|
+
var r, o;
|
|
586
|
+
if (this.isDisposed)
|
|
587
|
+
throw new v(
|
|
588
|
+
"Cannot appendData on disposed chart",
|
|
589
|
+
"DISPOSED",
|
|
590
|
+
"appendData",
|
|
591
|
+
this.chartId
|
|
592
|
+
);
|
|
593
|
+
if (!Number.isInteger(e) || e < 0)
|
|
594
|
+
throw new v(
|
|
595
|
+
`Invalid seriesIndex: ${e}. Must be a non-negative integer.`,
|
|
596
|
+
"INVALID_ARGUMENT",
|
|
597
|
+
"appendData",
|
|
598
|
+
this.chartId
|
|
599
|
+
);
|
|
600
|
+
if (t instanceof Float32Array || t instanceof Float64Array) {
|
|
601
|
+
if (!s)
|
|
602
|
+
throw new v(
|
|
603
|
+
"pointType parameter is required when passing typed arrays",
|
|
604
|
+
"INVALID_ARGUMENT",
|
|
605
|
+
"appendData",
|
|
606
|
+
this.chartId
|
|
607
|
+
);
|
|
608
|
+
const l = t;
|
|
609
|
+
if (l.length === 0)
|
|
610
|
+
return;
|
|
611
|
+
const d = s === "xy" ? 2 : 5, p = l.length / d, u = s === "xy" ? V : j;
|
|
612
|
+
if (l.length % d !== 0)
|
|
613
|
+
throw new v(
|
|
614
|
+
`Invalid typed array length: ${l.length}. Expected multiple of ${d} for '${s}' points.`,
|
|
615
|
+
"INVALID_ARGUMENT",
|
|
616
|
+
"appendData",
|
|
617
|
+
this.chartId
|
|
618
|
+
);
|
|
619
|
+
let h;
|
|
620
|
+
if (l instanceof Float64Array ? h = new Float32Array(l) : h = l, h.buffer.byteLength === 0) {
|
|
621
|
+
console.error(
|
|
622
|
+
"ChartGPU: Cannot transfer detached ArrayBuffer. The buffer may have already been transferred to another context."
|
|
623
|
+
);
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
const g = p * u, m = h.byteLength;
|
|
627
|
+
if (m !== g && console.warn(
|
|
628
|
+
`ChartGPU: Data buffer size mismatch. Expected ${g} bytes (${p} points × ${u} stride), got ${m} bytes.`
|
|
629
|
+
), h.byteLength % 4 !== 0)
|
|
630
|
+
throw new v(
|
|
631
|
+
`Buffer size (${h.byteLength} bytes) is not 4-byte aligned (WebGPU requirement)`,
|
|
632
|
+
"INVALID_ARGUMENT",
|
|
633
|
+
"appendData",
|
|
634
|
+
this.chartId
|
|
635
|
+
);
|
|
636
|
+
let b;
|
|
637
|
+
if (h.byteOffset === 0 && h.byteLength === h.buffer.byteLength ? b = h.buffer : (b = h.buffer.slice(h.byteOffset, h.byteOffset + h.byteLength), console.warn(
|
|
638
|
+
`ChartGPU: Typed array uses a subarray view (byteOffset=${h.byteOffset}). A buffer copy is required for transfer. For best performance, ensure typed arrays own their entire underlying buffer.`
|
|
639
|
+
)), this.incrementCachedSeriesPointCountForZoom(e, p), this.zoomState) {
|
|
640
|
+
const C = this.computeZoomSpanConstraints(this.cachedOptions), w = this.zoomState;
|
|
641
|
+
(r = w.setSpanConstraints) == null || r.call(
|
|
642
|
+
w,
|
|
643
|
+
C.minSpan ?? 0.5,
|
|
644
|
+
C.maxSpan ?? 100
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
this.sendMessage({
|
|
648
|
+
type: "appendData",
|
|
649
|
+
chartId: this.chartId,
|
|
650
|
+
seriesIndex: e,
|
|
651
|
+
data: b,
|
|
652
|
+
pointCount: p,
|
|
653
|
+
stride: u
|
|
654
|
+
}, [b]);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
const i = t;
|
|
658
|
+
if (!i || i.length === 0)
|
|
659
|
+
return;
|
|
660
|
+
Array.isArray(i) && i.length > 1e4 && console.warn(
|
|
661
|
+
`ChartGPU: appendData called with ${i.length.toLocaleString()} points as array. Consider using Float32Array for better performance:
|
|
662
|
+
|
|
663
|
+
import { packDataPoints } from 'chart-gpu';
|
|
664
|
+
const packed = packDataPoints(points);
|
|
665
|
+
chart.appendData(seriesIndex, packed, 'xy');
|
|
666
|
+
|
|
667
|
+
This can reduce memory usage by 50% and eliminate serialization overhead (~${(i.length * 2e-5).toFixed(2)}ms saved per append).`
|
|
668
|
+
);
|
|
669
|
+
const [n, a] = te(i);
|
|
670
|
+
if (this.incrementCachedSeriesPointCountForZoom(e, i.length), this.zoomState) {
|
|
671
|
+
const l = this.computeZoomSpanConstraints(this.cachedOptions), d = this.zoomState;
|
|
672
|
+
(o = d.setSpanConstraints) == null || o.call(
|
|
673
|
+
d,
|
|
674
|
+
l.minSpan ?? 0.5,
|
|
675
|
+
l.maxSpan ?? 100
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
this.sendMessage({
|
|
679
|
+
type: "appendData",
|
|
680
|
+
chartId: this.chartId,
|
|
681
|
+
seriesIndex: e,
|
|
682
|
+
data: n,
|
|
683
|
+
pointCount: i.length,
|
|
684
|
+
stride: a
|
|
685
|
+
}, [n]);
|
|
686
|
+
}
|
|
687
|
+
resize() {
|
|
688
|
+
if (this.isDisposed)
|
|
689
|
+
return;
|
|
690
|
+
const e = this.container.querySelector("canvas");
|
|
691
|
+
if (!e) {
|
|
692
|
+
console.warn("ChartGPUWorkerProxy.resize(): Canvas not found in container");
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const t = e.getBoundingClientRect(), s = window.devicePixelRatio || 1, i = Math.max(1, t.width), n = Math.max(1, t.height);
|
|
696
|
+
this.sendMessage({
|
|
697
|
+
type: "resize",
|
|
698
|
+
chartId: this.chartId,
|
|
699
|
+
width: i,
|
|
700
|
+
height: n,
|
|
701
|
+
devicePixelRatio: s,
|
|
702
|
+
requestRender: !0
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
dispose() {
|
|
706
|
+
if (this.isDisposed)
|
|
707
|
+
return;
|
|
708
|
+
this.isDisposed = !0, this.isInitialized = !1, this.cleanupEventListeners(), this.cleanupResizeMonitoring(), this.disposeOverlays(), this.sendMessage({
|
|
709
|
+
type: "dispose",
|
|
710
|
+
chartId: this.chartId
|
|
711
|
+
});
|
|
712
|
+
for (const t of this.pendingRequests.values())
|
|
713
|
+
clearTimeout(t.timeout), t.reject(new v(
|
|
714
|
+
"Chart disposed before operation completed",
|
|
715
|
+
"DISPOSED",
|
|
716
|
+
t.operation,
|
|
717
|
+
this.chartId
|
|
718
|
+
));
|
|
719
|
+
this.pendingRequests.clear();
|
|
720
|
+
for (const t of this.listeners.values())
|
|
721
|
+
t.clear();
|
|
722
|
+
this.worker.removeEventListener("message", this.boundMessageHandler);
|
|
723
|
+
const e = this.container.querySelector("canvas");
|
|
724
|
+
e && e.remove();
|
|
725
|
+
}
|
|
726
|
+
on(e, t) {
|
|
727
|
+
if (this.isDisposed)
|
|
728
|
+
return;
|
|
729
|
+
const s = this.listeners.get(e);
|
|
730
|
+
s && s.add(t);
|
|
731
|
+
}
|
|
732
|
+
off(e, t) {
|
|
733
|
+
const s = this.listeners.get(e);
|
|
734
|
+
s && s.delete(t);
|
|
735
|
+
}
|
|
736
|
+
getInteractionX() {
|
|
737
|
+
return this.isDisposed ? null : this.cachedInteractionX;
|
|
738
|
+
}
|
|
739
|
+
setInteractionX(e, t) {
|
|
740
|
+
this.isDisposed || (this.cachedInteractionX = e, this.sendMessage({
|
|
741
|
+
type: "setInteractionX",
|
|
742
|
+
chartId: this.chartId,
|
|
743
|
+
x: e,
|
|
744
|
+
source: t
|
|
745
|
+
}));
|
|
746
|
+
}
|
|
747
|
+
setCrosshairX(e, t) {
|
|
748
|
+
this.setInteractionX(e, t);
|
|
749
|
+
}
|
|
750
|
+
onInteractionXChange(e) {
|
|
751
|
+
const t = (s) => {
|
|
752
|
+
e(s.x, s.source);
|
|
753
|
+
};
|
|
754
|
+
return this.on("crosshairMove", t), () => {
|
|
755
|
+
this.off("crosshairMove", t);
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
getZoomRange() {
|
|
759
|
+
return this.isDisposed ? null : this.cachedZoomRange;
|
|
760
|
+
}
|
|
761
|
+
setZoomRange(e, t) {
|
|
762
|
+
if (!this.isDisposed) {
|
|
763
|
+
if (e < 0 || e > 100 || t < 0 || t > 100)
|
|
764
|
+
throw new v(
|
|
765
|
+
`Invalid zoom range: [${e}, ${t}]. Values must be in [0, 100] (percent space).`,
|
|
766
|
+
"INVALID_ARGUMENT",
|
|
767
|
+
"setZoomRange",
|
|
768
|
+
this.chartId
|
|
769
|
+
);
|
|
770
|
+
if (e >= t)
|
|
771
|
+
throw new v(
|
|
772
|
+
`Invalid zoom range: start (${e}) must be less than end (${t}).`,
|
|
773
|
+
"INVALID_ARGUMENT",
|
|
774
|
+
"setZoomRange",
|
|
775
|
+
this.chartId
|
|
776
|
+
);
|
|
777
|
+
this.cachedZoomRange = { start: e, end: t }, this.sendMessage({
|
|
778
|
+
type: "setZoomRange",
|
|
779
|
+
chartId: this.chartId,
|
|
780
|
+
start: e,
|
|
781
|
+
end: t
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Gets the latest performance metrics from the worker.
|
|
787
|
+
* Returns cached metrics updated every frame.
|
|
788
|
+
*
|
|
789
|
+
* @returns Current performance metrics, or null if not available yet
|
|
790
|
+
*/
|
|
791
|
+
getPerformanceMetrics() {
|
|
792
|
+
return this.isDisposed ? null : this.cachedPerformanceMetrics;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Gets the performance capabilities of the worker environment.
|
|
796
|
+
* Indicates which performance features are supported.
|
|
797
|
+
*
|
|
798
|
+
* @returns Performance capabilities, or null if not initialized yet
|
|
799
|
+
*/
|
|
800
|
+
getPerformanceCapabilities() {
|
|
801
|
+
return this.isDisposed ? null : this.cachedPerformanceCapabilities;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Registers a callback to be notified of performance metric updates.
|
|
805
|
+
* Callback is invoked every frame with the latest metrics.
|
|
806
|
+
*
|
|
807
|
+
* @param callback - Function to call with updated metrics
|
|
808
|
+
* @returns Unsubscribe function to remove the callback
|
|
809
|
+
*/
|
|
810
|
+
onPerformanceUpdate(e) {
|
|
811
|
+
return this.isDisposed ? () => {
|
|
812
|
+
} : (this.performanceUpdateCallbacks.add(e), () => {
|
|
813
|
+
this.performanceUpdateCallbacks.delete(e);
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Enables or disables GPU timing for performance metrics.
|
|
818
|
+
* GPU timing requires the 'timestamp-query' WebGPU feature.
|
|
819
|
+
*
|
|
820
|
+
* @param enabled - Whether to enable GPU timing
|
|
821
|
+
*/
|
|
822
|
+
setGPUTiming(e) {
|
|
823
|
+
this.isDisposed || this.sendMessage({
|
|
824
|
+
type: "setGPUTiming",
|
|
825
|
+
chartId: this.chartId,
|
|
826
|
+
enabled: e
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
// =============================================================================
|
|
830
|
+
// Worker Communication
|
|
831
|
+
// =============================================================================
|
|
832
|
+
/**
|
|
833
|
+
* Sends a message to the worker without expecting a response.
|
|
834
|
+
*
|
|
835
|
+
* @param message - Message to send
|
|
836
|
+
* @param transfer - Optional transferable objects
|
|
837
|
+
*/
|
|
838
|
+
sendMessage(e, t) {
|
|
839
|
+
if (!this.isDisposed)
|
|
840
|
+
try {
|
|
841
|
+
t && t.length > 0 ? this.worker.postMessage(e, t) : this.worker.postMessage(e);
|
|
842
|
+
} catch (s) {
|
|
843
|
+
throw new v(
|
|
844
|
+
`Failed to send message to worker: ${s instanceof Error ? s.message : String(s)}`,
|
|
845
|
+
"COMMUNICATION_ERROR",
|
|
846
|
+
e.type,
|
|
847
|
+
this.chartId
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Sends a message to the worker and waits for a response.
|
|
853
|
+
*
|
|
854
|
+
* **Message Correlation**: Uses unique messageId to match request/response pairs.
|
|
855
|
+
* The worker MUST echo the messageId in its response for correlation to work.
|
|
856
|
+
*
|
|
857
|
+
* **Timeout Behavior**:
|
|
858
|
+
* - Default timeout: 30 seconds (configurable via WorkerConfig.messageTimeout)
|
|
859
|
+
* - On timeout: Promise rejects with TIMEOUT error and pending request is cleaned up
|
|
860
|
+
* - Prevents indefinite promise accumulation if worker hangs or message is lost
|
|
861
|
+
* - Timeout starts when message is sent (not when promise is created)
|
|
862
|
+
*
|
|
863
|
+
* **Error Handling**:
|
|
864
|
+
* - Send failure: Immediately rejects and cleans up timeout
|
|
865
|
+
* - Worker error: Rejects with error from ErrorMessage (matched by messageId)
|
|
866
|
+
* - Disposal: All pending requests rejected with DISPOSED error
|
|
867
|
+
*
|
|
868
|
+
* **Concurrency Safety**: Multiple concurrent requests are supported via Map-based tracking.
|
|
869
|
+
* Each request has a unique messageId, preventing response cross-contamination.
|
|
870
|
+
*
|
|
871
|
+
* @param message - Message to send (must have messageId)
|
|
872
|
+
* @param transfer - Optional transferable objects (e.g., OffscreenCanvas, ArrayBuffer)
|
|
873
|
+
* @returns Promise that resolves with the response or rejects on timeout/error
|
|
874
|
+
*/
|
|
875
|
+
sendMessageWithResponse(e, t) {
|
|
876
|
+
return new Promise((s, i) => {
|
|
877
|
+
const { messageId: n } = e, a = setTimeout(() => {
|
|
878
|
+
this.pendingRequests.delete(n), i(new v(
|
|
879
|
+
`Operation "${e.type}" timed out after ${this.messageTimeout}ms. Worker may be unresponsive or message was lost.`,
|
|
880
|
+
"TIMEOUT",
|
|
881
|
+
e.type,
|
|
882
|
+
this.chartId
|
|
883
|
+
));
|
|
884
|
+
}, this.messageTimeout);
|
|
885
|
+
this.pendingRequests.set(n, {
|
|
886
|
+
resolve: s,
|
|
887
|
+
reject: i,
|
|
888
|
+
timeout: a,
|
|
889
|
+
operation: e.type
|
|
890
|
+
});
|
|
891
|
+
try {
|
|
892
|
+
this.sendMessage(e, t);
|
|
893
|
+
} catch (r) {
|
|
894
|
+
clearTimeout(a), this.pendingRequests.delete(n), i(r);
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Handles incoming messages from the worker.
|
|
900
|
+
* Routes messages to appropriate handlers based on type.
|
|
901
|
+
*
|
|
902
|
+
* @param event - Message event from worker
|
|
903
|
+
*/
|
|
904
|
+
handleWorkerMessage(e) {
|
|
905
|
+
const t = e.data;
|
|
906
|
+
if (t.chartId === this.chartId)
|
|
907
|
+
switch (t.type) {
|
|
908
|
+
case "ready":
|
|
909
|
+
this.handleReadyMessage(t);
|
|
910
|
+
break;
|
|
911
|
+
case "rendered":
|
|
912
|
+
break;
|
|
913
|
+
case "performance-update":
|
|
914
|
+
this.handlePerformanceUpdateMessage(t);
|
|
915
|
+
break;
|
|
916
|
+
case "tooltipUpdate":
|
|
917
|
+
this.handleTooltipUpdateMessage(t);
|
|
918
|
+
break;
|
|
919
|
+
case "legendUpdate":
|
|
920
|
+
this.handleLegendUpdateMessage(t);
|
|
921
|
+
break;
|
|
922
|
+
case "axisLabelsUpdate":
|
|
923
|
+
this.handleAxisLabelsUpdateMessage(t);
|
|
924
|
+
break;
|
|
925
|
+
case "hoverChange":
|
|
926
|
+
this.handleHoverChangeMessage(t);
|
|
927
|
+
break;
|
|
928
|
+
case "click":
|
|
929
|
+
this.handleClickMessage(t);
|
|
930
|
+
break;
|
|
931
|
+
case "crosshairMove":
|
|
932
|
+
this.handleCrosshairMoveMessage(t);
|
|
933
|
+
break;
|
|
934
|
+
case "zoomChange":
|
|
935
|
+
this.handleZoomChangeMessage(t);
|
|
936
|
+
break;
|
|
937
|
+
case "deviceLost":
|
|
938
|
+
this.handleDeviceLostMessage(t);
|
|
939
|
+
break;
|
|
940
|
+
case "disposed":
|
|
941
|
+
break;
|
|
942
|
+
case "error":
|
|
943
|
+
this.handleErrorMessage(t);
|
|
944
|
+
break;
|
|
945
|
+
default:
|
|
946
|
+
console.warn("ChartGPUWorkerProxy: Unknown message type:", t.type);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Handles ready message from worker.
|
|
951
|
+
* Resolves the pending init request and caches performance capabilities.
|
|
952
|
+
*/
|
|
953
|
+
handleReadyMessage(e) {
|
|
954
|
+
if (this.isInitialized = !0, this.cachedPerformanceCapabilities = e.performanceCapabilities, e.initialZoomRange && (this.cachedZoomRange = { start: e.initialZoomRange.start, end: e.initialZoomRange.end }, this.zoomState)) {
|
|
955
|
+
const s = this.zoomState.getRange();
|
|
956
|
+
if (s.start === 0 && s.end === 100 && (e.initialZoomRange.start !== 0 || e.initialZoomRange.end !== 100)) {
|
|
957
|
+
this.isProcessingWorkerZoomUpdate = !0;
|
|
958
|
+
try {
|
|
959
|
+
this.zoomState.setRange(e.initialZoomRange.start, e.initialZoomRange.end);
|
|
960
|
+
} finally {
|
|
961
|
+
this.isProcessingWorkerZoomUpdate = !1;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
const t = this.pendingRequests.get(e.messageId);
|
|
966
|
+
t && (clearTimeout(t.timeout), this.pendingRequests.delete(e.messageId), t.resolve(e));
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Handles hover change messages from worker.
|
|
970
|
+
* Emits mouseover/mouseout events to registered listeners.
|
|
971
|
+
*/
|
|
972
|
+
handleHoverChangeMessage(e) {
|
|
973
|
+
if (e.payload) {
|
|
974
|
+
const t = {
|
|
975
|
+
seriesIndex: e.payload.seriesIndex,
|
|
976
|
+
dataIndex: e.payload.dataIndex,
|
|
977
|
+
value: e.payload.value,
|
|
978
|
+
seriesName: null,
|
|
979
|
+
// Worker doesn't send series name
|
|
980
|
+
event: this.createSyntheticPointerEvent(e.payload.x, e.payload.y)
|
|
981
|
+
};
|
|
982
|
+
this.emit("mouseover", t);
|
|
983
|
+
} else {
|
|
984
|
+
const t = {
|
|
985
|
+
seriesIndex: null,
|
|
986
|
+
dataIndex: null,
|
|
987
|
+
value: null,
|
|
988
|
+
seriesName: null,
|
|
989
|
+
event: this.createSyntheticPointerEvent(0, 0)
|
|
990
|
+
};
|
|
991
|
+
this.emit("mouseout", t);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Handles click messages from worker.
|
|
996
|
+
* Emits click events to registered listeners.
|
|
997
|
+
*/
|
|
998
|
+
handleClickMessage(e) {
|
|
999
|
+
const t = {
|
|
1000
|
+
seriesIndex: e.payload.seriesIndex,
|
|
1001
|
+
dataIndex: e.payload.dataIndex,
|
|
1002
|
+
value: e.payload.value,
|
|
1003
|
+
seriesName: null,
|
|
1004
|
+
// Worker doesn't send series name
|
|
1005
|
+
event: this.createSyntheticPointerEvent(e.payload.x, e.payload.y)
|
|
1006
|
+
};
|
|
1007
|
+
this.emit("click", t);
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Handles crosshair move messages from worker.
|
|
1011
|
+
* Updates cached interaction X and emits crosshairMove events.
|
|
1012
|
+
*/
|
|
1013
|
+
handleCrosshairMoveMessage(e) {
|
|
1014
|
+
this.cachedInteractionX = e.x;
|
|
1015
|
+
const t = {
|
|
1016
|
+
x: e.x,
|
|
1017
|
+
source: e.source
|
|
1018
|
+
};
|
|
1019
|
+
this.emit("crosshairMove", t);
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Handles zoom change messages from worker.
|
|
1023
|
+
* Updates cached zoom range and zoom state with echo loop prevention.
|
|
1024
|
+
*
|
|
1025
|
+
* CRITICAL: Echo suppression strategy
|
|
1026
|
+
* - Sets isProcessingWorkerZoomUpdate flag before calling setRange
|
|
1027
|
+
* - The onChange callback checks this flag and skips sending message back to worker
|
|
1028
|
+
* - This prevents zoom changes originated in the worker from echoing back
|
|
1029
|
+
* - UI-originated changes (slider drag) still propagate normally to worker
|
|
1030
|
+
*/
|
|
1031
|
+
handleZoomChangeMessage(e) {
|
|
1032
|
+
if (this.cachedZoomRange = { start: e.start, end: e.end }, this.zoomState) {
|
|
1033
|
+
const t = this.zoomState.getRange();
|
|
1034
|
+
if (t.start !== e.start || t.end !== e.end) {
|
|
1035
|
+
this.isProcessingWorkerZoomUpdate = !0;
|
|
1036
|
+
try {
|
|
1037
|
+
this.zoomState.setRange(e.start, e.end);
|
|
1038
|
+
} finally {
|
|
1039
|
+
this.isProcessingWorkerZoomUpdate = !1;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Handles device lost messages from worker.
|
|
1046
|
+
* Marks chart as disposed and cleans up resources.
|
|
1047
|
+
*/
|
|
1048
|
+
handleDeviceLostMessage(e) {
|
|
1049
|
+
console.error(
|
|
1050
|
+
`ChartGPU: WebGPU device lost for chart "${this.chartId}".`,
|
|
1051
|
+
`Reason: ${e.reason}`,
|
|
1052
|
+
e.message ? `Message: ${e.message}` : ""
|
|
1053
|
+
), this.dispose();
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Handles error messages from worker.
|
|
1057
|
+
* Rejects pending requests or logs errors.
|
|
1058
|
+
*/
|
|
1059
|
+
handleErrorMessage(e) {
|
|
1060
|
+
const t = new v(
|
|
1061
|
+
e.message,
|
|
1062
|
+
e.code,
|
|
1063
|
+
e.operation,
|
|
1064
|
+
this.chartId
|
|
1065
|
+
);
|
|
1066
|
+
if (e.messageId) {
|
|
1067
|
+
const s = this.pendingRequests.get(e.messageId);
|
|
1068
|
+
if (s) {
|
|
1069
|
+
clearTimeout(s.timeout), this.pendingRequests.delete(e.messageId), s.reject(t);
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
console.error("ChartGPUWorkerProxy: Worker error:", t);
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Handles tooltip update messages from worker.
|
|
1077
|
+
* Batches updates via RAF to prevent layout thrashing.
|
|
1078
|
+
*/
|
|
1079
|
+
handleTooltipUpdateMessage(e) {
|
|
1080
|
+
this.pendingOverlayUpdates.tooltip = e, this.scheduleOverlayUpdates();
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Handles legend update messages from worker.
|
|
1084
|
+
* Batches updates via RAF to prevent layout thrashing.
|
|
1085
|
+
*/
|
|
1086
|
+
handleLegendUpdateMessage(e) {
|
|
1087
|
+
this.pendingOverlayUpdates.legend = e, this.scheduleOverlayUpdates();
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Handles axis labels update messages from worker.
|
|
1091
|
+
* Batches updates via RAF to prevent layout thrashing.
|
|
1092
|
+
*/
|
|
1093
|
+
handleAxisLabelsUpdateMessage(e) {
|
|
1094
|
+
this.pendingOverlayUpdates.axisLabels = e, this.scheduleOverlayUpdates();
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Handles performance update messages from worker.
|
|
1098
|
+
* Updates cached metrics and notifies subscribers.
|
|
1099
|
+
*/
|
|
1100
|
+
handlePerformanceUpdateMessage(e) {
|
|
1101
|
+
this.cachedPerformanceMetrics = e.metrics;
|
|
1102
|
+
for (const t of this.performanceUpdateCallbacks)
|
|
1103
|
+
try {
|
|
1104
|
+
t(e.metrics);
|
|
1105
|
+
} catch (s) {
|
|
1106
|
+
console.error("Error in performance update callback:", s);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Emits an event to all registered listeners.
|
|
1111
|
+
*
|
|
1112
|
+
* @param eventName - Event name
|
|
1113
|
+
* @param payload - Event payload
|
|
1114
|
+
*/
|
|
1115
|
+
emit(e, t) {
|
|
1116
|
+
const s = this.listeners.get(e);
|
|
1117
|
+
if (s)
|
|
1118
|
+
for (const i of s)
|
|
1119
|
+
try {
|
|
1120
|
+
i(t);
|
|
1121
|
+
} catch (n) {
|
|
1122
|
+
console.error(`Error in ${e} event handler:`, n);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Creates a synthetic PointerEvent for event payloads.
|
|
1127
|
+
* Worker can't transfer real PointerEvents, so we create a minimal synthetic one.
|
|
1128
|
+
*
|
|
1129
|
+
* @param x - Canvas-local CSS pixel x coordinate
|
|
1130
|
+
* @param y - Canvas-local CSS pixel y coordinate
|
|
1131
|
+
* @returns Synthetic PointerEvent
|
|
1132
|
+
*/
|
|
1133
|
+
createSyntheticPointerEvent(e, t) {
|
|
1134
|
+
const s = this.container.querySelector("canvas"), i = (s == null ? void 0 : s.getBoundingClientRect()) || { left: 0, top: 0 };
|
|
1135
|
+
return new PointerEvent("pointermove", {
|
|
1136
|
+
bubbles: !1,
|
|
1137
|
+
cancelable: !1,
|
|
1138
|
+
clientX: i.left + e,
|
|
1139
|
+
clientY: i.top + t,
|
|
1140
|
+
pointerId: -1,
|
|
1141
|
+
// Synthetic event marker
|
|
1142
|
+
pointerType: "mouse",
|
|
1143
|
+
isPrimary: !0
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
const ie = 3e4;
|
|
1148
|
+
async function ae(f, e, t) {
|
|
1149
|
+
if (!f || !(f instanceof HTMLElement))
|
|
1150
|
+
throw new v(
|
|
1151
|
+
"Invalid container: must be an HTMLElement",
|
|
1152
|
+
"INVALID_ARGUMENT",
|
|
1153
|
+
"createChartInWorker",
|
|
1154
|
+
"unknown"
|
|
1155
|
+
);
|
|
1156
|
+
let s = null, i = !1;
|
|
1157
|
+
const n = `chart_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
1158
|
+
try {
|
|
1159
|
+
if (t instanceof Worker)
|
|
1160
|
+
s = t, i = !1;
|
|
1161
|
+
else if (typeof t == "string" || t instanceof URL)
|
|
1162
|
+
try {
|
|
1163
|
+
s = new Worker(t, { type: "module" }), i = !0;
|
|
1164
|
+
} catch (r) {
|
|
1165
|
+
throw new v(
|
|
1166
|
+
`Failed to create worker from URL: ${r instanceof Error ? r.message : String(r)}`,
|
|
1167
|
+
"WEBGPU_INIT_FAILED",
|
|
1168
|
+
"createChartInWorker",
|
|
1169
|
+
n
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
else
|
|
1173
|
+
try {
|
|
1174
|
+
s = new Worker(new URL(
|
|
1175
|
+
/* @vite-ignore */
|
|
1176
|
+
"/assets/worker-entry-Wg897auv.js",
|
|
1177
|
+
import.meta.url
|
|
1178
|
+
), { type: "module" }), i = !0;
|
|
1179
|
+
} catch (r) {
|
|
1180
|
+
throw new v(
|
|
1181
|
+
`Failed to create built-in worker: ${r instanceof Error ? r.message : String(r)}`,
|
|
1182
|
+
"WEBGPU_INIT_FAILED",
|
|
1183
|
+
"createChartInWorker",
|
|
1184
|
+
n
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
const a = new se(
|
|
1188
|
+
{
|
|
1189
|
+
worker: s,
|
|
1190
|
+
chartId: n,
|
|
1191
|
+
messageTimeout: ie
|
|
1192
|
+
},
|
|
1193
|
+
f,
|
|
1194
|
+
e
|
|
1195
|
+
);
|
|
1196
|
+
try {
|
|
1197
|
+
await a.init();
|
|
1198
|
+
} catch (r) {
|
|
1199
|
+
throw a.dispose(), r;
|
|
1200
|
+
}
|
|
1201
|
+
return a;
|
|
1202
|
+
} catch (a) {
|
|
1203
|
+
if (s && i)
|
|
1204
|
+
try {
|
|
1205
|
+
s.terminate();
|
|
1206
|
+
} catch {
|
|
1207
|
+
}
|
|
1208
|
+
throw a instanceof v ? a : new v(
|
|
1209
|
+
`Failed to create worker chart: ${a instanceof Error ? a.message : String(a)}`,
|
|
1210
|
+
"UNKNOWN",
|
|
1211
|
+
"createChartInWorker",
|
|
1212
|
+
n
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
export {
|
|
1217
|
+
se as C,
|
|
1218
|
+
j as O,
|
|
1219
|
+
V as X,
|
|
1220
|
+
ae as a,
|
|
1221
|
+
v as b,
|
|
1222
|
+
Q as c
|
|
1223
|
+
};
|
|
1224
|
+
//# sourceMappingURL=createChartInWorker-C4fEeJL8.js.map
|