chartai 0.1.0 → 1.1.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.
Files changed (116) hide show
  1. package/dist/chart-library.d.ts +34 -146
  2. package/dist/chart-library.d.ts.map +1 -1
  3. package/dist/chart-library.js +411 -322
  4. package/dist/chart-library.min.js +1 -1
  5. package/dist/charts/area.d.ts +6 -0
  6. package/dist/charts/area.d.ts.map +1 -0
  7. package/dist/charts/area.js +65 -0
  8. package/dist/charts/area.min.js +1 -0
  9. package/dist/charts/bar.d.ts +11 -0
  10. package/dist/charts/bar.d.ts.map +1 -0
  11. package/dist/charts/bar.js +65 -0
  12. package/dist/charts/bar.min.js +1 -0
  13. package/dist/charts/boids.js +167 -0
  14. package/dist/charts/boids.min.js +18 -0
  15. package/dist/charts/candlestick.d.ts +21 -0
  16. package/dist/charts/candlestick.d.ts.map +1 -0
  17. package/dist/charts/candlestick.js +10 -0
  18. package/dist/charts/candlestick.min.js +1 -0
  19. package/dist/charts/experimental/baseline-area.js +70 -0
  20. package/dist/charts/experimental/baseline-area.min.js +1 -0
  21. package/dist/charts/experimental/bubble.js +48 -0
  22. package/dist/charts/experimental/bubble.min.js +1 -0
  23. package/dist/charts/experimental/error-band.js +111 -0
  24. package/dist/charts/experimental/error-band.min.js +1 -0
  25. package/dist/charts/experimental/heatmap.js +69 -0
  26. package/dist/charts/experimental/heatmap.min.js +1 -0
  27. package/dist/charts/experimental/histogram.js +139 -0
  28. package/dist/charts/experimental/histogram.min.js +7 -0
  29. package/dist/charts/experimental/ohlc.js +132 -0
  30. package/dist/charts/experimental/ohlc.min.js +32 -0
  31. package/dist/charts/experimental/step.js +67 -0
  32. package/dist/charts/experimental/step.min.js +1 -0
  33. package/dist/charts/experimental/waterfall.js +121 -0
  34. package/dist/charts/experimental/waterfall.min.js +7 -0
  35. package/dist/charts/line.d.ts +12 -0
  36. package/dist/charts/line.d.ts.map +1 -0
  37. package/dist/charts/line.js +62 -0
  38. package/dist/charts/line.min.js +1 -0
  39. package/dist/charts/scatter.d.ts +11 -0
  40. package/dist/charts/scatter.d.ts.map +1 -0
  41. package/dist/charts/scatter.js +46 -0
  42. package/dist/charts/scatter.min.js +1 -0
  43. package/dist/chunk-0eh4rzy9.min.js +2 -0
  44. package/dist/chunk-0jepamv9.js +7 -0
  45. package/dist/chunk-1ngxm8t2.js +129 -0
  46. package/dist/chunk-50bcv2hw.min.js +2 -0
  47. package/dist/chunk-5gtx3pza.js +9 -0
  48. package/dist/chunk-64q9a7nw.min.js +2 -0
  49. package/dist/chunk-831dem4f.js +4 -0
  50. package/dist/chunk-93yrr7er.js +35 -0
  51. package/dist/chunk-bbyt23tw.min.js +2 -0
  52. package/dist/chunk-cbydth3q.min.js +2 -0
  53. package/dist/chunk-cvtt04m6.min.js +2 -0
  54. package/dist/chunk-g2qmt43n.min.js +33 -0
  55. package/dist/chunk-gm0d4cgx.min.js +2 -0
  56. package/dist/chunk-mmsy3yqt.js +27 -0
  57. package/dist/chunk-n8ew0z0e.js +637 -0
  58. package/dist/chunk-t0kdz02m.js +129 -0
  59. package/dist/chunk-wdfq2fpx.min.js +2 -0
  60. package/dist/chunk-yabjrff2.js +11 -0
  61. package/dist/gpu-worker.js +630 -686
  62. package/dist/gpu-worker.min.js +1 -1
  63. package/dist/msg.d.ts +33 -0
  64. package/dist/msg.d.ts.map +1 -0
  65. package/dist/plugins/coords.d.ts +18 -0
  66. package/dist/plugins/coords.d.ts.map +1 -0
  67. package/dist/plugins/experimental/annotations.js +164 -0
  68. package/dist/plugins/experimental/annotations.min.js +1 -0
  69. package/dist/plugins/experimental/crosshair.js +82 -0
  70. package/dist/plugins/experimental/crosshair.min.js +1 -0
  71. package/dist/plugins/experimental/minimap.js +190 -0
  72. package/dist/plugins/experimental/minimap.min.js +1 -0
  73. package/dist/plugins/experimental/range-selector.js +220 -0
  74. package/dist/plugins/experimental/range-selector.min.js +1 -0
  75. package/dist/plugins/experimental/ruler.js +434 -0
  76. package/dist/plugins/experimental/ruler.min.js +59 -0
  77. package/dist/plugins/experimental/stats.js +229 -0
  78. package/dist/plugins/experimental/stats.min.js +8 -0
  79. package/dist/plugins/experimental/threshold.js +96 -0
  80. package/dist/plugins/experimental/threshold.min.js +1 -0
  81. package/dist/plugins/experimental/tooltip-pin.js +177 -0
  82. package/dist/plugins/experimental/tooltip-pin.min.js +1 -0
  83. package/dist/plugins/experimental/watermark.js +76 -0
  84. package/dist/plugins/experimental/watermark.min.js +1 -0
  85. package/dist/plugins/hover.d.ts +15 -2
  86. package/dist/plugins/hover.d.ts.map +1 -1
  87. package/dist/plugins/hover.js +75 -14
  88. package/dist/plugins/hover.min.js +1 -1
  89. package/dist/plugins/labels-panel.d.ts +4 -0
  90. package/dist/plugins/labels-panel.d.ts.map +1 -0
  91. package/dist/plugins/labels-panel.js +122 -0
  92. package/dist/plugins/labels-panel.min.js +1 -0
  93. package/dist/plugins/labels.d.ts +17 -2
  94. package/dist/plugins/labels.d.ts.map +1 -1
  95. package/dist/plugins/labels.js +11 -99
  96. package/dist/plugins/labels.min.js +1 -1
  97. package/dist/plugins/legend.d.ts +16 -0
  98. package/dist/plugins/legend.d.ts.map +1 -0
  99. package/dist/plugins/legend.js +353 -0
  100. package/dist/plugins/legend.min.js +37 -0
  101. package/dist/plugins/shared.d.ts +7 -0
  102. package/dist/plugins/shared.d.ts.map +1 -0
  103. package/dist/plugins/zoom.d.ts +10 -2
  104. package/dist/plugins/zoom.d.ts.map +1 -1
  105. package/dist/plugins/zoom.js +63 -62
  106. package/dist/plugins/zoom.min.js +1 -1
  107. package/dist/types.d.ts +187 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/dist/types.js +0 -0
  110. package/dist/types.min.js +0 -0
  111. package/dist/worker-inline.d.ts +1 -1
  112. package/dist/worker-inline.d.ts.map +1 -1
  113. package/package.json +11 -11
  114. package/readme.md +54 -42
  115. package/dist/chunk-bgfkgcmg.js +0 -25
  116. package/dist/chunk-cj3zanvs.min.js +0 -2
@@ -0,0 +1,637 @@
1
+ import {
2
+ M
3
+ } from "./chunk-93yrr7er.js";
4
+ import {
5
+ __require
6
+ } from "./chunk-5gtx3pza.js";
7
+
8
+ // src/chart-library.ts
9
+ class Chart {
10
+ id;
11
+ _mgr;
12
+ constructor(id, mgr) {
13
+ this.id = id;
14
+ this._mgr = mgr;
15
+ }
16
+ get _c() {
17
+ return this._mgr["charts"].get(this.id);
18
+ }
19
+ setData(series) {
20
+ this._mgr.updateSeries(this.id, series);
21
+ }
22
+ configure(patch) {
23
+ const c = this._c;
24
+ if (!c)
25
+ return;
26
+ Object.assign(c.config, patch);
27
+ const uniformNames = new Set((c.renderer.uniforms ?? []).map((u) => u.name));
28
+ const workerValues = {};
29
+ for (const key of Object.keys(patch)) {
30
+ const val = patch[key];
31
+ if (typeof val === "number" && uniformNames.has(key)) {
32
+ workerValues[key] = val;
33
+ }
34
+ }
35
+ if (Object.keys(workerValues).length > 0) {
36
+ Object.assign(c.customUniforms, workerValues);
37
+ this._mgr["worker"]?.postMessage({
38
+ type: M.SET_UNIFORMS,
39
+ id: this.id,
40
+ values: workerValues
41
+ });
42
+ }
43
+ if ("hiddenSeries" in patch) {
44
+ this._mgr["worker"]?.postMessage({
45
+ type: M.SET_STYLE,
46
+ id: this.id,
47
+ hiddenSeries: patch.hiddenSeries ?? new Set
48
+ });
49
+ }
50
+ if ("bgColor" in patch && patch.bgColor !== undefined) {
51
+ const [r, g, b] = patch.bgColor;
52
+ const wrap = c.el.querySelector("div");
53
+ if (wrap)
54
+ wrap.style.background = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`;
55
+ this._mgr["worker"]?.postMessage({
56
+ type: M.SET_STYLE,
57
+ id: this.id,
58
+ bgColor: patch.bgColor
59
+ });
60
+ }
61
+ this._mgr.requestRender(this.id);
62
+ this._mgr.drawChart(c);
63
+ }
64
+ addPlugin(plugin) {
65
+ const c = this._c;
66
+ if (!c || c.plugins.some((p) => p.name === plugin.name))
67
+ return;
68
+ const wrap = c.el.querySelector("div");
69
+ plugin.install?.(c, wrap);
70
+ c.plugins.push(plugin);
71
+ this._mgr.drawChart(c);
72
+ }
73
+ removePlugin(name) {
74
+ const c = this._c;
75
+ if (!c)
76
+ return;
77
+ const idx = c.plugins.findIndex((p) => p.name === name);
78
+ if (idx >= 0) {
79
+ c.plugins[idx].uninstall?.(c);
80
+ c.plugins.splice(idx, 1);
81
+ this._mgr.drawChart(c);
82
+ }
83
+ }
84
+ hasPlugin(name) {
85
+ return this._c?.plugins.some((p) => p.name === name) ?? false;
86
+ }
87
+ resetView() {
88
+ this._mgr.resetView(this.id);
89
+ }
90
+ destroy() {
91
+ this._mgr.destroy(this.id);
92
+ }
93
+ }
94
+ var _colorEl = null;
95
+ function parseColor(c) {
96
+ if (typeof c !== "string")
97
+ return c;
98
+ if (!_colorEl) {
99
+ _colorEl = document.createElement("i");
100
+ _colorEl.style.cssText = "display:none";
101
+ document.body.appendChild(_colorEl);
102
+ }
103
+ _colorEl.style.color = c;
104
+ const m = getComputedStyle(_colorEl).color.match(/\d+/g);
105
+ return { r: +m[0] / 255, g: +m[1] / 255, b: +m[2] / 255 };
106
+ }
107
+ function resizeCanvas(canvas, cssW, cssH) {
108
+ const dpr = devicePixelRatio || 1;
109
+ canvas.width = Math.round(cssW * dpr);
110
+ canvas.height = Math.round(cssH * dpr);
111
+ if (canvas instanceof HTMLCanvasElement) {
112
+ canvas.style.width = `${cssW}px`;
113
+ canvas.style.height = `${cssH}px`;
114
+ }
115
+ }
116
+
117
+ class _ChartManager {
118
+ static instance = null;
119
+ worker = null;
120
+ charts = new Map;
121
+ renderers = new Map;
122
+ uiPlugins = [];
123
+ pendingRenderers = [];
124
+ chartIdCounter = 0;
125
+ _isDark = false;
126
+ _syncViews = false;
127
+ statsCallbacks = [];
128
+ currentStats = {
129
+ fps: 0,
130
+ renderMs: 0,
131
+ total: 0,
132
+ active: 0
133
+ };
134
+ visibilityObserver;
135
+ resizeObserver;
136
+ constructor() {
137
+ this._isDark = document.documentElement.classList.contains("dark");
138
+ this.visibilityObserver = new IntersectionObserver((entries) => {
139
+ for (const e of entries) {
140
+ const id = e.target.dataset.chartId;
141
+ if (!id)
142
+ continue;
143
+ const chart = this.charts.get(id);
144
+ if (!chart)
145
+ continue;
146
+ chart.visible = e.isIntersecting;
147
+ this.worker?.postMessage({
148
+ type: M.SET_VISIBILITY,
149
+ id,
150
+ visible: e.isIntersecting
151
+ });
152
+ if (e.isIntersecting)
153
+ this.drawChart(chart);
154
+ }
155
+ }, { threshold: 0.01 });
156
+ this.resizeObserver = new ResizeObserver((entries) => {
157
+ for (const e of entries) {
158
+ const id = e.target.dataset.chartId;
159
+ if (!id)
160
+ continue;
161
+ const chart = this.charts.get(id);
162
+ if (!chart)
163
+ continue;
164
+ const { width, height } = e.contentRect;
165
+ if (width <= 0 || height <= 0)
166
+ continue;
167
+ chart.width = width;
168
+ chart.height = height;
169
+ const dpr = devicePixelRatio || 1;
170
+ resizeCanvas(chart.backCanvas, width, height);
171
+ resizeCanvas(chart.frontCanvas, width, height);
172
+ const { bufferSizes, perSeriesPassMeta } = this.computeRendererMeta(chart.renderer, chart);
173
+ this.worker?.postMessage({
174
+ type: M.RESIZE,
175
+ id,
176
+ width: Math.round(width * dpr),
177
+ height: Math.round(height * dpr),
178
+ bufferSizes,
179
+ perSeriesPassMeta
180
+ });
181
+ this.drawChart(chart);
182
+ }
183
+ });
184
+ }
185
+ static getInstance() {
186
+ if (!_ChartManager.instance)
187
+ _ChartManager.instance = new _ChartManager;
188
+ return _ChartManager.instance;
189
+ }
190
+ get isDark() {
191
+ return this._isDark;
192
+ }
193
+ get syncViews() {
194
+ return this._syncViews;
195
+ }
196
+ use(plugin) {
197
+ if ("passes" in plugin) {
198
+ const r = plugin;
199
+ this.renderers.set(r.name, r);
200
+ if (this.worker)
201
+ this.sendRendererRegistration(r);
202
+ else
203
+ this.pendingRenderers.push(r);
204
+ } else {
205
+ const p = plugin;
206
+ if (!this.uiPlugins.some((x) => x.name === p.name))
207
+ this.uiPlugins.push(p);
208
+ }
209
+ }
210
+ async init() {
211
+ if (this.worker)
212
+ return true;
213
+ return new Promise((resolve) => {
214
+ import("./worker-inline.js").then(({ WORKER_CODE }) => {
215
+ const blob = new Blob([WORKER_CODE], {
216
+ type: "application/javascript"
217
+ });
218
+ this.worker = new Worker(URL.createObjectURL(blob), {
219
+ type: "module"
220
+ });
221
+ this.setupWorkerHandlers(resolve);
222
+ }).catch(() => {
223
+ this.worker = new Worker(new URL("./gpu-worker.js", import.meta.url), { type: "module" });
224
+ this.setupWorkerHandlers(resolve);
225
+ });
226
+ });
227
+ }
228
+ setupWorkerHandlers(resolve) {
229
+ if (!this.worker)
230
+ return;
231
+ this.worker.onmessage = (e) => {
232
+ const { type, ...data } = e.data;
233
+ switch (type) {
234
+ case M.GPU_READY:
235
+ for (const r of this.pendingRenderers)
236
+ this.sendRendererRegistration(r);
237
+ this.pendingRenderers = [];
238
+ resolve(true);
239
+ break;
240
+ case M.ERROR:
241
+ console.error("chartai:", data.code);
242
+ resolve(false);
243
+ break;
244
+ case M.STATS:
245
+ this.currentStats = {
246
+ fps: data.fps,
247
+ renderMs: data.renderMs,
248
+ total: data.totalCharts,
249
+ active: data.activeCharts
250
+ };
251
+ for (const cb of this.statsCallbacks)
252
+ cb(this.currentStats);
253
+ break;
254
+ }
255
+ };
256
+ this.worker.onerror = (e) => {
257
+ console.error("chartai:", e);
258
+ resolve(false);
259
+ };
260
+ this.worker.postMessage({ type: M.INIT, isDark: this._isDark });
261
+ }
262
+ sendRendererRegistration(renderer) {
263
+ const bufferDefs = (renderer.buffers ?? []).map((buf) => ({
264
+ name: buf.name,
265
+ usages: buf.usages,
266
+ perSeries: renderer.passes.some((p) => p.perSeries !== false && p.bindings.some((b) => b.source === buf.name))
267
+ }));
268
+ this.worker?.postMessage({
269
+ type: M.REGISTER_RENDERER,
270
+ name: renderer.name,
271
+ shaders: renderer.shaders,
272
+ passes: renderer.passes.map((p) => ({
273
+ type: p.type,
274
+ shader: p.shader,
275
+ bindings: p.bindings,
276
+ perSeries: p.perSeries !== false,
277
+ topology: p.topology,
278
+ loadOp: p.loadOp,
279
+ blend: p.blend
280
+ })),
281
+ bufferDefs,
282
+ uniformDefs: renderer.uniforms ?? []
283
+ });
284
+ }
285
+ computeRendererMeta(renderer, chart) {
286
+ const bufferSizes = {};
287
+ const perSeriesPassMeta = [];
288
+ const series = chart.series.length > 0 ? chart.series : [
289
+ {
290
+ rawX: [],
291
+ rawY: [],
292
+ extra: {},
293
+ label: "",
294
+ color: { r: 0, g: 0, b: 0 }
295
+ }
296
+ ];
297
+ const dpr = devicePixelRatio || 1;
298
+ const physW = Math.round(chart.width * dpr);
299
+ const physH = Math.round(chart.height * dpr);
300
+ for (const s of series) {
301
+ const ctx = {
302
+ width: physW,
303
+ height: physH,
304
+ samples: s.rawX.length,
305
+ seriesCount: series.length,
306
+ bounds: chart.bounds,
307
+ view: chart.view
308
+ };
309
+ for (const buf of renderer.buffers ?? []) {
310
+ const size = buf.bytes(ctx);
311
+ bufferSizes[buf.name] = Math.max(bufferSizes[buf.name] ?? 0, size);
312
+ }
313
+ perSeriesPassMeta.push(renderer.passes.map((p) => ({
314
+ dispatch: p.dispatch?.(ctx),
315
+ draw: p.draw?.(ctx)
316
+ })));
317
+ }
318
+ return { bufferSizes, perSeriesPassMeta };
319
+ }
320
+ create(config) {
321
+ if (!this.worker)
322
+ throw new Error("No worker. Call init().");
323
+ const renderer = this.renderers.get(config.type);
324
+ if (!renderer)
325
+ throw new Error(`No renderer "${config.type}". Call manager.use() first.`);
326
+ const id = `chart-${++this.chartIdCounter}`;
327
+ const el = document.createElement("div");
328
+ el.dataset.chartId = id;
329
+ el.style.cssText = "width:100%;height:100%;position:relative;";
330
+ const wrap = document.createElement("div");
331
+ wrap.dataset.chartId = id;
332
+ wrap.style.cssText = "width:100%;height:100%;position:relative;";
333
+ const mkCanvas = (z, events) => {
334
+ const c = document.createElement("canvas");
335
+ c.style.cssText = `position:absolute;inset:0;width:100%;height:100%;pointer-events:${events};z-index:${z};`;
336
+ return c;
337
+ };
338
+ const backCanvas = mkCanvas(0, "none");
339
+ const gpuCanvas = mkCanvas(1, "auto");
340
+ const frontCanvas = mkCanvas(2, "none");
341
+ wrap.append(backCanvas, gpuCanvas, frontCanvas);
342
+ el.appendChild(wrap);
343
+ config.container.appendChild(el);
344
+ let offscreen;
345
+ try {
346
+ offscreen = gpuCanvas.transferControlToOffscreen();
347
+ } catch (e) {
348
+ throw new Error(`Failed OffscreenCanvas: ${e}`);
349
+ }
350
+ const rect = wrap.getBoundingClientRect();
351
+ const cssW = rect.width || 400;
352
+ const cssH = rect.height || 200;
353
+ resizeCanvas(offscreen, cssW, cssH);
354
+ resizeCanvas(backCanvas, cssW, cssH);
355
+ resizeCanvas(frontCanvas, cssW, cssH);
356
+ if (config.bgColor) {
357
+ const [r, g, b] = config.bgColor;
358
+ wrap.style.background = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`;
359
+ }
360
+ const customUniforms = {};
361
+ for (const u of renderer.uniforms ?? []) {
362
+ const v = config[u.name];
363
+ customUniforms[u.name] = typeof v === "number" ? v : u.default;
364
+ }
365
+ const chart = {
366
+ id,
367
+ config,
368
+ el,
369
+ backCanvas,
370
+ frontCanvas,
371
+ width: cssW,
372
+ height: cssH,
373
+ series: [],
374
+ bounds: { minX: 0, maxX: 1, minY: 0, maxY: 1 },
375
+ view: { panX: 0, panY: 0, zoomX: 1, zoomY: 1 },
376
+ homeView: { panX: 0, panY: 0, zoomX: 1, zoomY: 1 },
377
+ visible: true,
378
+ dragging: false,
379
+ plugins: [...this.uiPlugins],
380
+ renderer,
381
+ customUniforms
382
+ };
383
+ this.charts.set(id, chart);
384
+ const dpr = devicePixelRatio || 1;
385
+ const { bufferSizes, perSeriesPassMeta } = this.computeRendererMeta(renderer, chart);
386
+ this.worker.postMessage({
387
+ type: M.REGISTER_CHART,
388
+ id,
389
+ canvas: offscreen,
390
+ rendererName: config.type,
391
+ bgColor: config.bgColor ?? null,
392
+ bufferSizes,
393
+ perSeriesPassMeta,
394
+ customUniformValues: customUniforms,
395
+ width: Math.round(cssW * dpr),
396
+ height: Math.round(cssH * dpr)
397
+ }, [offscreen]);
398
+ this.visibilityObserver.observe(el);
399
+ this.resizeObserver.observe(wrap);
400
+ for (const plugin of chart.plugins)
401
+ plugin.install?.(chart, wrap);
402
+ renderer.install?.(chart, wrap);
403
+ this.updateSeries(id, config.series);
404
+ return new Chart(id, this);
405
+ }
406
+ destroy(id) {
407
+ const chart = this.charts.get(id);
408
+ if (!chart)
409
+ return;
410
+ chart.renderer.uninstall?.(chart);
411
+ for (const p of chart.plugins)
412
+ p.uninstall?.(chart);
413
+ this.visibilityObserver.unobserve(chart.el);
414
+ const wrap = chart.el.querySelector("div");
415
+ if (wrap)
416
+ this.resizeObserver.unobserve(wrap);
417
+ chart.el.remove();
418
+ this.worker?.postMessage({ type: M.UNREGISTER_CHART, id });
419
+ this.charts.delete(id);
420
+ }
421
+ updateSeries(id, series) {
422
+ const chart = this.charts.get(id);
423
+ if (!chart || !this.worker || series.length === 0)
424
+ return;
425
+ chart.config.hiddenSeries = series.reduce((acc, s, i) => {
426
+ if (s.hidden)
427
+ acc.add(i);
428
+ return acc;
429
+ }, new Set);
430
+ chart.series = series.map((s) => {
431
+ const n = s.x.length;
432
+ const color = parseColor(s.color);
433
+ if (n === 0)
434
+ return { label: s.label, color, rawX: [], rawY: [], extra: {} };
435
+ const idx = Array.from({ length: n }, (_, i) => i).sort((a, b) => s.x[a] - s.x[b]);
436
+ const extra = {};
437
+ for (const key in s) {
438
+ if (key !== "label" && key !== "color" && key !== "x" && key !== "y" && Array.isArray(s[key])) {
439
+ extra[key] = idx.map((i) => s[key][i]);
440
+ }
441
+ }
442
+ return {
443
+ label: s.label,
444
+ color,
445
+ rawX: idx.map((i) => s.x[i]),
446
+ rawY: idx.map((i) => s.y[i]),
447
+ extra
448
+ };
449
+ });
450
+ const customBounds = chart.renderer.computeBounds?.(chart.series);
451
+ let { minX, maxX, minY, maxY } = customBounds ?? (() => {
452
+ let minX2 = Infinity, maxX2 = -Infinity, minY2 = Infinity, maxY2 = -Infinity;
453
+ for (const s of chart.series) {
454
+ for (let i = 0;i < s.rawX.length; i++) {
455
+ if (s.rawX[i] < minX2)
456
+ minX2 = s.rawX[i];
457
+ if (s.rawX[i] > maxX2)
458
+ maxX2 = s.rawX[i];
459
+ if (s.rawY[i] < minY2)
460
+ minY2 = s.rawY[i];
461
+ if (s.rawY[i] > maxY2)
462
+ maxY2 = s.rawY[i];
463
+ }
464
+ }
465
+ const px = (maxX2 - minX2) * 0.05 || 1;
466
+ const py = (maxY2 - minY2) * 0.1 || 1;
467
+ return {
468
+ minX: minX2 - px,
469
+ maxX: maxX2 + px,
470
+ minY: minY2 - py,
471
+ maxY: maxY2 + py
472
+ };
473
+ })();
474
+ const db = chart.config.defaultBounds;
475
+ if (db) {
476
+ if (db.minX !== undefined)
477
+ minX = db.minX;
478
+ if (db.maxX !== undefined)
479
+ maxX = db.maxX;
480
+ if (db.minY !== undefined)
481
+ minY = db.minY;
482
+ if (db.maxY !== undefined)
483
+ maxY = db.maxY;
484
+ }
485
+ chart.bounds = { minX, maxX, minY, maxY };
486
+ const { bufferSizes, perSeriesPassMeta } = this.computeRendererMeta(chart.renderer, chart);
487
+ const hidden = chart.config.hiddenSeries ?? new Set;
488
+ const seriesData = chart.series.map((s, i) => {
489
+ const extra = {};
490
+ for (const key in s.extra)
491
+ extra[key] = new Float32Array(s.extra[key]);
492
+ return {
493
+ label: s.label,
494
+ colorR: s.color.r,
495
+ colorG: s.color.g,
496
+ colorB: s.color.b,
497
+ dataX: new Float32Array(s.rawX),
498
+ dataY: new Float32Array(s.rawY),
499
+ extra,
500
+ hidden: hidden.has(i)
501
+ };
502
+ });
503
+ const transferables = seriesData.flatMap((s) => [
504
+ s.dataX.buffer,
505
+ s.dataY.buffer,
506
+ ...Object.values(s.extra).map((a) => a.buffer)
507
+ ]);
508
+ this.worker.postMessage({
509
+ type: M.UPDATE_SERIES,
510
+ id,
511
+ series: seriesData,
512
+ bounds: chart.bounds,
513
+ bufferSizes,
514
+ perSeriesPassMeta
515
+ }, transferables);
516
+ this.sendViewTransform(chart);
517
+ this.drawChart(chart);
518
+ }
519
+ setSyncViews(sync) {
520
+ this._syncViews = sync;
521
+ }
522
+ setTheme(dark) {
523
+ this._isDark = dark;
524
+ this.worker?.postMessage({ type: M.THEME, isDark: dark });
525
+ for (const chart of this.charts.values())
526
+ this.drawChart(chart);
527
+ }
528
+ onStats(callback) {
529
+ this.statsCallbacks.push(callback);
530
+ return () => {
531
+ const idx = this.statsCallbacks.indexOf(callback);
532
+ if (idx >= 0)
533
+ this.statsCallbacks.splice(idx, 1);
534
+ };
535
+ }
536
+ getStats() {
537
+ return { ...this.currentStats };
538
+ }
539
+ resetView(id) {
540
+ const chart = this.charts.get(id);
541
+ if (!chart)
542
+ return;
543
+ for (const p of chart.plugins)
544
+ p.resetView?.(chart);
545
+ const { panX: spx, panY: spy, zoomX: szx, zoomY: szy } = chart.view;
546
+ const { panX: tpx, panY: tpy, zoomX: tzx, zoomY: tzy } = chart.homeView;
547
+ const t0 = performance.now();
548
+ const animate = () => {
549
+ const t = Math.min(1, (performance.now() - t0) / 300);
550
+ const e = 1 - Math.pow(1 - t, 3);
551
+ chart.view.panX = spx + (tpx - spx) * e;
552
+ chart.view.panY = spy + (tpy - spy) * e;
553
+ chart.view.zoomX = szx + (tzx - szx) * e;
554
+ chart.view.zoomY = szy + (tzy - szy) * e;
555
+ this.sendViewTransform(chart);
556
+ this.drawChart(chart);
557
+ if (this._syncViews)
558
+ this.syncAllViews(chart);
559
+ if (t < 1)
560
+ requestAnimationFrame(animate);
561
+ };
562
+ requestAnimationFrame(animate);
563
+ }
564
+ setHiddenSeries(id, hidden) {
565
+ const chart = this.charts.get(id);
566
+ if (!chart)
567
+ return;
568
+ chart.config.hiddenSeries = new Set(hidden);
569
+ this.worker?.postMessage({
570
+ type: M.SET_STYLE,
571
+ id,
572
+ hiddenSeries: chart.config.hiddenSeries
573
+ });
574
+ this.drawChart(chart);
575
+ }
576
+ requestRender(id) {
577
+ const chart = this.charts.get(id);
578
+ if (chart)
579
+ this.sendViewTransform(chart);
580
+ }
581
+ sendViewTransform(chart) {
582
+ this.worker?.postMessage({
583
+ type: M.VIEW_TRANSFORM,
584
+ id: chart.id,
585
+ panX: chart.view.panX,
586
+ panY: chart.view.panY,
587
+ zoomX: chart.view.zoomX,
588
+ zoomY: chart.view.zoomY
589
+ });
590
+ }
591
+ syncAllViews(source) {
592
+ const transforms = [];
593
+ for (const chart of this.charts.values()) {
594
+ if (chart.id !== source.id) {
595
+ chart.view = { ...source.view };
596
+ transforms.push({ id: chart.id });
597
+ this.drawChart(chart);
598
+ }
599
+ }
600
+ if (transforms.length > 0) {
601
+ this.worker?.postMessage({
602
+ type: M.BATCH_VIEW_TRANSFORM,
603
+ panX: source.view.panX,
604
+ panY: source.view.panY,
605
+ zoomX: source.view.zoomX,
606
+ zoomY: source.view.zoomY,
607
+ transforms
608
+ });
609
+ }
610
+ }
611
+ drawChart(chart) {
612
+ if (!chart.visible)
613
+ return;
614
+ const dpr = devicePixelRatio || 1;
615
+ const backCtx = chart.backCanvas.getContext("2d");
616
+ if (backCtx) {
617
+ backCtx.clearRect(0, 0, chart.backCanvas.width, chart.backCanvas.height);
618
+ backCtx.save();
619
+ backCtx.scale(dpr, dpr);
620
+ for (const p of chart.plugins)
621
+ p.beforeDraw?.(backCtx, chart);
622
+ backCtx.restore();
623
+ }
624
+ const ctx = chart.frontCanvas.getContext("2d");
625
+ if (ctx) {
626
+ ctx.clearRect(0, 0, chart.frontCanvas.width, chart.frontCanvas.height);
627
+ ctx.save();
628
+ ctx.scale(dpr, dpr);
629
+ for (const p of chart.plugins)
630
+ p.afterDraw?.(ctx, chart);
631
+ ctx.restore();
632
+ }
633
+ }
634
+ }
635
+ var ChartManager = _ChartManager.getInstance();
636
+
637
+ export { Chart, ChartManager };