velo-plot 1.11.1 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -2
- package/dist/{index.core-CYu3tydL.js → ChartCore-BimVvUEg.js} +1936 -1588
- package/dist/ChartCore-BimVvUEg.js.map +1 -0
- package/dist/axisFormat-B7o_uIEA.js +127 -0
- package/dist/axisFormat-B7o_uIEA.js.map +1 -0
- package/dist/core/OverlayRenderer.d.ts +1 -2
- package/dist/core/chart/ChartCore.d.ts +18 -1
- package/dist/core/chart/ChartRenderLoop.d.ts +4 -0
- package/dist/core/chart/ChartScaling.d.ts +11 -0
- package/dist/core/chart/NavigationUtils.d.ts +12 -0
- package/dist/core/chart/exporter/SVGExporter.d.ts +7 -2
- package/dist/core/chart/types.d.ts +13 -1
- package/dist/core/format/axisFormat.d.ts +16 -0
- package/dist/core/indicator/buildIndicatorPane.d.ts +22 -0
- package/dist/core/indicator/buildIndicatorSeries.d.ts +14 -0
- package/dist/core/indicator/index.d.ts +3 -0
- package/dist/core/indicator/types.d.ts +74 -0
- package/dist/core/render/pixelSnap.d.ts +8 -0
- package/dist/core/series/SeriesBounds.d.ts +1 -1
- package/dist/core/stacked/createStackedChart.d.ts +3 -0
- package/dist/core/stacked/index.d.ts +6 -0
- package/dist/core/stacked/paneAxis.d.ts +20 -0
- package/dist/core/stacked/paneResize.d.ts +29 -0
- package/dist/core/stacked/stackExport.d.ts +18 -0
- package/dist/core/stacked/types.d.ts +120 -0
- package/dist/core/sync/index.d.ts +25 -70
- package/dist/createStackedChart-CjsKcOvX.js +1088 -0
- package/dist/createStackedChart-CjsKcOvX.js.map +1 -0
- package/dist/index-CUGS98p4.js +277 -0
- package/dist/index-CUGS98p4.js.map +1 -0
- package/dist/index-ChgIdk3N.js +229 -0
- package/dist/index-ChgIdk3N.js.map +1 -0
- package/dist/{index-D8ifudJH.js → index-DjeWClO9.js} +601 -561
- package/dist/index-DjeWClO9.js.map +1 -0
- package/dist/index.core-C_-CFftD.js +167 -0
- package/dist/index.core-C_-CFftD.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/math-Ddm2EZjj.js +85 -0
- package/dist/math-Ddm2EZjj.js.map +1 -0
- package/dist/plugins/analysis.js +132 -130
- package/dist/plugins/analysis.js.map +1 -1
- package/dist/plugins/anomaly-detection.d.ts +1 -0
- package/dist/plugins/anomaly-detection.js +221 -0
- package/dist/plugins/anomaly-detection.js.map +1 -0
- package/dist/plugins/broken-axis.d.ts +3 -0
- package/dist/plugins/broken-axis.js +262 -0
- package/dist/plugins/broken-axis.js.map +1 -0
- package/dist/plugins/caching.d.ts +3 -0
- package/dist/plugins/caching.js +182 -0
- package/dist/plugins/caching.js.map +1 -0
- package/dist/plugins/data-transform.d.ts +3 -0
- package/dist/plugins/data-transform.js +146 -0
- package/dist/plugins/data-transform.js.map +1 -0
- package/dist/plugins/debug.js +12 -11
- package/dist/plugins/debug.js.map +1 -1
- package/dist/plugins/forecasting.d.ts +1 -0
- package/dist/plugins/forecasting.js +236 -0
- package/dist/plugins/forecasting.js.map +1 -0
- package/dist/plugins/latex.d.ts +1 -0
- package/dist/plugins/latex.js +454 -0
- package/dist/plugins/latex.js.map +1 -0
- package/dist/plugins/lazy-load.d.ts +3 -0
- package/dist/plugins/lazy-load.js +189 -0
- package/dist/plugins/lazy-load.js.map +1 -0
- package/dist/plugins/ml-integration.d.ts +3 -0
- package/dist/plugins/ml-integration.js +355 -0
- package/dist/plugins/ml-integration.js.map +1 -0
- package/dist/plugins/offscreen.d.ts +3 -0
- package/dist/plugins/offscreen.js +169 -0
- package/dist/plugins/offscreen.js.map +1 -0
- package/dist/plugins/pattern-recognition.d.ts +3 -0
- package/dist/plugins/pattern-recognition.js +690 -0
- package/dist/plugins/pattern-recognition.js.map +1 -0
- package/dist/plugins/radar.d.ts +3 -0
- package/dist/plugins/radar.js +103 -0
- package/dist/plugins/radar.js.map +1 -0
- package/dist/plugins/regression.d.ts +3 -0
- package/dist/plugins/regression.js +634 -0
- package/dist/plugins/regression.js.map +1 -0
- package/dist/plugins/roi.d.ts +1 -0
- package/dist/plugins/roi.js +223 -0
- package/dist/plugins/roi.js.map +1 -0
- package/dist/plugins/snapshot/types.d.ts +1 -1
- package/dist/plugins/snapshot.d.ts +3 -0
- package/dist/plugins/snapshot.js +90 -0
- package/dist/plugins/snapshot.js.map +1 -0
- package/dist/plugins/sync/index.d.ts +2 -1
- package/dist/plugins/sync.js +12 -244
- package/dist/plugins/sync.js.map +1 -1
- package/dist/plugins/tools/tooltip/TooltipManager.d.ts +9 -1
- package/dist/plugins/tools/tooltip/format.d.ts +7 -0
- package/dist/plugins/tools/tooltip/types.d.ts +6 -8
- package/dist/plugins/tools.js +1 -1
- package/dist/plugins/video-recorder.d.ts +3 -0
- package/dist/plugins/video-recorder.js +104 -0
- package/dist/plugins/video-recorder.js.map +1 -0
- package/dist/plugins/virtualization.d.ts +3 -0
- package/dist/plugins/virtualization.js +6 -0
- package/dist/plugins/virtualization.js.map +1 -0
- package/dist/react/index.d.ts +2 -1
- package/dist/react/useStackedPlot.d.ts +17 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +31 -0
- package/dist/react.js.map +1 -0
- package/dist/types.d.ts +21 -1
- package/dist/utils-BK5UUXxj.js +172 -0
- package/dist/utils-BK5UUXxj.js.map +1 -0
- package/dist/velo-plot.full.js +1000 -5576
- package/dist/velo-plot.full.js.map +1 -1
- package/dist/velo-plot.js +23 -22
- package/dist/velo-plot.js.map +1 -1
- package/package.json +17 -3
- package/dist/EventEmitter-DAbs2K1C.js +0 -60
- package/dist/EventEmitter-DAbs2K1C.js.map +0 -1
- package/dist/index-D8ifudJH.js.map +0 -1
- package/dist/index.core-CYu3tydL.js.map +0 -1
- package/dist/utils-Dbro9-qM.js +0 -254
- package/dist/utils-Dbro9-qM.js.map +0 -1
package/dist/plugins/sync.js
CHANGED
|
@@ -1,250 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var a = (o, t, s) => l(o, typeof t != "symbol" ? t + "" : t, s);
|
|
4
|
-
class c {
|
|
5
|
-
constructor(t) {
|
|
6
|
-
a(this, "charts", /* @__PURE__ */ new Map());
|
|
7
|
-
a(this, "options");
|
|
8
|
-
a(this, "eventHandlers", /* @__PURE__ */ new Map());
|
|
9
|
-
a(this, "isUpdating", !1);
|
|
10
|
-
a(this, "debounceTimers", /* @__PURE__ */ new Map());
|
|
11
|
-
this.options = {
|
|
12
|
-
axis: "x",
|
|
13
|
-
syncCursor: !0,
|
|
14
|
-
syncSelection: !1,
|
|
15
|
-
syncZoom: !0,
|
|
16
|
-
syncPan: !0,
|
|
17
|
-
debounce: 0,
|
|
18
|
-
bidirectional: !0,
|
|
19
|
-
...t
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Add a chart to the group
|
|
24
|
-
*/
|
|
25
|
-
add(t) {
|
|
26
|
-
const s = t.getId();
|
|
27
|
-
return this.charts.has(s) ? (console.warn(`[ChartGroup] Chart ${s} is already in the group`), this) : (this.charts.set(s, t), this.attachEventHandlers(t), this);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Add multiple charts at once
|
|
31
|
-
*/
|
|
32
|
-
addAll(...t) {
|
|
33
|
-
for (const s of t)
|
|
34
|
-
this.add(s);
|
|
35
|
-
return this;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Remove a chart from the group
|
|
39
|
-
*/
|
|
40
|
-
remove(t) {
|
|
41
|
-
const s = t.getId();
|
|
42
|
-
return this.charts.has(s) ? (this.detachEventHandlers(t), this.charts.delete(s), this) : this;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Get all charts in the group
|
|
46
|
-
*/
|
|
47
|
-
getCharts() {
|
|
48
|
-
return Array.from(this.charts.values());
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Get chart count
|
|
52
|
-
*/
|
|
53
|
-
size() {
|
|
54
|
-
return this.charts.size;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Check if a chart is in the group
|
|
58
|
-
*/
|
|
59
|
-
has(t) {
|
|
60
|
-
return this.charts.has(t.getId());
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Set synchronization axis
|
|
64
|
-
*/
|
|
65
|
-
syncAxis(t) {
|
|
66
|
-
return this.options.axis = t, this;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Enable/disable cursor synchronization
|
|
70
|
-
*/
|
|
71
|
-
syncCursor(t) {
|
|
72
|
-
return this.options.syncCursor = t, this;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Enable/disable selection synchronization
|
|
76
|
-
*/
|
|
77
|
-
syncSelection(t) {
|
|
78
|
-
return this.options.syncSelection = t, this;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Synchronize all charts to a specific view
|
|
82
|
-
*/
|
|
83
|
-
syncTo(t, s) {
|
|
84
|
-
this.propagateZoom(s || "", t);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Reset all charts to auto-scale
|
|
88
|
-
*/
|
|
89
|
-
resetAll() {
|
|
90
|
-
for (const t of this.charts.values())
|
|
91
|
-
t.zoom({ x: void 0, y: void 0 });
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Clear all selections in the group
|
|
95
|
-
*/
|
|
96
|
-
clearAllSelections() {
|
|
97
|
-
var t;
|
|
98
|
-
for (const s of this.charts.values())
|
|
99
|
-
(t = s.clearSelection) == null || t.call(s);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Destroy the group and cleanup
|
|
103
|
-
*/
|
|
104
|
-
destroy() {
|
|
105
|
-
for (const t of this.charts.values())
|
|
106
|
-
this.detachEventHandlers(t);
|
|
107
|
-
this.charts.clear(), this.eventHandlers.clear();
|
|
108
|
-
for (const t of this.debounceTimers.values())
|
|
109
|
-
clearTimeout(t);
|
|
110
|
-
this.debounceTimers.clear();
|
|
111
|
-
}
|
|
112
|
-
// ============================================
|
|
113
|
-
// Private Methods
|
|
114
|
-
// ============================================
|
|
115
|
-
attachEventHandlers(t) {
|
|
116
|
-
const s = t.getId(), i = /* @__PURE__ */ new Map();
|
|
117
|
-
if (this.options.syncZoom) {
|
|
118
|
-
const n = (...e) => {
|
|
119
|
-
const r = e[0];
|
|
120
|
-
this.handleZoom(s, r);
|
|
121
|
-
};
|
|
122
|
-
t.on("zoom", n), i.set("zoom", n);
|
|
123
|
-
}
|
|
124
|
-
if (this.options.syncPan) {
|
|
125
|
-
const n = (...e) => {
|
|
126
|
-
const r = e[0];
|
|
127
|
-
this.handlePan(s, r);
|
|
128
|
-
};
|
|
129
|
-
t.on("pan", n), i.set("pan", n);
|
|
130
|
-
}
|
|
131
|
-
if (this.options.syncCursor) {
|
|
132
|
-
const n = (...e) => {
|
|
133
|
-
const r = e[0];
|
|
134
|
-
this.handleCursor(s, r);
|
|
135
|
-
};
|
|
136
|
-
t.on("hover", n), i.set("hover", n);
|
|
137
|
-
}
|
|
138
|
-
if (this.options.syncSelection) {
|
|
139
|
-
const n = (...e) => {
|
|
140
|
-
const r = e[0];
|
|
141
|
-
this.handleSelection(s, r);
|
|
142
|
-
};
|
|
143
|
-
t.on("selectionChange", n), i.set("selectionChange", n);
|
|
144
|
-
}
|
|
145
|
-
this.eventHandlers.set(s, i);
|
|
146
|
-
}
|
|
147
|
-
detachEventHandlers(t) {
|
|
148
|
-
const s = t.getId(), i = this.eventHandlers.get(s);
|
|
149
|
-
if (i) {
|
|
150
|
-
for (const [n, e] of i.entries())
|
|
151
|
-
t.off(n, e);
|
|
152
|
-
this.eventHandlers.delete(s);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
handleZoom(t, s) {
|
|
156
|
-
if (this.isUpdating) return;
|
|
157
|
-
const i = {};
|
|
158
|
-
(this.options.axis === "x" || this.options.axis === "xy") && (i.xMin = s.x[0], i.xMax = s.x[1]), (this.options.axis === "y" || this.options.axis === "xy") && (i.yMin = s.y[0], i.yMax = s.y[1]), this.debounceAction(`zoom-${t}`, () => {
|
|
159
|
-
this.propagateZoom(t, i);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
handlePan(t, s) {
|
|
163
|
-
if (this.isUpdating) return;
|
|
164
|
-
const i = this.options.axis === "x" || this.options.axis === "xy" ? s.deltaX : 0, n = this.options.axis === "y" || this.options.axis === "xy" ? s.deltaY : 0;
|
|
165
|
-
i === 0 && n === 0 || this.debounceAction(`pan-${t}`, () => {
|
|
166
|
-
this.propagatePan(t, i, n);
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
handleCursor(t, s) {
|
|
170
|
-
var i, n;
|
|
171
|
-
if (!this.isUpdating)
|
|
172
|
-
for (const [e, r] of this.charts.entries())
|
|
173
|
-
e !== t && (s != null && s.point ? (i = r.setExternalCursor) == null || i.call(r, s.point.x, s.point.y) : (n = r.clearExternalCursor) == null || n.call(r));
|
|
174
|
-
}
|
|
175
|
-
handleSelection(t, s) {
|
|
176
|
-
if (!(this.isUpdating || !this.options.syncSelection))
|
|
177
|
-
for (const [i, n] of this.charts.entries())
|
|
178
|
-
;
|
|
179
|
-
}
|
|
180
|
-
propagateZoom(t, s) {
|
|
181
|
-
if (!this.isUpdating) {
|
|
182
|
-
this.isUpdating = !0;
|
|
183
|
-
try {
|
|
184
|
-
for (const [i, n] of this.charts.entries()) {
|
|
185
|
-
if (i === t && !this.options.bidirectional || i === t) continue;
|
|
186
|
-
const e = {
|
|
187
|
-
animate: !1
|
|
188
|
-
};
|
|
189
|
-
s.xMin !== void 0 && s.xMax !== void 0 && (e.x = [s.xMin, s.xMax]), s.yMin !== void 0 && s.yMax !== void 0 && (e.y = [s.yMin, s.yMax]), n.zoom(e);
|
|
190
|
-
}
|
|
191
|
-
} finally {
|
|
192
|
-
this.isUpdating = !1;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
propagatePan(t, s, i) {
|
|
197
|
-
if (!this.isUpdating) {
|
|
198
|
-
this.isUpdating = !0;
|
|
199
|
-
try {
|
|
200
|
-
for (const [n, e] of this.charts.entries())
|
|
201
|
-
n !== t && e.pan(s, i);
|
|
202
|
-
} finally {
|
|
203
|
-
this.isUpdating = !1;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
debounceAction(t, s) {
|
|
208
|
-
if (this.options.debounce <= 0) {
|
|
209
|
-
s();
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
const i = this.debounceTimers.get(t);
|
|
213
|
-
i && clearTimeout(i);
|
|
214
|
-
const n = window.setTimeout(() => {
|
|
215
|
-
this.debounceTimers.delete(t), s();
|
|
216
|
-
}, this.options.debounce);
|
|
217
|
-
this.debounceTimers.set(t, n);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
function d(o, t) {
|
|
221
|
-
const s = new c(t);
|
|
222
|
-
return s.addAll(...o), s;
|
|
223
|
-
}
|
|
224
|
-
function p(o, t, s) {
|
|
225
|
-
return d([o, t], s);
|
|
226
|
-
}
|
|
227
|
-
function y(o, t, s = "x") {
|
|
228
|
-
return new c({
|
|
229
|
-
axis: s,
|
|
230
|
-
bidirectional: !1,
|
|
231
|
-
syncCursor: !0,
|
|
232
|
-
syncZoom: !0,
|
|
233
|
-
syncPan: !0
|
|
234
|
-
}).addAll(o, t);
|
|
235
|
-
}
|
|
236
|
-
const u = {
|
|
1
|
+
import { C as c, c as s, a as i, l } from "../index-CUGS98p4.js";
|
|
2
|
+
const n = {
|
|
237
3
|
name: "velo-plot-sync",
|
|
238
4
|
version: "1.0.0",
|
|
239
5
|
description: "Multi-chart synchronization for velo-plot",
|
|
240
6
|
provides: ["interaction"],
|
|
241
7
|
tags: ["sync", "multi-chart", "coordination"]
|
|
242
8
|
};
|
|
243
|
-
function
|
|
9
|
+
function r(o = {}) {
|
|
244
10
|
return {
|
|
245
|
-
manifest:
|
|
11
|
+
manifest: n,
|
|
246
12
|
onInit(t) {
|
|
247
|
-
|
|
13
|
+
console.warn(
|
|
14
|
+
"[PluginSync] Deprecated: use ChartGroup / createChartGroup from the core sync module instead."
|
|
15
|
+
);
|
|
248
16
|
},
|
|
249
17
|
onDestroy(t) {
|
|
250
18
|
}
|
|
@@ -252,10 +20,10 @@ function x(o = {}) {
|
|
|
252
20
|
}
|
|
253
21
|
export {
|
|
254
22
|
c as ChartGroup,
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
23
|
+
r as PluginSync,
|
|
24
|
+
s as createChartGroup,
|
|
25
|
+
i as createMasterSlave,
|
|
26
|
+
r as default,
|
|
27
|
+
l as linkCharts
|
|
260
28
|
};
|
|
261
29
|
//# sourceMappingURL=sync.js.map
|
package/dist/plugins/sync.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sources":["../../src/core/sync/index.ts","../../src/plugins/sync/index.ts"],"sourcesContent":["/**\n * Sci Plot - Chart Synchronization Module\n * \n * Provides synchronization between multiple charts:\n * - Synchronized zoom/pan (X, Y, or both)\n * - Shared crosshair cursor\n * - Coordinated selection\n * - Event propagation between linked charts\n * \n * @module sync\n */\n\nimport type { Bounds, Range } from \"../../types\";\n\n// ============================================\n// Types\n// ============================================\n\nexport type SyncAxis = 'x' | 'y' | 'xy' | 'none';\n\nexport interface SyncOptions {\n /** Synchronize axis (default: 'x') */\n axis?: SyncAxis;\n /** Synchronize cursor position (default: true) */\n syncCursor?: boolean;\n /** Synchronize selection state (default: false) */\n syncSelection?: boolean;\n /** Synchronize zoom level (default: true) */\n syncZoom?: boolean;\n /** Synchronize pan (default: true) */\n syncPan?: boolean;\n /** Debounce time for sync events in ms (default: 0) */\n debounce?: number;\n /** Enable bidirectional sync (default: true) */\n bidirectional?: boolean;\n}\n\nexport interface ChartLike {\n /** Unique identifier for the chart */\n getId(): string;\n /** Get current view bounds */\n getViewBounds(): Bounds;\n /** Set view bounds (zoom) */\n zoom(options: { x?: Range; y?: Range; animate?: boolean }): void;\n /** Pan the chart */\n pan(dx: number, dy: number): void;\n /** Get cursor position */\n getCursorPosition?(): { x: number; y: number } | null;\n /** Set external cursor position */\n setExternalCursor?(x: number, y: number): void;\n /** Clear external cursor */\n clearExternalCursor?(): void;\n /** Get selected points */\n getSelectedPoints?(): { seriesId: string; indices: number[] }[];\n /** Set selection */\n selectPoints?(points: { seriesId: string; indices: number[] }[]): void;\n /** Clear selection */\n clearSelection?(): void;\n /** Subscribe to events */\n on(event: string, callback: (...args: unknown[]) => void): void;\n /** Unsubscribe from events */\n off(event: string, callback: (...args: unknown[]) => void): void;\n}\n\nexport interface SyncEvent {\n /** Source chart ID */\n sourceId: string;\n /** Event type */\n type: 'zoom' | 'pan' | 'cursor' | 'selection' | 'bounds';\n /** Event data */\n data: unknown;\n}\n\n// ============================================\n// Chart Group Implementation\n// ============================================\n\nexport class ChartGroup {\n private charts: Map<string, ChartLike> = new Map();\n private options: Required<SyncOptions>;\n private eventHandlers: Map<string, Map<string, (...args: unknown[]) => void>> = new Map();\n private isUpdating: boolean = false;\n private debounceTimers: Map<string, number> = new Map();\n\n constructor(options?: SyncOptions) {\n this.options = {\n axis: 'x',\n syncCursor: true,\n syncSelection: false,\n syncZoom: true,\n syncPan: true,\n debounce: 0,\n bidirectional: true,\n ...options,\n };\n }\n\n /**\n * Add a chart to the group\n */\n add(chart: ChartLike): this {\n const chartId = chart.getId();\n \n if (this.charts.has(chartId)) {\n console.warn(`[ChartGroup] Chart ${chartId} is already in the group`);\n return this;\n }\n\n this.charts.set(chartId, chart);\n this.attachEventHandlers(chart);\n \n return this;\n }\n\n /**\n * Add multiple charts at once\n */\n addAll(...charts: ChartLike[]): this {\n for (const chart of charts) {\n this.add(chart);\n }\n return this;\n }\n\n /**\n * Remove a chart from the group\n */\n remove(chart: ChartLike): this {\n const chartId = chart.getId();\n \n if (!this.charts.has(chartId)) {\n return this;\n }\n\n this.detachEventHandlers(chart);\n this.charts.delete(chartId);\n \n return this;\n }\n\n /**\n * Get all charts in the group\n */\n getCharts(): ChartLike[] {\n return Array.from(this.charts.values());\n }\n\n /**\n * Get chart count\n */\n size(): number {\n return this.charts.size;\n }\n\n /**\n * Check if a chart is in the group\n */\n has(chart: ChartLike): boolean {\n return this.charts.has(chart.getId());\n }\n\n /**\n * Set synchronization axis\n */\n syncAxis(axis: SyncAxis): this {\n this.options.axis = axis;\n return this;\n }\n\n /**\n * Enable/disable cursor synchronization\n */\n syncCursor(enabled: boolean): this {\n this.options.syncCursor = enabled;\n return this;\n }\n\n /**\n * Enable/disable selection synchronization\n */\n syncSelection(enabled: boolean): this {\n this.options.syncSelection = enabled;\n return this;\n }\n\n /**\n * Synchronize all charts to a specific view\n */\n syncTo(bounds: Partial<Bounds>, excludeChartId?: string): void {\n this.propagateZoom(excludeChartId || '', bounds);\n }\n\n /**\n * Reset all charts to auto-scale\n */\n resetAll(): void {\n for (const chart of this.charts.values()) {\n chart.zoom({ x: undefined, y: undefined });\n }\n }\n\n /**\n * Clear all selections in the group\n */\n clearAllSelections(): void {\n for (const chart of this.charts.values()) {\n chart.clearSelection?.();\n }\n }\n\n /**\n * Destroy the group and cleanup\n */\n destroy(): void {\n for (const chart of this.charts.values()) {\n this.detachEventHandlers(chart);\n }\n this.charts.clear();\n this.eventHandlers.clear();\n \n // Clear any pending debounce timers\n for (const timerId of this.debounceTimers.values()) {\n clearTimeout(timerId);\n }\n this.debounceTimers.clear();\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private attachEventHandlers(chart: ChartLike): void {\n const chartId = chart.getId();\n const handlers = new Map<string, (...args: unknown[]) => void>();\n\n // Zoom handler\n if (this.options.syncZoom) {\n const zoomHandler = (...args: unknown[]) => {\n const e = args[0] as { x: Range; y: Range };\n this.handleZoom(chartId, e);\n };\n chart.on('zoom', zoomHandler);\n handlers.set('zoom', zoomHandler);\n }\n\n // Pan handler\n if (this.options.syncPan) {\n const panHandler = (...args: unknown[]) => {\n const e = args[0] as { deltaX: number; deltaY: number };\n this.handlePan(chartId, e);\n };\n chart.on('pan', panHandler);\n handlers.set('pan', panHandler);\n }\n\n // Cursor handler\n if (this.options.syncCursor) {\n const hoverHandler = (...args: unknown[]) => {\n const e = args[0] as { point?: { x: number; y: number } } | null;\n this.handleCursor(chartId, e);\n };\n chart.on('hover', hoverHandler);\n handlers.set('hover', hoverHandler);\n }\n\n // Selection handler\n if (this.options.syncSelection) {\n const selectionHandler = (...args: unknown[]) => {\n const e = args[0] as { selected: unknown[] };\n this.handleSelection(chartId, e);\n };\n chart.on('selectionChange', selectionHandler);\n handlers.set('selectionChange', selectionHandler);\n }\n\n this.eventHandlers.set(chartId, handlers);\n }\n\n private detachEventHandlers(chart: ChartLike): void {\n const chartId = chart.getId();\n const handlers = this.eventHandlers.get(chartId);\n \n if (!handlers) return;\n\n for (const [event, handler] of handlers.entries()) {\n chart.off(event, handler);\n }\n\n this.eventHandlers.delete(chartId);\n }\n\n private handleZoom(sourceId: string, event: { x: Range; y: Range }): void {\n if (this.isUpdating) return;\n \n const bounds: Partial<Bounds> = {};\n \n if (this.options.axis === 'x' || this.options.axis === 'xy') {\n bounds.xMin = event.x[0];\n bounds.xMax = event.x[1];\n }\n \n if (this.options.axis === 'y' || this.options.axis === 'xy') {\n bounds.yMin = event.y[0];\n bounds.yMax = event.y[1];\n }\n\n this.debounceAction(`zoom-${sourceId}`, () => {\n this.propagateZoom(sourceId, bounds);\n });\n }\n\n private handlePan(sourceId: string, event: { deltaX: number; deltaY: number }): void {\n if (this.isUpdating) return;\n\n const dx = (this.options.axis === 'x' || this.options.axis === 'xy') ? event.deltaX : 0;\n const dy = (this.options.axis === 'y' || this.options.axis === 'xy') ? event.deltaY : 0;\n\n if (dx === 0 && dy === 0) return;\n\n this.debounceAction(`pan-${sourceId}`, () => {\n this.propagatePan(sourceId, dx, dy);\n });\n }\n\n private handleCursor(sourceId: string, event: { point?: { x: number; y: number } } | null): void {\n if (this.isUpdating) return;\n\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n \n if (event?.point) {\n chart.setExternalCursor?.(event.point.x, event.point.y);\n } else {\n chart.clearExternalCursor?.();\n }\n }\n }\n\n private handleSelection(sourceId: string, _event: { selected: unknown[] }): void {\n if (this.isUpdating || !this.options.syncSelection) return;\n\n // Selection sync is more complex - we need to map indices across charts\n // For now, just clear selection on other charts when one changes\n for (const [chartId, _chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n // In a full implementation, you'd map selection by data values\n // For basic sync, we just notify that selection changed\n }\n }\n\n private propagateZoom(sourceId: string, bounds: Partial<Bounds>): void {\n if (this.isUpdating) return;\n \n this.isUpdating = true;\n\n try {\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId && !this.options.bidirectional) continue;\n if (chartId === sourceId) continue;\n\n const zoomOptions: { x?: Range; y?: Range; animate?: boolean } = {\n animate: false,\n };\n\n if (bounds.xMin !== undefined && bounds.xMax !== undefined) {\n zoomOptions.x = [bounds.xMin, bounds.xMax];\n }\n\n if (bounds.yMin !== undefined && bounds.yMax !== undefined) {\n zoomOptions.y = [bounds.yMin, bounds.yMax];\n }\n\n chart.zoom(zoomOptions);\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private propagatePan(sourceId: string, dx: number, dy: number): void {\n if (this.isUpdating) return;\n \n this.isUpdating = true;\n\n try {\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n chart.pan(dx, dy);\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private debounceAction(key: string, action: () => void): void {\n if (this.options.debounce <= 0) {\n action();\n return;\n }\n\n // Clear existing timer\n const existingTimer = this.debounceTimers.get(key);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new timer\n const timerId = window.setTimeout(() => {\n this.debounceTimers.delete(key);\n action();\n }, this.options.debounce);\n\n this.debounceTimers.set(key, timerId);\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/**\n * Create a chart group with specified charts\n */\nexport function createChartGroup(\n charts: ChartLike[],\n options?: SyncOptions\n): ChartGroup {\n const group = new ChartGroup(options);\n group.addAll(...charts);\n return group;\n}\n\n/**\n * Link two charts for synchronized viewing\n */\nexport function linkCharts(\n chart1: ChartLike,\n chart2: ChartLike,\n options?: SyncOptions\n): ChartGroup {\n return createChartGroup([chart1, chart2], options);\n}\n\n/**\n * Create a master-slave relationship (master controls slave)\n */\nexport function createMasterSlave(\n master: ChartLike,\n slave: ChartLike,\n axis: SyncAxis = 'x'\n): ChartGroup {\n return new ChartGroup({\n axis,\n bidirectional: false,\n syncCursor: true,\n syncZoom: true,\n syncPan: true,\n }).addAll(master, slave);\n}\n","/**\n * SciPlot Engine - Chart Sync Plugin\n * \n * Provides synchronization between multiple chart instances.\n * \n * @module plugins/sync\n */\n\nexport * from \"../../core/sync\";\n\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginSyncConfig {\n /** Group ID to join */\n groupId?: string;\n /** Sync axes: 'x' | 'y' | 'both' */\n syncAxes?: \"x\" | \"y\" | \"both\";\n}\n\nconst manifestSync: PluginManifest = {\n name: \"velo-plot-sync\",\n version: \"1.0.0\",\n description: \"Multi-chart synchronization for velo-plot\",\n provides: [\"interaction\"],\n tags: [\"sync\", \"multi-chart\", \"coordination\"],\n};\n\n/**\n * SciPlot Sync Plugin\n * \n * Enables smooth coordination and synchronization between separate chart instances.\n */\nexport function PluginSync(config: PluginSyncConfig = {}): ChartPlugin<PluginSyncConfig> {\n void config;\n return {\n manifest: manifestSync,\n\n onInit(_ctx: PluginContext) { \n if (config.groupId) {\n // Join the specified group\n }\n },\n\n onDestroy(_ctx: PluginContext) {\n }\n };\n}\n\nexport default PluginSync;\n"],"names":["ChartGroup","options","__publicField","chart","chartId","charts","axis","enabled","bounds","excludeChartId","_a","timerId","handlers","zoomHandler","args","e","panHandler","hoverHandler","selectionHandler","event","handler","sourceId","dx","dy","_b","_event","_chart","zoomOptions","key","action","existingTimer","createChartGroup","group","linkCharts","chart1","chart2","createMasterSlave","master","slave","manifestSync","PluginSync","config","_ctx"],"mappings":";;;AA6EO,MAAMA,EAAW;AAAA,EAOtB,YAAYC,GAAuB;AAN3B,IAAAC,EAAA,oCAAqC,IAAA;AACrC,IAAAA,EAAA;AACA,IAAAA,EAAA,2CAA4E,IAAA;AAC5E,IAAAA,EAAA,oBAAsB;AACtB,IAAAA,EAAA,4CAA0C,IAAA;AAGhD,SAAK,UAAU;AAAA,MACb,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,eAAe;AAAA,MACf,GAAGD;AAAA,IAAA;AAAA,EAEP;AAAA;AAAA;AAAA;AAAA,EAKA,IAAIE,GAAwB;AAC1B,UAAMC,IAAUD,EAAM,MAAA;AAEtB,WAAI,KAAK,OAAO,IAAIC,CAAO,KACzB,QAAQ,KAAK,sBAAsBA,CAAO,0BAA0B,GAC7D,SAGT,KAAK,OAAO,IAAIA,GAASD,CAAK,GAC9B,KAAK,oBAAoBA,CAAK,GAEvB;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAUE,GAA2B;AACnC,eAAWF,KAASE;AAClB,WAAK,IAAIF,CAAK;AAEhB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAOA,GAAwB;AAC7B,UAAMC,IAAUD,EAAM,MAAA;AAEtB,WAAK,KAAK,OAAO,IAAIC,CAAO,KAI5B,KAAK,oBAAoBD,CAAK,GAC9B,KAAK,OAAO,OAAOC,CAAO,GAEnB,QANE;AAAA,EAOX;AAAA;AAAA;AAAA;AAAA,EAKA,YAAyB;AACvB,WAAO,MAAM,KAAK,KAAK,OAAO,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAID,GAA2B;AAC7B,WAAO,KAAK,OAAO,IAAIA,EAAM,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,SAASG,GAAsB;AAC7B,gBAAK,QAAQ,OAAOA,GACb;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAWC,GAAwB;AACjC,gBAAK,QAAQ,aAAaA,GACnB;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,cAAcA,GAAwB;AACpC,gBAAK,QAAQ,gBAAgBA,GACtB;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAOC,GAAyBC,GAA+B;AAC7D,SAAK,cAAcA,KAAkB,IAAID,CAAM;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,WAAiB;AACf,eAAWL,KAAS,KAAK,OAAO,OAAA;AAC9B,MAAAA,EAAM,KAAK,EAAE,GAAG,QAAW,GAAG,QAAW;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA2B;AA/HtB,QAAAO;AAgIH,eAAWP,KAAS,KAAK,OAAO,OAAA;AAC9B,OAAAO,IAAAP,EAAM,mBAAN,QAAAO,EAAA,KAAAP;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,eAAWA,KAAS,KAAK,OAAO,OAAA;AAC9B,WAAK,oBAAoBA,CAAK;AAEhC,SAAK,OAAO,MAAA,GACZ,KAAK,cAAc,MAAA;AAGnB,eAAWQ,KAAW,KAAK,eAAe,OAAA;AACxC,mBAAaA,CAAO;AAEtB,SAAK,eAAe,MAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAAoBR,GAAwB;AAClD,UAAMC,IAAUD,EAAM,MAAA,GAChBS,wBAAe,IAAA;AAGrB,QAAI,KAAK,QAAQ,UAAU;AACzB,YAAMC,IAAc,IAAIC,MAAoB;AAC1C,cAAMC,IAAID,EAAK,CAAC;AAChB,aAAK,WAAWV,GAASW,CAAC;AAAA,MAC5B;AACA,MAAAZ,EAAM,GAAG,QAAQU,CAAW,GAC5BD,EAAS,IAAI,QAAQC,CAAW;AAAA,IAClC;AAGA,QAAI,KAAK,QAAQ,SAAS;AACxB,YAAMG,IAAa,IAAIF,MAAoB;AACzC,cAAMC,IAAID,EAAK,CAAC;AAChB,aAAK,UAAUV,GAASW,CAAC;AAAA,MAC3B;AACA,MAAAZ,EAAM,GAAG,OAAOa,CAAU,GAC1BJ,EAAS,IAAI,OAAOI,CAAU;AAAA,IAChC;AAGA,QAAI,KAAK,QAAQ,YAAY;AAC3B,YAAMC,IAAe,IAAIH,MAAoB;AAC3C,cAAMC,IAAID,EAAK,CAAC;AAChB,aAAK,aAAaV,GAASW,CAAC;AAAA,MAC9B;AACA,MAAAZ,EAAM,GAAG,SAASc,CAAY,GAC9BL,EAAS,IAAI,SAASK,CAAY;AAAA,IACpC;AAGA,QAAI,KAAK,QAAQ,eAAe;AAC9B,YAAMC,IAAmB,IAAIJ,MAAoB;AAC/C,cAAMC,IAAID,EAAK,CAAC;AAChB,aAAK,gBAAgBV,GAASW,CAAC;AAAA,MACjC;AACA,MAAAZ,EAAM,GAAG,mBAAmBe,CAAgB,GAC5CN,EAAS,IAAI,mBAAmBM,CAAgB;AAAA,IAClD;AAEA,SAAK,cAAc,IAAId,GAASQ,CAAQ;AAAA,EAC1C;AAAA,EAEQ,oBAAoBT,GAAwB;AAClD,UAAMC,IAAUD,EAAM,MAAA,GAChBS,IAAW,KAAK,cAAc,IAAIR,CAAO;AAE/C,QAAKQ,GAEL;AAAA,iBAAW,CAACO,GAAOC,CAAO,KAAKR,EAAS;AACtC,QAAAT,EAAM,IAAIgB,GAAOC,CAAO;AAG1B,WAAK,cAAc,OAAOhB,CAAO;AAAA;AAAA,EACnC;AAAA,EAEQ,WAAWiB,GAAkBF,GAAqC;AACxE,QAAI,KAAK,WAAY;AAErB,UAAMX,IAA0B,CAAA;AAEhC,KAAI,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,SAAS,UACrDA,EAAO,OAAOW,EAAM,EAAE,CAAC,GACvBX,EAAO,OAAOW,EAAM,EAAE,CAAC,KAGrB,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,SAAS,UACrDX,EAAO,OAAOW,EAAM,EAAE,CAAC,GACvBX,EAAO,OAAOW,EAAM,EAAE,CAAC,IAGzB,KAAK,eAAe,QAAQE,CAAQ,IAAI,MAAM;AAC5C,WAAK,cAAcA,GAAUb,CAAM;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEQ,UAAUa,GAAkBF,GAAiD;AACnF,QAAI,KAAK,WAAY;AAErB,UAAMG,IAAM,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,SAAS,OAAQH,EAAM,SAAS,GAChFI,IAAM,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,SAAS,OAAQJ,EAAM,SAAS;AAEtF,IAAIG,MAAO,KAAKC,MAAO,KAEvB,KAAK,eAAe,OAAOF,CAAQ,IAAI,MAAM;AAC3C,WAAK,aAAaA,GAAUC,GAAIC,CAAE;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEQ,aAAaF,GAAkBF,GAA0D;AAvP5F,QAAAT,GAAAc;AAwPH,QAAI,MAAK;AAET,iBAAW,CAACpB,GAASD,CAAK,KAAK,KAAK,OAAO;AACzC,QAAIC,MAAYiB,MAEZF,KAAA,QAAAA,EAAO,SACTT,IAAAP,EAAM,sBAAN,QAAAO,EAAA,KAAAP,GAA0BgB,EAAM,MAAM,GAAGA,EAAM,MAAM,MAErDK,IAAArB,EAAM,wBAAN,QAAAqB,EAAA,KAAArB;AAAA,EAGN;AAAA,EAEQ,gBAAgBkB,GAAkBI,GAAuC;AAC/E,QAAI,OAAK,cAAc,CAAC,KAAK,QAAQ;AAIrC,iBAAW,CAACrB,GAASsB,CAAM,KAAK,KAAK,OAAO;AAAW;AAAA,EAKzD;AAAA,EAEQ,cAAcL,GAAkBb,GAA+B;AACrE,QAAI,MAAK,YAET;AAAA,WAAK,aAAa;AAElB,UAAI;AACF,mBAAW,CAACJ,GAASD,CAAK,KAAK,KAAK,OAAO,WAAW;AAEpD,cADIC,MAAYiB,KAAY,CAAC,KAAK,QAAQ,iBACtCjB,MAAYiB,EAAU;AAE1B,gBAAMM,IAA2D;AAAA,YAC/D,SAAS;AAAA,UAAA;AAGX,UAAInB,EAAO,SAAS,UAAaA,EAAO,SAAS,WAC/CmB,EAAY,IAAI,CAACnB,EAAO,MAAMA,EAAO,IAAI,IAGvCA,EAAO,SAAS,UAAaA,EAAO,SAAS,WAC/CmB,EAAY,IAAI,CAACnB,EAAO,MAAMA,EAAO,IAAI,IAG3CL,EAAM,KAAKwB,CAAW;AAAA,QACxB;AAAA,MACF,UAAA;AACE,aAAK,aAAa;AAAA,MACpB;AAAA;AAAA,EACF;AAAA,EAEQ,aAAaN,GAAkBC,GAAYC,GAAkB;AACnE,QAAI,MAAK,YAET;AAAA,WAAK,aAAa;AAElB,UAAI;AACF,mBAAW,CAACnB,GAASD,CAAK,KAAK,KAAK,OAAO;AACzC,UAAIC,MAAYiB,KAChBlB,EAAM,IAAImB,GAAIC,CAAE;AAAA,MAEpB,UAAA;AACE,aAAK,aAAa;AAAA,MACpB;AAAA;AAAA,EACF;AAAA,EAEQ,eAAeK,GAAaC,GAA0B;AAC5D,QAAI,KAAK,QAAQ,YAAY,GAAG;AAC9B,MAAAA,EAAA;AACA;AAAA,IACF;AAGA,UAAMC,IAAgB,KAAK,eAAe,IAAIF,CAAG;AACjD,IAAIE,KACF,aAAaA,CAAa;AAI5B,UAAMnB,IAAU,OAAO,WAAW,MAAM;AACtC,WAAK,eAAe,OAAOiB,CAAG,GAC9BC,EAAA;AAAA,IACF,GAAG,KAAK,QAAQ,QAAQ;AAExB,SAAK,eAAe,IAAID,GAAKjB,CAAO;AAAA,EACtC;AACF;AASO,SAASoB,EACd1B,GACAJ,GACY;AACZ,QAAM+B,IAAQ,IAAIhC,EAAWC,CAAO;AACpC,SAAA+B,EAAM,OAAO,GAAG3B,CAAM,GACf2B;AACT;AAKO,SAASC,EACdC,GACAC,GACAlC,GACY;AACZ,SAAO8B,EAAiB,CAACG,GAAQC,CAAM,GAAGlC,CAAO;AACnD;AAKO,SAASmC,EACdC,GACAC,GACAhC,IAAiB,KACL;AACZ,SAAO,IAAIN,EAAW;AAAA,IACpB,MAAAM;AAAA,IACA,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA,EAAA,CACV,EAAE,OAAO+B,GAAQC,CAAK;AACzB;ACvbA,MAAMC,IAA+B;AAAA,EACjC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,aAAa;AAAA,EACxB,MAAM,CAAC,QAAQ,eAAe,cAAc;AAChD;AAOO,SAASC,EAAWC,IAA2B,IAAmC;AAErF,SAAO;AAAA,IACH,UAAUF;AAAA,IAEV,OAAOG,GAAqB;AACxB,MAAID,EAAO;AAAA,IAGf;AAAA,IAEA,UAAUC,GAAqB;AAAA,IAC/B;AAAA,EAAA;AAER;"}
|
|
1
|
+
{"version":3,"file":"sync.js","sources":["../../src/plugins/sync/index.ts"],"sourcesContent":["/**\n * SciPlot Engine - Chart Sync Plugin\n * \n * Provides synchronization between multiple chart instances.\n * \n * @module plugins/sync\n */\n\nexport * from \"../../core/sync\";\n\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginSyncConfig {\n /** Group ID to join */\n groupId?: string;\n /** Sync axes: 'x' | 'y' | 'both' */\n syncAxes?: \"x\" | \"y\" | \"both\";\n}\n\nconst manifestSync: PluginManifest = {\n name: \"velo-plot-sync\",\n version: \"1.0.0\",\n description: \"Multi-chart synchronization for velo-plot\",\n provides: [\"interaction\"],\n tags: [\"sync\", \"multi-chart\", \"coordination\"],\n};\n\n/**\n * SciPlot Sync Plugin\n *\n * @deprecated Use `ChartGroup` / `createChartGroup` from `velo-plot` (or `velo-plot/full`) instead.\n * This plugin stub does not perform synchronization. Kept for backward-compatible imports only.\n */\nexport function PluginSync(config: PluginSyncConfig = {}): ChartPlugin<PluginSyncConfig> {\n void config;\n return {\n manifest: manifestSync,\n\n onInit(_ctx: PluginContext) {\n console.warn(\n \"[PluginSync] Deprecated: use ChartGroup / createChartGroup from the core sync module instead.\",\n );\n },\n\n onDestroy(_ctx: PluginContext) {\n },\n };\n}\n\nexport default PluginSync;\n"],"names":["manifestSync","PluginSync","config","_ctx"],"mappings":";AAmBA,MAAMA,IAA+B;AAAA,EACjC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,aAAa;AAAA,EACxB,MAAM,CAAC,QAAQ,eAAe,cAAc;AAChD;AAQO,SAASC,EAAWC,IAA2B,IAAmC;AAEvF,SAAO;AAAA,IACL,UAAUF;AAAA,IAEV,OAAOG,GAAqB;AAC1B,cAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAEJ;AAAA,IAEA,UAAUA,GAAqB;AAAA,IAC/B;AAAA,EAAA;AAEJ;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PlotArea, Bounds } from '../../../types';
|
|
1
|
+
import { PlotArea, Bounds, AxisOptions } from '../../../types';
|
|
2
2
|
import { Scale } from '../../../scales';
|
|
3
3
|
import { Series } from '../../../core/Series';
|
|
4
4
|
import { TooltipData, TooltipOptions, TooltipTheme, TooltipTemplate, ShowTooltipOptions, TooltipEventMap } from './types';
|
|
@@ -23,6 +23,10 @@ export interface TooltipManagerConfig {
|
|
|
23
23
|
getYScales: () => Map<string, Scale>;
|
|
24
24
|
/** Function to get view bounds */
|
|
25
25
|
getViewBounds: () => Bounds;
|
|
26
|
+
/** Function to get X axis options */
|
|
27
|
+
getXAxisOptions?: () => AxisOptions;
|
|
28
|
+
/** Function to get Y axis options for a series axis id */
|
|
29
|
+
getYAxisOptions?: (axisId?: string) => AxisOptions | undefined;
|
|
26
30
|
/** Initial options */
|
|
27
31
|
options?: TooltipOptions;
|
|
28
32
|
}
|
|
@@ -34,6 +38,9 @@ export declare class TooltipManager {
|
|
|
34
38
|
private pixelToDataY;
|
|
35
39
|
private getXScale;
|
|
36
40
|
private getYScales;
|
|
41
|
+
private getViewBounds;
|
|
42
|
+
private getXAxisOptions?;
|
|
43
|
+
private getYAxisOptions?;
|
|
37
44
|
private options;
|
|
38
45
|
private theme;
|
|
39
46
|
private positioner;
|
|
@@ -131,6 +138,7 @@ export declare class TooltipManager {
|
|
|
131
138
|
* Handle heatmap and crosshair tooltip types (fallback)
|
|
132
139
|
*/
|
|
133
140
|
private performFallbackTooltipUpdate;
|
|
141
|
+
private buildAxisFormat;
|
|
134
142
|
/**
|
|
135
143
|
* Find data point by X coordinate only (O(log n) - fastest method)
|
|
136
144
|
* Best for very large datasets where precision is less important than speed
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DataPointTooltip, CrosshairTooltip } from './types';
|
|
2
|
+
|
|
3
|
+
export declare function formatDataPointX(data: DataPointTooltip): string;
|
|
4
|
+
export declare function formatDataPointY(data: DataPointTooltip): string;
|
|
5
|
+
export declare function formatCrosshairX(data: CrosshairTooltip): string;
|
|
6
|
+
export declare function formatCrosshairY(value: number, data: CrosshairTooltip): string;
|
|
7
|
+
export declare function formatCompactValue(data: DataPointTooltip, axis: "x" | "y"): string;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* This module defines all types and interfaces for the high-performance
|
|
5
|
-
* tooltip system in Sci Plot.
|
|
6
|
-
*
|
|
7
|
-
* @module tooltip/types
|
|
8
|
-
*/
|
|
1
|
+
import { TooltipAxisFormat } from '../../../core/format/axisFormat';
|
|
2
|
+
|
|
9
3
|
/** Base type for all tooltip data */
|
|
10
4
|
export type TooltipType = 'datapoint' | 'crosshair' | 'range' | 'annotation' | 'heatmap' | 'axis';
|
|
11
5
|
/** Union type for all tooltip data structures */
|
|
@@ -37,6 +31,8 @@ export interface DataPointTooltip {
|
|
|
37
31
|
xError?: [number, number];
|
|
38
32
|
/** Cycle number (for CV data) */
|
|
39
33
|
cycle?: number;
|
|
34
|
+
/** Axis formatting context aligned with chart tick formatters */
|
|
35
|
+
axisFormat?: TooltipAxisFormat;
|
|
40
36
|
/** Custom metadata from series */
|
|
41
37
|
metadata?: Record<string, unknown>;
|
|
42
38
|
}
|
|
@@ -53,6 +49,8 @@ export interface CrosshairTooltip {
|
|
|
53
49
|
dataX: number;
|
|
54
50
|
/** Interpolated values for each visible series */
|
|
55
51
|
interpolatedValues: CrosshairSeriesValue[];
|
|
52
|
+
/** Axis formatting context aligned with chart tick formatters */
|
|
53
|
+
axisFormat?: TooltipAxisFormat;
|
|
56
54
|
}
|
|
57
55
|
export interface CrosshairSeriesValue {
|
|
58
56
|
/** Series ID */
|
package/dist/plugins/tools.js
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const w = {
|
|
2
|
+
name: "velo-plot-video-recorder",
|
|
3
|
+
version: "1.0.0",
|
|
4
|
+
description: "Capture chart animations and export to video files",
|
|
5
|
+
provides: ["video-export", "media-tools"],
|
|
6
|
+
tags: ["export", "video", "animation"]
|
|
7
|
+
}, R = {
|
|
8
|
+
format: "webm",
|
|
9
|
+
fps: 30,
|
|
10
|
+
bitrate: 25e5,
|
|
11
|
+
fillBackground: !0,
|
|
12
|
+
backgroundColor: "#ffffff",
|
|
13
|
+
quality: 0.9,
|
|
14
|
+
autoDownload: !1,
|
|
15
|
+
filename: "chart-recording",
|
|
16
|
+
debug: !1
|
|
17
|
+
};
|
|
18
|
+
function F(b = {}) {
|
|
19
|
+
const a = { ...R, ...b };
|
|
20
|
+
let s = null, t = null, m = [], r = !1, l = !1, n = null, d = null, o = null;
|
|
21
|
+
function h() {
|
|
22
|
+
var i;
|
|
23
|
+
if (!s) return;
|
|
24
|
+
const e = (i = s.render.gl) == null ? void 0 : i.canvas;
|
|
25
|
+
e && (n = document.createElement("canvas"), n.width = e.width, n.height = e.height, d = n.getContext("2d"));
|
|
26
|
+
}
|
|
27
|
+
function u() {
|
|
28
|
+
var c, f, p, g, v;
|
|
29
|
+
if (!s || !d || !n) return;
|
|
30
|
+
const e = (c = s.render.gl) == null ? void 0 : c.canvas, i = (f = s.render.ctx2d) == null ? void 0 : f.canvas;
|
|
31
|
+
a.fillBackground ? (d.fillStyle = a.backgroundColor || ((v = (g = (p = s.chart).getTheme) == null ? void 0 : g.call(p)) == null ? void 0 : v.background) || "#ffffff", d.fillRect(0, 0, n.width, n.height)) : d.clearRect(0, 0, n.width, n.height), e && d.drawImage(e, 0, 0), i && d.drawImage(i, 0, 0), r && !l && (o && cancelAnimationFrame(o), o = requestAnimationFrame(u));
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
manifest: w,
|
|
35
|
+
onInit(e) {
|
|
36
|
+
s = e;
|
|
37
|
+
},
|
|
38
|
+
onDestroy() {
|
|
39
|
+
r && (t == null || t.stop(), o && cancelAnimationFrame(o)), s = null;
|
|
40
|
+
},
|
|
41
|
+
api: {
|
|
42
|
+
start() {
|
|
43
|
+
if (r || !s) return;
|
|
44
|
+
if (h(), !n) {
|
|
45
|
+
console.error("[VideoRecorder] Could not initialize capture canvas");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
m = [];
|
|
49
|
+
const e = n.captureStream(a.fps), i = {
|
|
50
|
+
mimeType: a.format === "mp4" ? "video/mp4;codecs=h264" : "video/webm;codecs=vp9",
|
|
51
|
+
videoBitsPerSecond: a.bitrate
|
|
52
|
+
};
|
|
53
|
+
MediaRecorder.isTypeSupported(i.mimeType) || (i.mimeType = "video/webm");
|
|
54
|
+
try {
|
|
55
|
+
t = new MediaRecorder(e, i), t.ondataavailable = (c) => {
|
|
56
|
+
c.data.size > 0 && m.push(c.data);
|
|
57
|
+
}, t.onstop = () => {
|
|
58
|
+
r = !1, o && cancelAnimationFrame(o);
|
|
59
|
+
}, r = !0, l = !1, t.start(100), o && cancelAnimationFrame(o), u(), a.debug && console.log("[VideoRecorder] Recording started");
|
|
60
|
+
} catch (c) {
|
|
61
|
+
console.error("[VideoRecorder] Failed to start MediaRecorder:", c);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
async stop() {
|
|
65
|
+
return new Promise((e) => {
|
|
66
|
+
if (!t || !r) {
|
|
67
|
+
e(new Blob([], { type: "video/webm" }));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
t.onstop = () => {
|
|
71
|
+
const i = new Blob(m, {
|
|
72
|
+
type: a.format === "mp4" ? "video/mp4" : "video/webm"
|
|
73
|
+
});
|
|
74
|
+
if (a.autoDownload) {
|
|
75
|
+
const c = URL.createObjectURL(i), f = document.createElement("a");
|
|
76
|
+
f.href = c, f.download = `${a.filename}.${a.format}`, f.click(), setTimeout(() => URL.revokeObjectURL(c), 100);
|
|
77
|
+
}
|
|
78
|
+
e(i), r = !1, o && cancelAnimationFrame(o), a.debug && console.log("[VideoRecorder] Recording stopped, size:", i.size);
|
|
79
|
+
}, t.stop();
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
pause() {
|
|
83
|
+
t && r && !l && (t.pause(), l = !0);
|
|
84
|
+
},
|
|
85
|
+
resume() {
|
|
86
|
+
t && r && l && (t.resume(), l = !1, o && cancelAnimationFrame(o), u());
|
|
87
|
+
},
|
|
88
|
+
isRecording() {
|
|
89
|
+
return r;
|
|
90
|
+
},
|
|
91
|
+
isPaused() {
|
|
92
|
+
return l;
|
|
93
|
+
},
|
|
94
|
+
updateConfig(e) {
|
|
95
|
+
Object.assign(a, e);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export {
|
|
101
|
+
F as PluginVideoRecorder,
|
|
102
|
+
F as default
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=video-recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-recorder.js","sources":["../../src/plugins/video-recorder/index.ts"],"sourcesContent":["/**\n * @fileoverview Video Recorder plugin for capturing chart animations.\n * @module plugins/video-recorder\n */\n\nimport type {\n PluginVideoRecorderConfig,\n VideoRecorderAPI,\n VideoRecorderOptions,\n} from './types';\nimport type {\n ChartPlugin,\n PluginContext,\n PluginManifest,\n} from '../types';\n\nconst manifest: PluginManifest = {\n name: 'velo-plot-video-recorder',\n version: '1.0.0',\n description: 'Capture chart animations and export to video files',\n provides: ['video-export', 'media-tools'],\n tags: ['export', 'video', 'animation'],\n};\n\nconst DEFAULT_CONFIG: Required<PluginVideoRecorderConfig> = {\n format: 'webm',\n fps: 30,\n bitrate: 2500000,\n fillBackground: true,\n backgroundColor: '#ffffff',\n quality: 0.9,\n autoDownload: false,\n filename: 'chart-recording',\n debug: false,\n};\n\nexport function PluginVideoRecorder(\n userConfig: Partial<PluginVideoRecorderConfig> = {}\n): ChartPlugin<PluginVideoRecorderConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n \n let mediaRecorder: MediaRecorder | null = null;\n let recordedChunks: Blob[] = [];\n let isRecording = false;\n let isPaused = false;\n \n // Composite canvas for capturing both WebGL and Overlay\n let compositeCanvas: HTMLCanvasElement | null = null;\n let compositeCtx: CanvasRenderingContext2D | null = null;\n let animationFrameId: number | null = null;\n\n function createCompositeCanvas() {\n if (!ctx) return;\n \n // Get canvases from the rendering context\n const mainCanvas = ctx.render.gl?.canvas as HTMLCanvasElement;\n \n if (!mainCanvas) return;\n\n compositeCanvas = document.createElement('canvas');\n compositeCanvas.width = mainCanvas.width;\n compositeCanvas.height = mainCanvas.height;\n compositeCtx = compositeCanvas.getContext('2d');\n }\n\n function updateComposite() {\n if (!ctx || !compositeCtx || !compositeCanvas) return;\n \n const mainCanvas = ctx.render.gl?.canvas as HTMLCanvasElement;\n const overlayCanvas = ctx.render.ctx2d?.canvas as HTMLCanvasElement;\n \n // Clear/Background\n if (config.fillBackground) {\n compositeCtx.fillStyle = config.backgroundColor || (ctx.chart as any).getTheme?.()?.background || '#ffffff';\n compositeCtx.fillRect(0, 0, compositeCanvas.width, compositeCanvas.height);\n } else {\n compositeCtx.clearRect(0, 0, compositeCanvas.width, compositeCanvas.height);\n }\n\n // Draw all chart canvases in order\n if (mainCanvas) compositeCtx.drawImage(mainCanvas, 0, 0);\n if (overlayCanvas) compositeCtx.drawImage(overlayCanvas, 0, 0);\n\n if (isRecording && !isPaused) {\n if (animationFrameId) cancelAnimationFrame(animationFrameId);\n animationFrameId = requestAnimationFrame(updateComposite);\n }\n }\n\n const api: VideoRecorderAPI = {\n start() {\n if (isRecording || !ctx) return;\n \n createCompositeCanvas();\n if (!compositeCanvas) {\n console.error('[VideoRecorder] Could not initialize capture canvas');\n return;\n }\n\n recordedChunks = [];\n const stream = compositeCanvas.captureStream(config.fps);\n \n const options: MediaRecorderOptions = {\n mimeType: config.format === 'mp4' ? 'video/mp4;codecs=h264' : 'video/webm;codecs=vp9',\n videoBitsPerSecond: config.bitrate\n };\n\n // Check for browser support and fallback\n if (!MediaRecorder.isTypeSupported(options.mimeType!)) {\n options.mimeType = 'video/webm';\n }\n\n try {\n mediaRecorder = new MediaRecorder(stream, options);\n \n mediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n recordedChunks.push(event.data);\n }\n };\n\n mediaRecorder.onstop = () => {\n isRecording = false;\n if (animationFrameId) cancelAnimationFrame(animationFrameId);\n };\n\n isRecording = true;\n isPaused = false;\n mediaRecorder.start(100); // Collect data every 100ms\n \n if (animationFrameId) cancelAnimationFrame(animationFrameId);\n updateComposite(); // Start render loop\n \n if (config.debug) console.log('[VideoRecorder] Recording started');\n } catch (e) {\n console.error('[VideoRecorder] Failed to start MediaRecorder:', e);\n }\n },\n\n async stop(): Promise<Blob> {\n return new Promise((resolve) => {\n if (!mediaRecorder || !isRecording) {\n resolve(new Blob([], { type: 'video/webm' }));\n return;\n }\n\n mediaRecorder.onstop = () => {\n const blob = new Blob(recordedChunks, {\n type: config.format === 'mp4' ? 'video/mp4' : 'video/webm'\n });\n \n if (config.autoDownload) {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `${config.filename}.${config.format}`;\n a.click();\n setTimeout(() => URL.revokeObjectURL(url), 100);\n }\n\n resolve(blob);\n isRecording = false;\n if (animationFrameId) cancelAnimationFrame(animationFrameId);\n if (config.debug) console.log('[VideoRecorder] Recording stopped, size:', blob.size);\n };\n\n mediaRecorder.stop();\n });\n },\n\n pause() {\n if (mediaRecorder && isRecording && !isPaused) {\n mediaRecorder.pause();\n isPaused = true;\n }\n },\n\n resume() {\n if (mediaRecorder && isRecording && isPaused) {\n mediaRecorder.resume();\n isPaused = false;\n if (animationFrameId) cancelAnimationFrame(animationFrameId);\n updateComposite();\n }\n },\n\n isRecording() { return isRecording; },\n isPaused() { return isPaused; },\n \n updateConfig(newConfig: Partial<VideoRecorderOptions>) {\n Object.assign(config, newConfig);\n }\n };\n\n const pluginApi: VideoRecorderAPI & Record<string, unknown> = api as any;\n\n return {\n manifest,\n onInit(pCtx) {\n ctx = pCtx;\n },\n onDestroy() {\n if (isRecording) {\n mediaRecorder?.stop();\n if (animationFrameId) cancelAnimationFrame(animationFrameId);\n }\n ctx = null;\n },\n api: pluginApi\n };\n}\n\nexport default PluginVideoRecorder;\n\n// Type exports\nexport type {\n PluginVideoRecorderConfig,\n VideoRecorderAPI,\n VideoRecorderOptions,\n} from './types';\n"],"names":["manifest","DEFAULT_CONFIG","PluginVideoRecorder","userConfig","config","ctx","mediaRecorder","recordedChunks","isRecording","isPaused","compositeCanvas","compositeCtx","animationFrameId","createCompositeCanvas","_a","mainCanvas","updateComposite","_b","_c","_d","_e","overlayCanvas","pCtx","stream","options","event","e","resolve","blob","url","a","newConfig"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualization.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* React bindings for
|
|
2
|
+
* React bindings for Velo Plot
|
|
3
3
|
*/
|
|
4
4
|
export { SciPlot, type SciPlotProps, type SciPlotRef, type SciPlotSeries } from './SciPlot';
|
|
5
5
|
export { useSciPlot, type UseSciPlotOptions, type UseSciPlotReturn } from './useSciPlot';
|
|
6
|
+
export { useStackedPlot, type UseStackedPlotOptions, type UseStackedPlotReturn } from './useStackedPlot';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { StackedChart, StackedChartOptions } from '../core/stacked';
|
|
3
|
+
import { Range } from '../types';
|
|
4
|
+
|
|
5
|
+
export interface UseStackedPlotOptions extends Omit<StackedChartOptions, "container"> {
|
|
6
|
+
}
|
|
7
|
+
export interface UseStackedPlotReturn {
|
|
8
|
+
containerRef: RefObject<HTMLDivElement>;
|
|
9
|
+
stack: StackedChart | null;
|
|
10
|
+
isReady: boolean;
|
|
11
|
+
fitAll: (options?: {
|
|
12
|
+
x?: Range;
|
|
13
|
+
padding?: number;
|
|
14
|
+
}) => void;
|
|
15
|
+
resetAll: () => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function useStackedPlot(options: UseStackedPlotOptions): UseStackedPlotReturn;
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './react/index'
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { c as k } from "./createStackedChart-CjsKcOvX.js";
|
|
2
|
+
import { S as x, u as C } from "./createStackedChart-CjsKcOvX.js";
|
|
3
|
+
import { useRef as n, useState as a, useEffect as m, useCallback as f } from "react";
|
|
4
|
+
function A(c) {
|
|
5
|
+
const s = n(null), r = n(null), [i, l] = a(null), [d, u] = a(!1), o = n(c);
|
|
6
|
+
o.current = c, m(() => {
|
|
7
|
+
const t = s.current;
|
|
8
|
+
if (!t) return;
|
|
9
|
+
const e = k({
|
|
10
|
+
...o.current,
|
|
11
|
+
container: t
|
|
12
|
+
});
|
|
13
|
+
return r.current = e, l(e), e.whenReady().then(() => u(!0)), () => {
|
|
14
|
+
u(!1), e.destroy(), r.current = null, l(null);
|
|
15
|
+
};
|
|
16
|
+
}, []);
|
|
17
|
+
const R = f((t) => {
|
|
18
|
+
var e;
|
|
19
|
+
(e = r.current) == null || e.fitAll(t);
|
|
20
|
+
}, []), S = f(() => {
|
|
21
|
+
var t;
|
|
22
|
+
(t = r.current) == null || t.resetAll();
|
|
23
|
+
}, []);
|
|
24
|
+
return { containerRef: s, stack: i, isReady: d, fitAll: R, resetAll: S };
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
x as SciPlot,
|
|
28
|
+
C as useSciPlot,
|
|
29
|
+
A as useStackedPlot
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sources":["../src/react/useStackedPlot.ts"],"sourcesContent":["/**\n * useStackedPlot - React hook for multi-pane stacked charts\n */\n\nimport {\n useEffect,\n useRef,\n useState,\n useCallback,\n type RefObject,\n} from \"react\";\nimport { createStackedChart } from \"../core/stacked\";\nimport type { StackedChart, StackedChartOptions } from \"../core/stacked\";\nimport type { Range } from \"../types\";\n\nexport interface UseStackedPlotOptions extends Omit<StackedChartOptions, \"container\"> {}\n\nexport interface UseStackedPlotReturn {\n containerRef: RefObject<HTMLDivElement>;\n stack: StackedChart | null;\n isReady: boolean;\n fitAll: (options?: { x?: Range; padding?: number }) => void;\n resetAll: () => void;\n}\n\nexport function useStackedPlot(\n options: UseStackedPlotOptions,\n): UseStackedPlotReturn {\n const containerRef = useRef<HTMLDivElement>(null);\n const stackRef = useRef<StackedChart | null>(null);\n const [stack, setStack] = useState<StackedChart | null>(null);\n const [isReady, setIsReady] = useState(false);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const created = createStackedChart({\n ...optionsRef.current,\n container: el,\n });\n stackRef.current = created;\n setStack(created);\n\n created.whenReady().then(() => setIsReady(true));\n\n return () => {\n setIsReady(false);\n created.destroy();\n stackRef.current = null;\n setStack(null);\n };\n }, []);\n\n const fitAll = useCallback((opts?: { x?: Range; padding?: number }) => {\n stackRef.current?.fitAll(opts);\n }, []);\n\n const resetAll = useCallback(() => {\n stackRef.current?.resetAll();\n }, []);\n\n return { containerRef, stack, isReady, fitAll, resetAll };\n}\n"],"names":["useStackedPlot","options","containerRef","useRef","stackRef","stack","setStack","useState","isReady","setIsReady","optionsRef","useEffect","el","created","createStackedChart","fitAll","useCallback","opts","_a","resetAll"],"mappings":";;;AAyBO,SAASA,EACdC,GACsB;AACtB,QAAMC,IAAeC,EAAuB,IAAI,GAC1CC,IAAWD,EAA4B,IAAI,GAC3C,CAACE,GAAOC,CAAQ,IAAIC,EAA8B,IAAI,GACtD,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAK,GACtCG,IAAaP,EAAOF,CAAO;AACjC,EAAAS,EAAW,UAAUT,GAErBU,EAAU,MAAM;AACd,UAAMC,IAAKV,EAAa;AACxB,QAAI,CAACU,EAAI;AAET,UAAMC,IAAUC,EAAmB;AAAA,MACjC,GAAGJ,EAAW;AAAA,MACd,WAAWE;AAAA,IAAA,CACZ;AACD,WAAAR,EAAS,UAAUS,GACnBP,EAASO,CAAO,GAEhBA,EAAQ,YAAY,KAAK,MAAMJ,EAAW,EAAI,CAAC,GAExC,MAAM;AACX,MAAAA,EAAW,EAAK,GAChBI,EAAQ,QAAA,GACRT,EAAS,UAAU,MACnBE,EAAS,IAAI;AAAA,IACf;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,QAAMS,IAASC,EAAY,CAACC,MAA2C;;AACrE,KAAAC,IAAAd,EAAS,YAAT,QAAAc,EAAkB,OAAOD;AAAA,EAC3B,GAAG,CAAA,CAAE,GAECE,IAAWH,EAAY,MAAM;;AACjC,KAAAE,IAAAd,EAAS,YAAT,QAAAc,EAAkB;AAAA,EACpB,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,cAAAhB,GAAc,OAAAG,GAAO,SAAAG,GAAS,QAAAO,GAAQ,UAAAI,EAAA;AACjD;"}
|