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.
- package/dist/chart-library.d.ts +34 -146
- package/dist/chart-library.d.ts.map +1 -1
- package/dist/chart-library.js +411 -322
- package/dist/chart-library.min.js +1 -1
- package/dist/charts/area.d.ts +6 -0
- package/dist/charts/area.d.ts.map +1 -0
- package/dist/charts/area.js +65 -0
- package/dist/charts/area.min.js +1 -0
- package/dist/charts/bar.d.ts +11 -0
- package/dist/charts/bar.d.ts.map +1 -0
- package/dist/charts/bar.js +65 -0
- package/dist/charts/bar.min.js +1 -0
- package/dist/charts/boids.js +167 -0
- package/dist/charts/boids.min.js +18 -0
- package/dist/charts/candlestick.d.ts +21 -0
- package/dist/charts/candlestick.d.ts.map +1 -0
- package/dist/charts/candlestick.js +10 -0
- package/dist/charts/candlestick.min.js +1 -0
- package/dist/charts/experimental/baseline-area.js +70 -0
- package/dist/charts/experimental/baseline-area.min.js +1 -0
- package/dist/charts/experimental/bubble.js +48 -0
- package/dist/charts/experimental/bubble.min.js +1 -0
- package/dist/charts/experimental/error-band.js +111 -0
- package/dist/charts/experimental/error-band.min.js +1 -0
- package/dist/charts/experimental/heatmap.js +69 -0
- package/dist/charts/experimental/heatmap.min.js +1 -0
- package/dist/charts/experimental/histogram.js +139 -0
- package/dist/charts/experimental/histogram.min.js +7 -0
- package/dist/charts/experimental/ohlc.js +132 -0
- package/dist/charts/experimental/ohlc.min.js +32 -0
- package/dist/charts/experimental/step.js +67 -0
- package/dist/charts/experimental/step.min.js +1 -0
- package/dist/charts/experimental/waterfall.js +121 -0
- package/dist/charts/experimental/waterfall.min.js +7 -0
- package/dist/charts/line.d.ts +12 -0
- package/dist/charts/line.d.ts.map +1 -0
- package/dist/charts/line.js +62 -0
- package/dist/charts/line.min.js +1 -0
- package/dist/charts/scatter.d.ts +11 -0
- package/dist/charts/scatter.d.ts.map +1 -0
- package/dist/charts/scatter.js +46 -0
- package/dist/charts/scatter.min.js +1 -0
- package/dist/chunk-0eh4rzy9.min.js +2 -0
- package/dist/chunk-0jepamv9.js +7 -0
- package/dist/chunk-1ngxm8t2.js +129 -0
- package/dist/chunk-50bcv2hw.min.js +2 -0
- package/dist/chunk-5gtx3pza.js +9 -0
- package/dist/chunk-64q9a7nw.min.js +2 -0
- package/dist/chunk-831dem4f.js +4 -0
- package/dist/chunk-93yrr7er.js +35 -0
- package/dist/chunk-bbyt23tw.min.js +2 -0
- package/dist/chunk-cbydth3q.min.js +2 -0
- package/dist/chunk-cvtt04m6.min.js +2 -0
- package/dist/chunk-g2qmt43n.min.js +33 -0
- package/dist/chunk-gm0d4cgx.min.js +2 -0
- package/dist/chunk-mmsy3yqt.js +27 -0
- package/dist/chunk-n8ew0z0e.js +637 -0
- package/dist/chunk-t0kdz02m.js +129 -0
- package/dist/chunk-wdfq2fpx.min.js +2 -0
- package/dist/chunk-yabjrff2.js +11 -0
- package/dist/gpu-worker.js +630 -686
- package/dist/gpu-worker.min.js +1 -1
- package/dist/msg.d.ts +33 -0
- package/dist/msg.d.ts.map +1 -0
- package/dist/plugins/coords.d.ts +18 -0
- package/dist/plugins/coords.d.ts.map +1 -0
- package/dist/plugins/experimental/annotations.js +164 -0
- package/dist/plugins/experimental/annotations.min.js +1 -0
- package/dist/plugins/experimental/crosshair.js +82 -0
- package/dist/plugins/experimental/crosshair.min.js +1 -0
- package/dist/plugins/experimental/minimap.js +190 -0
- package/dist/plugins/experimental/minimap.min.js +1 -0
- package/dist/plugins/experimental/range-selector.js +220 -0
- package/dist/plugins/experimental/range-selector.min.js +1 -0
- package/dist/plugins/experimental/ruler.js +434 -0
- package/dist/plugins/experimental/ruler.min.js +59 -0
- package/dist/plugins/experimental/stats.js +229 -0
- package/dist/plugins/experimental/stats.min.js +8 -0
- package/dist/plugins/experimental/threshold.js +96 -0
- package/dist/plugins/experimental/threshold.min.js +1 -0
- package/dist/plugins/experimental/tooltip-pin.js +177 -0
- package/dist/plugins/experimental/tooltip-pin.min.js +1 -0
- package/dist/plugins/experimental/watermark.js +76 -0
- package/dist/plugins/experimental/watermark.min.js +1 -0
- package/dist/plugins/hover.d.ts +15 -2
- package/dist/plugins/hover.d.ts.map +1 -1
- package/dist/plugins/hover.js +75 -14
- package/dist/plugins/hover.min.js +1 -1
- package/dist/plugins/labels-panel.d.ts +4 -0
- package/dist/plugins/labels-panel.d.ts.map +1 -0
- package/dist/plugins/labels-panel.js +122 -0
- package/dist/plugins/labels-panel.min.js +1 -0
- package/dist/plugins/labels.d.ts +17 -2
- package/dist/plugins/labels.d.ts.map +1 -1
- package/dist/plugins/labels.js +11 -99
- package/dist/plugins/labels.min.js +1 -1
- package/dist/plugins/legend.d.ts +16 -0
- package/dist/plugins/legend.d.ts.map +1 -0
- package/dist/plugins/legend.js +353 -0
- package/dist/plugins/legend.min.js +37 -0
- package/dist/plugins/shared.d.ts +7 -0
- package/dist/plugins/shared.d.ts.map +1 -0
- package/dist/plugins/zoom.d.ts +10 -2
- package/dist/plugins/zoom.d.ts.map +1 -1
- package/dist/plugins/zoom.js +63 -62
- package/dist/plugins/zoom.min.js +1 -1
- package/dist/types.d.ts +187 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/dist/types.min.js +0 -0
- package/dist/worker-inline.d.ts +1 -1
- package/dist/worker-inline.d.ts.map +1 -1
- package/package.json +11 -11
- package/readme.md +54 -42
- package/dist/chunk-bgfkgcmg.js +0 -25
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/plugins/shared.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;CAA8C,CAAC"}
|
package/dist/plugins/zoom.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import type { ChartPlugin } from "../
|
|
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,
|
|
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"}
|