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,353 @@
1
+ import {
2
+ DEFAULT_FONT,
3
+ DEFAULT_LABEL_SIZE
4
+ } from "../chunk-1ngxm8t2.js";
5
+ import"../chunk-831dem4f.js";
6
+ import {
7
+ ChartManager
8
+ } from "../chunk-n8ew0z0e.js";
9
+ import"../chunk-93yrr7er.js";
10
+ import"../chunk-5gtx3pza.js";
11
+
12
+ // src/plugins/legend.ts
13
+ var ICON_SIZE = 28;
14
+ var PANEL_MAX_WIDTH = 220;
15
+ var PANEL_MIN_WIDTH = 100;
16
+ var DEFAULT_MAX_LABEL_CHARS = 24;
17
+ var states = new WeakMap;
18
+ function getLegendConfig(chart) {
19
+ return chart.config.legend ?? {};
20
+ }
21
+ function getLegendStyles(chart) {
22
+ const dark = ChartManager.isDark;
23
+ const bgc = chart.config.bgColor ?? (dark ? [0.11, 0.11, 0.12] : [0.98, 0.98, 0.98]);
24
+ const rgb = `${Math.round(bgc[0] * 255)},${Math.round(bgc[1] * 255)},${Math.round(bgc[2] * 255)}`;
25
+ const border = dark ? "rgba(255,255,255,0.18)" : "rgba(0,0,0,0.14)";
26
+ const panelBg = dark ? `rgba(${rgb},0.95)` : "rgba(255,255,255,0.98)";
27
+ const closeBg = dark ? "rgba(0,0,0,0.35)" : "rgba(255,255,255,0.98)";
28
+ return {
29
+ panelBg,
30
+ panelBorder: border,
31
+ closeBg,
32
+ closeBgSolid: dark ? "rgba(0.2,0.2,0.22,0.98)" : "rgba(255,255,255,0.98)",
33
+ text: getLegendConfig(chart).textColor ?? chart.config.textColor ?? (dark ? "#c0c0c0" : "#333333"),
34
+ textMuted: dark ? "#888" : "#999",
35
+ font: getLegendConfig(chart).fontFamily ?? chart.config.fontFamily ?? DEFAULT_FONT,
36
+ labelSize: getLegendConfig(chart).labelSize ?? chart.config.labelSize ?? DEFAULT_LABEL_SIZE
37
+ };
38
+ }
39
+ var CLOSE_BTN_SIZE = Math.round(ICON_SIZE * 0.8);
40
+ var PANEL_MAX_HEIGHT = 180;
41
+ var LEGEND_HTML = `
42
+ <div class="chart-legend-overlay" style="position:absolute;inset:0;pointer-events:none;z-index:20">
43
+ <div class="chart-legend-container" style="position:absolute;top:4px;right:4px;width:${ICON_SIZE}px;height:${ICON_SIZE}px;overflow:hidden;border-radius:50%;pointer-events:auto;transition:width .2s ease,height .2s ease,border-radius .2s ease">
44
+ <button type="button" class="chart-legend-icon" title="Legend" style="position:absolute;inset:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;border:none;border-radius:inherit;cursor:pointer;flex-shrink:0;transition:transform .18s ease,opacity .2s ease"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/></svg></button>
45
+ <div class="chart-legend-panel" style="position:absolute;inset:0;display:none;flex-direction:column;overflow:hidden;border-radius:inherit">
46
+ <div class="chart-legend-scroll" style="flex:1;min-width:0;min-height:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;padding:10px 12px">
47
+ <div class="chart-legend-list" style="display:flex;flex-direction:column;gap:4px"></div>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ <button type="button" class="chart-legend-close" title="Close" style="position:absolute;top:-${CLOSE_BTN_SIZE / 2}px;right:-${CLOSE_BTN_SIZE / 2}px;width:${CLOSE_BTN_SIZE}px;height:${CLOSE_BTN_SIZE}px;display:flex;align-items:center;justify-content:center;border-radius:50%;border:none;cursor:pointer;padding:0;pointer-events:none;opacity:0;visibility:hidden;transition:transform .12s ease,opacity .18s ease .1s;z-index:21;transform:translate(-50%,50%);"><svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6L6 18"/><path d="M6 6l12 12"/></svg></button>
52
+ </div>`;
53
+ var legendPlugin = {
54
+ name: "legend",
55
+ install(chart, el) {
56
+ const ac = new AbortController;
57
+ const wrap = document.createElement("div");
58
+ wrap.innerHTML = LEGEND_HTML.trim();
59
+ const overlay = wrap.firstElementChild;
60
+ const container = overlay.querySelector(".chart-legend-container");
61
+ const iconBtn = container.querySelector(".chart-legend-icon");
62
+ const panel = container.querySelector(".chart-legend-panel");
63
+ const scrollArea = container.querySelector(".chart-legend-scroll");
64
+ const list = scrollArea.querySelector(".chart-legend-list");
65
+ const closeBtn = overlay.querySelector(".chart-legend-close");
66
+ el.appendChild(overlay);
67
+ iconBtn.addEventListener("mouseenter", () => {
68
+ iconBtn.style.transform = "scale(1.08)";
69
+ });
70
+ iconBtn.addEventListener("mouseleave", () => {
71
+ iconBtn.style.transform = "scale(1)";
72
+ });
73
+ const closeBase = "translate(-50%, 50%)";
74
+ closeBtn.addEventListener("mouseenter", () => {
75
+ closeBtn.style.transform = `${closeBase} scale(1.1)`;
76
+ });
77
+ closeBtn.addEventListener("mouseleave", () => {
78
+ closeBtn.style.transform = closeBase;
79
+ });
80
+ scrollArea.addEventListener("wheel", (e) => e.stopPropagation(), {
81
+ passive: false,
82
+ signal: ac.signal
83
+ });
84
+ list.addEventListener("pointerdown", (e) => {
85
+ const row = e.target.closest(".chart-legend-row");
86
+ if (!row)
87
+ return;
88
+ e.stopPropagation();
89
+ e.preventDefault();
90
+ const idx = Number(row.dataset.series);
91
+ if (isNaN(idx))
92
+ return;
93
+ const current = new Set(chart.config.hiddenSeries ?? []);
94
+ if (current.has(idx))
95
+ current.delete(idx);
96
+ else
97
+ current.add(idx);
98
+ const isNowHidden = current.has(idx);
99
+ const ser = chart.series[idx];
100
+ if (ser) {
101
+ const col = `rgb(${ser.color.r * 100}% ${ser.color.g * 100}% ${ser.color.b * 100}%)`;
102
+ const swatch = row.querySelector(".chart-legend-swatch");
103
+ const labelEl = row.querySelector(".chart-legend-label");
104
+ swatch.style.background = isNowHidden ? "transparent" : col;
105
+ swatch.style.border = isNowHidden ? `1.5px solid ${col}` : "";
106
+ labelEl.style.opacity = isNowHidden ? "0.4" : "";
107
+ swatch.classList.remove("chart-legend-swatch--bounce");
108
+ labelEl.classList.remove("chart-legend-label--bounce");
109
+ swatch.offsetWidth;
110
+ swatch.classList.add("chart-legend-swatch--bounce");
111
+ labelEl.classList.add("chart-legend-label--bounce");
112
+ }
113
+ ChartManager.setHiddenSeries(chart.id, [...current]);
114
+ }, { capture: true, signal: ac.signal });
115
+ const cfg = getLegendConfig(chart);
116
+ const alwaysOpen = cfg.alwaysOpen ?? false;
117
+ const defaultOpen = cfg.defaultOpen ?? false;
118
+ const s = {
119
+ overlay,
120
+ container,
121
+ iconBtn,
122
+ panel,
123
+ closeBtn,
124
+ scrollArea,
125
+ list,
126
+ open: alwaysOpen || defaultOpen,
127
+ abort: ac,
128
+ lastSeriesKey: "",
129
+ computedWidth: PANEL_MAX_WIDTH
130
+ };
131
+ states.set(chart, s);
132
+ if (!alwaysOpen) {
133
+ const toggle = () => {
134
+ s.open = !s.open;
135
+ applyOpenState(chart);
136
+ };
137
+ iconBtn.addEventListener("pointerdown", (e) => {
138
+ e.stopPropagation();
139
+ e.preventDefault();
140
+ toggle();
141
+ }, { capture: true, signal: ac.signal });
142
+ closeBtn.addEventListener("pointerdown", (e) => {
143
+ e.stopPropagation();
144
+ e.preventDefault();
145
+ s.open = false;
146
+ applyOpenState(chart);
147
+ }, { capture: true, signal: ac.signal });
148
+ }
149
+ applyStyles(chart);
150
+ syncSeries(chart);
151
+ applyOpenState(chart);
152
+ },
153
+ afterDraw(_, chart) {
154
+ applyStyles(chart);
155
+ syncSeries(chart);
156
+ },
157
+ uninstall(chart) {
158
+ const s = states.get(chart);
159
+ if (s) {
160
+ s.abort.abort();
161
+ s.overlay.remove();
162
+ states.delete(chart);
163
+ }
164
+ }
165
+ };
166
+ function applyStyles(chart) {
167
+ const s = states.get(chart);
168
+ if (!s)
169
+ return;
170
+ const styles = getLegendStyles(chart);
171
+ const border = `1px solid ${styles.panelBorder}`;
172
+ s.container.style.background = styles.panelBg;
173
+ s.container.style.border = border;
174
+ s.container.style.fontFamily = styles.font;
175
+ s.container.style.fontSize = `${styles.labelSize}px`;
176
+ s.container.style.color = styles.text;
177
+ s.iconBtn.style.background = styles.closeBg;
178
+ s.iconBtn.style.border = "none";
179
+ s.iconBtn.style.boxShadow = "none";
180
+ s.iconBtn.style.color = styles.text;
181
+ s.panel.style.background = styles.panelBg;
182
+ s.panel.style.fontFamily = styles.font;
183
+ s.panel.style.fontSize = `${styles.labelSize}px`;
184
+ s.panel.style.color = styles.text;
185
+ s.closeBtn.style.background = styles.closeBgSolid;
186
+ s.closeBtn.style.border = border;
187
+ s.closeBtn.style.boxShadow = "none";
188
+ s.closeBtn.style.color = styles.text;
189
+ }
190
+ function seriesKey(chart) {
191
+ return chart.series.map((s, i) => `${i}:${s.label}`).join("|");
192
+ }
193
+ function measureTextWidth(text, font, fontSize) {
194
+ const canvas = document.createElement("canvas");
195
+ const ctx = canvas.getContext("2d");
196
+ if (!ctx)
197
+ return 0;
198
+ ctx.font = `${fontSize}px ${font}`;
199
+ return ctx.measureText(text).width;
200
+ }
201
+ function computePanelWidth(chart, labels) {
202
+ const styles = getLegendStyles(chart);
203
+ const font = styles.font;
204
+ const fontSize = styles.labelSize;
205
+ const maxChars = getLegendConfig(chart).maxLabelChars ?? DEFAULT_MAX_LABEL_CHARS;
206
+ let maxW = 0;
207
+ for (const label of labels) {
208
+ const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "…" : label;
209
+ const w = measureTextWidth(truncated, font, fontSize);
210
+ if (w > maxW)
211
+ maxW = w;
212
+ }
213
+ const swatchGap = 18;
214
+ const padding = 44;
215
+ const target = Math.ceil(maxW) + swatchGap + padding;
216
+ return Math.min(Math.max(target, PANEL_MIN_WIDTH), PANEL_MAX_WIDTH);
217
+ }
218
+ function syncSeries(chart) {
219
+ const s = states.get(chart);
220
+ if (!s)
221
+ return;
222
+ const key = seriesKey(chart);
223
+ if (key === s.lastSeriesKey) {
224
+ applyHiddenState(chart, s);
225
+ return;
226
+ }
227
+ s.lastSeriesKey = key;
228
+ rebuildRows(chart, s);
229
+ }
230
+ function rebuildRows(chart, s) {
231
+ const series = chart.series;
232
+ const maxChars = getLegendConfig(chart).maxLabelChars ?? DEFAULT_MAX_LABEL_CHARS;
233
+ const labels = series.map((ser, i) => ser.label || `Series ${i + 1}`);
234
+ s.computedWidth = computePanelWidth(chart, labels);
235
+ const hidden = chart.config.hiddenSeries ?? new Set;
236
+ const rowBase = "display:flex;align-items:center;gap:8px;min-width:0;padding-right:8px;cursor:pointer;user-select:none";
237
+ const rowAnim = ";opacity:0;transform:translateY(6px);animation:chart-legend-row-in .25s cubic-bezier(.34,1.2,.64,1) forwards";
238
+ const swatchBase = "width:10px;height:10px;border-radius:2px;flex-shrink:0;box-sizing:border-box";
239
+ const labelBase = "min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity .15s ease";
240
+ s.list.innerHTML = series.map((ser, i) => {
241
+ const col = `rgb(${ser.color.r * 100}% ${ser.color.g * 100}% ${ser.color.b * 100}%)`;
242
+ let label = ser.label || `Series ${i + 1}`;
243
+ if (label.length > maxChars)
244
+ label = label.slice(0, maxChars - 1) + "…";
245
+ const animDelay = Math.min(0.02 + i * 0.02, 0.02 + 7 * 0.02);
246
+ const isHidden = hidden.has(i);
247
+ const swatchStyle = isHidden ? `${swatchBase};background:transparent;border:1.5px solid ${col}` : `${swatchBase};background:${col}`;
248
+ const labelOpacity = isHidden ? "opacity:0.4;" : "";
249
+ return `<div class="chart-legend-row" data-series="${i}" style="${rowBase}${rowAnim};animation-delay:${animDelay}s"><span class="chart-legend-swatch" style="${swatchStyle}"></span><span class="chart-legend-label" style="${labelOpacity}${labelBase}">${escapeHtml(label)}</span></div>`;
250
+ }).join("");
251
+ if (s.open) {
252
+ const packedH = s.list.scrollHeight + 20;
253
+ s.container.style.width = `${s.computedWidth}px`;
254
+ s.container.style.height = `${Math.min(PANEL_MAX_HEIGHT, packedH)}px`;
255
+ }
256
+ }
257
+ function applyHiddenState(chart, s) {
258
+ const hidden = chart.config.hiddenSeries ?? new Set;
259
+ s.list.querySelectorAll(".chart-legend-row").forEach((row) => {
260
+ const i = Number(row.dataset.series);
261
+ if (isNaN(i))
262
+ return;
263
+ const ser = chart.series[i];
264
+ if (!ser)
265
+ return;
266
+ const col = `rgb(${ser.color.r * 100}% ${ser.color.g * 100}% ${ser.color.b * 100}%)`;
267
+ const isHidden = hidden.has(i);
268
+ const swatch = row.querySelector(".chart-legend-swatch");
269
+ const labelEl = row.querySelector(".chart-legend-label");
270
+ swatch.style.background = isHidden ? "transparent" : col;
271
+ swatch.style.border = isHidden ? `1.5px solid ${col}` : "";
272
+ labelEl.style.opacity = isHidden ? "0.4" : "";
273
+ });
274
+ }
275
+ function escapeHtml(s) {
276
+ const div = document.createElement("div");
277
+ div.textContent = s;
278
+ return div.innerHTML;
279
+ }
280
+ function applyOpenState(chart) {
281
+ const s = states.get(chart);
282
+ if (!s)
283
+ return;
284
+ const alwaysOpen = getLegendConfig(chart).alwaysOpen ?? false;
285
+ const open = alwaysOpen || s.open;
286
+ s.container.style.width = open ? `${s.computedWidth}px` : `${ICON_SIZE}px`;
287
+ s.container.style.height = `${ICON_SIZE}px`;
288
+ s.container.style.borderRadius = open ? "8px" : "50%";
289
+ s.container.style.overflow = "hidden";
290
+ s.iconBtn.style.opacity = alwaysOpen ? "0" : open ? "0" : "1";
291
+ s.iconBtn.style.pointerEvents = alwaysOpen ? "none" : open ? "none" : "auto";
292
+ s.iconBtn.style.visibility = alwaysOpen ? "hidden" : "visible";
293
+ s.panel.style.display = open ? "flex" : "none";
294
+ s.closeBtn.style.opacity = alwaysOpen ? "0" : open ? "0" : "0";
295
+ s.closeBtn.style.pointerEvents = alwaysOpen ? "none" : open ? "auto" : "none";
296
+ s.closeBtn.style.visibility = alwaysOpen ? "hidden" : open ? "visible" : "hidden";
297
+ s.scrollArea.style.overflowY = "hidden";
298
+ if (open) {
299
+ const packedH = s.list.scrollHeight + 20;
300
+ s.container.style.height = `${Math.min(PANEL_MAX_HEIGHT, packedH)}px`;
301
+ const onHeightDone = (e) => {
302
+ if (e.propertyName !== "height")
303
+ return;
304
+ s.container.removeEventListener("transitionend", onHeightDone);
305
+ s.scrollArea.style.overflowY = "auto";
306
+ };
307
+ s.container.addEventListener("transitionend", onHeightDone);
308
+ if (!alwaysOpen) {
309
+ requestAnimationFrame(() => {
310
+ requestAnimationFrame(() => {
311
+ s.closeBtn.style.opacity = "1";
312
+ });
313
+ });
314
+ }
315
+ }
316
+ }
317
+ function injectLegendKeyframes() {
318
+ if (document.getElementById("chart-legend-keyframes"))
319
+ return;
320
+ const style = document.createElement("style");
321
+ style.id = "chart-legend-keyframes";
322
+ style.textContent = `
323
+ @keyframes chart-legend-row-in {
324
+ from { opacity: 0; transform: translateY(6px); }
325
+ to { opacity: 1; transform: translateY(0); }
326
+ }
327
+ @keyframes chart-legend-swatch-bounce {
328
+ 0% { transform: scale(1); }
329
+ 30% { transform: scale(1.5); }
330
+ 60% { transform: scale(0.82); }
331
+ 80% { transform: scale(1.12); }
332
+ 100% { transform: scale(1); }
333
+ }
334
+ .chart-legend-swatch--bounce { animation: chart-legend-swatch-bounce 0.28s ease-out; }
335
+ @keyframes chart-legend-label-bounce {
336
+ 0% { transform: scale(1); }
337
+ 30% { transform: scale(1.05); }
338
+ 60% { transform: scale(0.97); }
339
+ 80% { transform: scale(1.02); }
340
+ 100% { transform: scale(1); }
341
+ }
342
+ .chart-legend-label--bounce { animation: chart-legend-label-bounce 0.28s ease-out; }
343
+ .chart-legend-scroll::-webkit-scrollbar { width: 6px; }
344
+ .chart-legend-scroll::-webkit-scrollbar-track { background: transparent; }
345
+ .chart-legend-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 3px; }
346
+ .chart-legend-scroll::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
347
+ `;
348
+ document.head.appendChild(style);
349
+ }
350
+ injectLegendKeyframes();
351
+ export {
352
+ legendPlugin
353
+ };
@@ -0,0 +1,37 @@
1
+ import{l as b,m as S}from"../chunk-cvtt04m6.js";import"../chunk-0eh4rzy9.js";import{q as C}from"../chunk-50bcv2hw.js";import"../chunk-wdfq2fpx.js";import"../chunk-bbyt23tw.js";var m=28,L=220,w=100,_=24,k=new WeakMap;function M(J){return J.config.legend??{}}function E(J){let q=C.isDark,Q=J.config.bgColor??(q?[0.11,0.11,0.12]:[0.98,0.98,0.98]),V=`${Math.round(Q[0]*255)},${Math.round(Q[1]*255)},${Math.round(Q[2]*255)}`,Y=q?"rgba(255,255,255,0.18)":"rgba(0,0,0,0.14)";return{panelBg:q?`rgba(${V},0.95)`:"rgba(255,255,255,0.98)",panelBorder:Y,closeBg:q?"rgba(0,0,0,0.35)":"rgba(255,255,255,0.98)",closeBgSolid:q?"rgba(0.2,0.2,0.22,0.98)":"rgba(255,255,255,0.98)",text:M(J).textColor??J.config.textColor??(q?"#c0c0c0":"#333333"),textMuted:q?"#888":"#999",font:M(J).fontFamily??J.config.fontFamily??b,labelSize:M(J).labelSize??J.config.labelSize??S}}var f=Math.round(m*0.8),g=180,p=`
2
+ <div class="chart-legend-overlay" style="position:absolute;inset:0;pointer-events:none;z-index:20">
3
+ <div class="chart-legend-container" style="position:absolute;top:4px;right:4px;width:${m}px;height:${m}px;overflow:hidden;border-radius:50%;pointer-events:auto;transition:width .2s ease,height .2s ease,border-radius .2s ease">
4
+ <button type="button" class="chart-legend-icon" title="Legend" style="position:absolute;inset:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;border:none;border-radius:inherit;cursor:pointer;flex-shrink:0;transition:transform .18s ease,opacity .2s ease"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/></svg></button>
5
+ <div class="chart-legend-panel" style="position:absolute;inset:0;display:none;flex-direction:column;overflow:hidden;border-radius:inherit">
6
+ <div class="chart-legend-scroll" style="flex:1;min-width:0;min-height:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;padding:10px 12px">
7
+ <div class="chart-legend-list" style="display:flex;flex-direction:column;gap:4px"></div>
8
+ </div>
9
+ </div>
10
+ </div>
11
+ <button type="button" class="chart-legend-close" title="Close" style="position:absolute;top:-${f/2}px;right:-${f/2}px;width:${f}px;height:${f}px;display:flex;align-items:center;justify-content:center;border-radius:50%;border:none;cursor:pointer;padding:0;pointer-events:none;opacity:0;visibility:hidden;transition:transform .12s ease,opacity .18s ease .1s;z-index:21;transform:translate(-50%,50%);"><svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6L6 18"/><path d="M6 6l12 12"/></svg></button>
12
+ </div>`,t={name:"legend",install(J,q){let Q=new AbortController,V=document.createElement("div");V.innerHTML=p.trim();let Y=V.firstElementChild,j=Y.querySelector(".chart-legend-container"),K=j.querySelector(".chart-legend-icon"),U=j.querySelector(".chart-legend-panel"),z=j.querySelector(".chart-legend-scroll"),P=z.querySelector(".chart-legend-list"),$=Y.querySelector(".chart-legend-close");q.appendChild(Y),K.addEventListener("mouseenter",()=>{K.style.transform="scale(1.08)"}),K.addEventListener("mouseleave",()=>{K.style.transform="scale(1)"});let R="translate(-50%, 50%)";$.addEventListener("mouseenter",()=>{$.style.transform=`${R} scale(1.1)`}),$.addEventListener("mouseleave",()=>{$.style.transform=R}),z.addEventListener("wheel",(F)=>F.stopPropagation(),{passive:!1,signal:Q.signal}),P.addEventListener("pointerdown",(F)=>{let G=F.target.closest(".chart-legend-row");if(!G)return;F.stopPropagation(),F.preventDefault();let Z=Number(G.dataset.series);if(isNaN(Z))return;let u=new Set(J.config.hiddenSeries??[]);if(u.has(Z))u.delete(Z);else u.add(Z);let N=u.has(Z),T=J.series[Z];if(T){let O=`rgb(${T.color.r*100}% ${T.color.g*100}% ${T.color.b*100}%)`,D=G.querySelector(".chart-legend-swatch"),I=G.querySelector(".chart-legend-label");D.style.background=N?"transparent":O,D.style.border=N?`1.5px solid ${O}`:"",I.style.opacity=N?"0.4":"",D.classList.remove("chart-legend-swatch--bounce"),I.classList.remove("chart-legend-label--bounce"),D.offsetWidth,D.classList.add("chart-legend-swatch--bounce"),I.classList.add("chart-legend-label--bounce")}C.setHiddenSeries(J.id,[...u])},{capture:!0,signal:Q.signal});let X=M(J),v=X.alwaysOpen??!1,x=X.defaultOpen??!1,W={overlay:Y,container:j,iconBtn:K,panel:U,closeBtn:$,scrollArea:z,list:P,open:v||x,abort:Q,lastSeriesKey:"",computedWidth:L};if(k.set(J,W),!v){let F=()=>{W.open=!W.open,A(J)};K.addEventListener("pointerdown",(G)=>{G.stopPropagation(),G.preventDefault(),F()},{capture:!0,signal:Q.signal}),$.addEventListener("pointerdown",(G)=>{G.stopPropagation(),G.preventDefault(),W.open=!1,A(J)},{capture:!0,signal:Q.signal})}B(J),H(J),A(J)},afterDraw(J,q){B(q),H(q)},uninstall(J){let q=k.get(J);if(q)q.abort.abort(),q.overlay.remove(),k.delete(J)}};function B(J){let q=k.get(J);if(!q)return;let Q=E(J),V=`1px solid ${Q.panelBorder}`;q.container.style.background=Q.panelBg,q.container.style.border=V,q.container.style.fontFamily=Q.font,q.container.style.fontSize=`${Q.labelSize}px`,q.container.style.color=Q.text,q.iconBtn.style.background=Q.closeBg,q.iconBtn.style.border="none",q.iconBtn.style.boxShadow="none",q.iconBtn.style.color=Q.text,q.panel.style.background=Q.panelBg,q.panel.style.fontFamily=Q.font,q.panel.style.fontSize=`${Q.labelSize}px`,q.panel.style.color=Q.text,q.closeBtn.style.background=Q.closeBgSolid,q.closeBtn.style.border=V,q.closeBtn.style.boxShadow="none",q.closeBtn.style.color=Q.text}function y(J){return J.series.map((q,Q)=>`${Q}:${q.label}`).join("|")}function d(J,q,Q){let Y=document.createElement("canvas").getContext("2d");if(!Y)return 0;return Y.font=`${Q}px ${q}`,Y.measureText(J).width}function i(J,q){let Q=E(J),V=Q.font,Y=Q.labelSize,j=M(J).maxLabelChars??_,K=0;for(let $ of q){let R=$.length>j?$.slice(0,j-1)+"…":$,X=d(R,V,Y);if(X>K)K=X}let U=18,z=44,P=Math.ceil(K)+U+z;return Math.min(Math.max(P,w),L)}function H(J){let q=k.get(J);if(!q)return;let Q=y(J);if(Q===q.lastSeriesKey){h(J,q);return}q.lastSeriesKey=Q,o(J,q)}function o(J,q){let Q=J.series,V=M(J).maxLabelChars??_,Y=Q.map(($,R)=>$.label||`Series ${R+1}`);q.computedWidth=i(J,Y);let j=J.config.hiddenSeries??new Set,K="display:flex;align-items:center;gap:8px;min-width:0;padding-right:8px;cursor:pointer;user-select:none",U=";opacity:0;transform:translateY(6px);animation:chart-legend-row-in .25s cubic-bezier(.34,1.2,.64,1) forwards",z="width:10px;height:10px;border-radius:2px;flex-shrink:0;box-sizing:border-box",P="min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity .15s ease";if(q.list.innerHTML=Q.map(($,R)=>{let X=`rgb(${$.color.r*100}% ${$.color.g*100}% ${$.color.b*100}%)`,v=$.label||`Series ${R+1}`;if(v.length>V)v=v.slice(0,V-1)+"…";let x=Math.min(0.02+R*0.02,0.16),W=j.has(R),F=W?`${z};background:transparent;border:1.5px solid ${X}`:`${z};background:${X}`;return`<div class="chart-legend-row" data-series="${R}" style="${K}${U};animation-delay:${x}s"><span class="chart-legend-swatch" style="${F}"></span><span class="chart-legend-label" style="${W?"opacity:0.4;":""}${P}">${n(v)}</span></div>`}).join(""),q.open){let $=q.list.scrollHeight+20;q.container.style.width=`${q.computedWidth}px`,q.container.style.height=`${Math.min(g,$)}px`}}function h(J,q){let Q=J.config.hiddenSeries??new Set;q.list.querySelectorAll(".chart-legend-row").forEach((V)=>{let Y=Number(V.dataset.series);if(isNaN(Y))return;let j=J.series[Y];if(!j)return;let K=`rgb(${j.color.r*100}% ${j.color.g*100}% ${j.color.b*100}%)`,U=Q.has(Y),z=V.querySelector(".chart-legend-swatch"),P=V.querySelector(".chart-legend-label");z.style.background=U?"transparent":K,z.style.border=U?`1.5px solid ${K}`:"",P.style.opacity=U?"0.4":""})}function n(J){let q=document.createElement("div");return q.textContent=J,q.innerHTML}function A(J){let q=k.get(J);if(!q)return;let Q=M(J).alwaysOpen??!1,V=Q||q.open;if(q.container.style.width=V?`${q.computedWidth}px`:`${m}px`,q.container.style.height=`${m}px`,q.container.style.borderRadius=V?"8px":"50%",q.container.style.overflow="hidden",q.iconBtn.style.opacity=Q?"0":V?"0":"1",q.iconBtn.style.pointerEvents=Q?"none":V?"none":"auto",q.iconBtn.style.visibility=Q?"hidden":"visible",q.panel.style.display=V?"flex":"none",q.closeBtn.style.opacity=Q?"0":V?"0":"0",q.closeBtn.style.pointerEvents=Q?"none":V?"auto":"none",q.closeBtn.style.visibility=Q?"hidden":V?"visible":"hidden",q.scrollArea.style.overflowY="hidden",V){let Y=q.list.scrollHeight+20;q.container.style.height=`${Math.min(g,Y)}px`;let j=(K)=>{if(K.propertyName!=="height")return;q.container.removeEventListener("transitionend",j),q.scrollArea.style.overflowY="auto"};if(q.container.addEventListener("transitionend",j),!Q)requestAnimationFrame(()=>{requestAnimationFrame(()=>{q.closeBtn.style.opacity="1"})})}}function l(){if(document.getElementById("chart-legend-keyframes"))return;let J=document.createElement("style");J.id="chart-legend-keyframes",J.textContent=`
13
+ @keyframes chart-legend-row-in {
14
+ from { opacity: 0; transform: translateY(6px); }
15
+ to { opacity: 1; transform: translateY(0); }
16
+ }
17
+ @keyframes chart-legend-swatch-bounce {
18
+ 0% { transform: scale(1); }
19
+ 30% { transform: scale(1.5); }
20
+ 60% { transform: scale(0.82); }
21
+ 80% { transform: scale(1.12); }
22
+ 100% { transform: scale(1); }
23
+ }
24
+ .chart-legend-swatch--bounce { animation: chart-legend-swatch-bounce 0.28s ease-out; }
25
+ @keyframes chart-legend-label-bounce {
26
+ 0% { transform: scale(1); }
27
+ 30% { transform: scale(1.05); }
28
+ 60% { transform: scale(0.97); }
29
+ 80% { transform: scale(1.02); }
30
+ 100% { transform: scale(1); }
31
+ }
32
+ .chart-legend-label--bounce { animation: chart-legend-label-bounce 0.28s ease-out; }
33
+ .chart-legend-scroll::-webkit-scrollbar { width: 6px; }
34
+ .chart-legend-scroll::-webkit-scrollbar-track { background: transparent; }
35
+ .chart-legend-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 3px; }
36
+ .chart-legend-scroll::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
37
+ `,document.head.appendChild(J)}l();export{t as legendPlugin};
@@ -0,0 +1,7 @@
1
+ export declare const MARGIN: {
2
+ left: number;
3
+ right: number;
4
+ top: number;
5
+ bottom: number;
6
+ };
7
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/plugins/shared.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;CAA8C,CAAC"}
@@ -1,6 +1,14 @@
1
- import type { ChartPlugin } from "../chart-library.ts";
1
+ import type { ChartPlugin, ZoomMode } from "../types.ts";
2
+ export interface ZoomConfig {
3
+ zoomMode?: ZoomMode;
4
+ }
5
+ declare module "../types.ts" {
6
+ interface ChartPluginRegistry {
7
+ zoom: ZoomConfig;
8
+ }
9
+ }
2
10
  export interface ZoomPluginOptions {
3
11
  momentumDecay?: number;
4
12
  }
5
- export declare function zoomPlugin(opts?: ZoomPluginOptions): ChartPlugin;
13
+ export declare function zoomPlugin(opts?: ZoomPluginOptions): ChartPlugin<ZoomConfig>;
6
14
  //# sourceMappingURL=zoom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../src/plugins/zoom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,qBAAqB,CAAC;AAGtE,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,WAAW,CA2epE"}
1
+ {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../src/plugins/zoom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAiB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAOxE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,mBAAmB;QAC3B,IAAI,EAAE,UAAU,CAAC;KAClB;CACF;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,UAAU,CACxB,IAAI,GAAE,iBAAsB,GAC3B,WAAW,CAAC,UAAU,CAAC,CAiczB"}