chartai 0.0.11 → 1.0.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 +33 -146
- package/dist/chart-library.d.ts.map +1 -1
- package/dist/chart-library.js +378 -321
- 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 +132 -0
- package/dist/charts/candlestick.min.js +32 -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-0jepamv9.js +7 -0
- package/dist/chunk-1p45ex5n.min.js +2 -0
- package/dist/chunk-831dem4f.js +4 -0
- package/dist/chunk-93yrr7er.js +35 -0
- package/dist/chunk-94kc81rr.min.js +2 -0
- package/dist/chunk-a27be8p9.js +105 -0
- package/dist/chunk-bfyv7z27.min.js +2 -0
- package/dist/chunk-dmaxrg6s.min.js +2 -0
- package/dist/chunk-e7d3zgw5.min.js +2 -0
- package/dist/chunk-g6m56ptf.js +609 -0
- package/dist/chunk-m17t3vjq.js +9 -0
- package/dist/chunk-me3qaz3m.min.js +2 -0
- package/dist/chunk-qr6mweck.min.js +2 -0
- package/dist/chunk-yabjrff2.js +11 -0
- package/dist/gpu-worker.js +625 -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/hover.d.ts +15 -2
- package/dist/plugins/hover.d.ts.map +1 -1
- package/dist/plugins/hover.js +103 -16
- 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 +282 -0
- package/dist/plugins/legend.min.js +21 -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 +227 -97
- package/dist/plugins/zoom.min.js +1 -1
- package/dist/types.d.ts +179 -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 +13 -12
- package/readme.md +51 -42
- package/dist/chunk-bgfkgcmg.js +0 -25
- package/dist/chunk-cj3zanvs.min.js +0 -2
package/dist/plugins/labels.js
CHANGED
|
@@ -1,102 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import"../chunk-bgfkgcmg.js";
|
|
5
|
-
|
|
6
|
-
// src/plugins/labels.ts
|
|
7
|
-
var niceTicks = (min, max, count) => {
|
|
8
|
-
const range = max - min;
|
|
9
|
-
if (range <= 0)
|
|
10
|
-
return [min];
|
|
11
|
-
const rough = range / count, mag = 10 ** Math.floor(Math.log10(rough)), res = rough / mag;
|
|
12
|
-
const step = mag * (res <= 1.5 ? 1 : res <= 3 ? 2 : res <= 7 ? 5 : 10);
|
|
13
|
-
const ticks = [];
|
|
14
|
-
for (let v = Math.ceil(min / step) * step;v <= max; v += step)
|
|
15
|
-
ticks.push(v);
|
|
16
|
-
return ticks;
|
|
17
|
-
};
|
|
18
|
-
var getViewState = (chart) => {
|
|
19
|
-
const mgr = ChartManager.getInstance(), w = chart.width, h = chart.height, m = ChartManager.MARGIN;
|
|
20
|
-
const { bounds: b, view: v } = chart, fullX = b.maxX - b.minX, fullY = b.maxY - b.minY;
|
|
21
|
-
const rx = fullX / v.zoomX, ry = fullY / v.zoomY;
|
|
22
|
-
const mx = b.minX + v.panX * fullX, my = b.minY + v.panY * fullY;
|
|
23
|
-
const bgc = chart.bgColor ?? (mgr.isDark ? [0.11, 0.11, 0.12] : [0.98, 0.98, 0.98]);
|
|
24
|
-
return {
|
|
25
|
-
w,
|
|
26
|
-
h,
|
|
27
|
-
m,
|
|
28
|
-
rx,
|
|
29
|
-
ry,
|
|
30
|
-
mx,
|
|
31
|
-
my,
|
|
32
|
-
bg: `${Math.round(bgc[0] * 255)},${Math.round(bgc[1] * 255)},${Math.round(bgc[2] * 255)}`,
|
|
33
|
-
font: chart.fontFamily ?? ChartManager.DEFAULT_FONT,
|
|
34
|
-
text: chart.textColor ?? (mgr.isDark ? "#c0c0c0" : "#333333"),
|
|
35
|
-
grid: chart.gridColor ?? (mgr.isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)")
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
var labelsPlugin = {
|
|
39
|
-
name: "labels",
|
|
40
|
-
beforeDraw(ctx, chart) {
|
|
41
|
-
const { w, h, m, rx, ry, mx, my, grid } = getViewState(chart);
|
|
42
|
-
ctx.strokeStyle = grid;
|
|
43
|
-
ctx.lineWidth = 1;
|
|
44
|
-
ctx.beginPath();
|
|
45
|
-
niceTicks(my, my + ry, 7).forEach((v) => {
|
|
46
|
-
const y = h * (1 - (v - my) / ry);
|
|
47
|
-
if (y > 5 && y < h - m.bottom - 5) {
|
|
48
|
-
ctx.moveTo(m.left, y);
|
|
49
|
-
ctx.lineTo(w, y);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
niceTicks(mx, mx + rx, 8).forEach((v) => {
|
|
53
|
-
const x = w * ((v - mx) / rx);
|
|
54
|
-
if (x > m.left && x < w) {
|
|
55
|
-
ctx.moveTo(x, 0);
|
|
56
|
-
ctx.lineTo(x, h - m.bottom);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
ctx.stroke();
|
|
60
|
-
},
|
|
61
|
-
afterDraw(ctx, chart) {
|
|
62
|
-
const { w, h, m, rx, ry, mx, my, bg, font, text } = getViewState(chart);
|
|
63
|
-
const {
|
|
64
|
-
formatX = String,
|
|
65
|
-
formatY = String,
|
|
66
|
-
labelSize = ChartManager.DEFAULT_LABEL_SIZE
|
|
67
|
-
} = chart.config;
|
|
68
|
-
const drawFade = (dir, x, y, fw, fh) => {
|
|
69
|
-
const g = dir === "left" ? ctx.createLinearGradient(x, 0, x + fw, 0) : ctx.createLinearGradient(0, y, 0, y + fh);
|
|
70
|
-
const alphas = dir === "left" ? [1, 0.7, 0.2, 0.05, 0] : [0, 0.05, 0.2, 0.7, 1];
|
|
71
|
-
[0, 0.35, 0.55, 0.7, 1].forEach((s, i) => g.addColorStop(s, `rgba(${bg},${alphas[i]})`));
|
|
72
|
-
ctx.fillStyle = g;
|
|
73
|
-
ctx.fillRect(x, y, fw, fh);
|
|
74
|
-
};
|
|
75
|
-
drawFade("left", 0, 0, m.left + 20, h);
|
|
76
|
-
drawFade("bottom", 0, h - m.bottom - 20, w, m.bottom + 20);
|
|
77
|
-
ctx.font = `${labelSize}px ${font}`;
|
|
78
|
-
ctx.fillStyle = text;
|
|
79
|
-
ctx.textAlign = "right";
|
|
80
|
-
ctx.textBaseline = "middle";
|
|
81
|
-
niceTicks(my, my + ry, 7).forEach((v) => {
|
|
82
|
-
const y = h * (1 - (v - my) / ry);
|
|
83
|
-
if (y > 5 && y < h - m.bottom - 5)
|
|
84
|
-
ctx.fillText(formatY(v), m.left - 5, y);
|
|
85
|
-
});
|
|
86
|
-
ctx.textAlign = "right";
|
|
87
|
-
ctx.textBaseline = "top";
|
|
88
|
-
niceTicks(mx, mx + rx, 8).forEach((v) => {
|
|
89
|
-
const x = w * ((v - mx) / rx);
|
|
90
|
-
if (x < m.left - 10 || x > w + 30)
|
|
91
|
-
return;
|
|
92
|
-
ctx.save();
|
|
93
|
-
ctx.translate(x, h - m.bottom + 5);
|
|
94
|
-
ctx.rotate(-Math.PI / 14);
|
|
95
|
-
ctx.fillText(formatX(v), 0, 0);
|
|
96
|
-
ctx.restore();
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
export {
|
|
2
|
+
DEFAULT_FONT,
|
|
3
|
+
DEFAULT_LABEL_SIZE,
|
|
101
4
|
labelsPlugin
|
|
5
|
+
} from "../chunk-a27be8p9.js";
|
|
6
|
+
import"../chunk-831dem4f.js";
|
|
7
|
+
import"../chunk-g6m56ptf.js";
|
|
8
|
+
import"../chunk-93yrr7er.js";
|
|
9
|
+
import"../chunk-m17t3vjq.js";
|
|
10
|
+
export {
|
|
11
|
+
labelsPlugin,
|
|
12
|
+
DEFAULT_LABEL_SIZE,
|
|
13
|
+
DEFAULT_FONT
|
|
102
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{g as a,h as b,i as c}from"../chunk-qr6mweck.js";import"../chunk-e7d3zgw5.js";import"../chunk-94kc81rr.js";import"../chunk-bfyv7z27.js";import"../chunk-me3qaz3m.js";export{c as labelsPlugin,b as DEFAULT_LABEL_SIZE,a as DEFAULT_FONT};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ChartPlugin } from "../types.ts";
|
|
2
|
+
export interface LegendConfig {
|
|
3
|
+
maxLabelChars?: number;
|
|
4
|
+
fontFamily?: string;
|
|
5
|
+
labelSize?: number;
|
|
6
|
+
textColor?: string;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
alwaysOpen?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare module "../types.ts" {
|
|
11
|
+
interface ChartPluginRegistry {
|
|
12
|
+
legend: LegendConfig;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export declare const legendPlugin: ChartPlugin<LegendConfig>;
|
|
16
|
+
//# sourceMappingURL=legend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legend.d.ts","sourceRoot":"","sources":["../../src/plugins/legend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,aAAa,CAAC;AAI3E,MAAM,WAAW,YAAY;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,mBAAmB;QAC3B,MAAM,EAAE,YAAY,CAAC;KACtB;CACF;AAwED,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,YAAY,CAmGlD,CAAC"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_FONT,
|
|
3
|
+
DEFAULT_LABEL_SIZE
|
|
4
|
+
} from "../chunk-a27be8p9.js";
|
|
5
|
+
import"../chunk-831dem4f.js";
|
|
6
|
+
import {
|
|
7
|
+
ChartManager
|
|
8
|
+
} from "../chunk-g6m56ptf.js";
|
|
9
|
+
import"../chunk-93yrr7er.js";
|
|
10
|
+
import"../chunk-m17t3vjq.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;padding:10px 12px">
|
|
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">
|
|
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
|
+
const cfg = getLegendConfig(chart);
|
|
85
|
+
const alwaysOpen = cfg.alwaysOpen ?? false;
|
|
86
|
+
const defaultOpen = cfg.defaultOpen ?? false;
|
|
87
|
+
const s = {
|
|
88
|
+
overlay,
|
|
89
|
+
container,
|
|
90
|
+
iconBtn,
|
|
91
|
+
panel,
|
|
92
|
+
closeBtn,
|
|
93
|
+
scrollArea,
|
|
94
|
+
list,
|
|
95
|
+
open: alwaysOpen || defaultOpen,
|
|
96
|
+
abort: ac,
|
|
97
|
+
lastSeriesKey: "",
|
|
98
|
+
computedWidth: PANEL_MAX_WIDTH
|
|
99
|
+
};
|
|
100
|
+
states.set(chart, s);
|
|
101
|
+
if (!alwaysOpen) {
|
|
102
|
+
const toggle = () => {
|
|
103
|
+
s.open = !s.open;
|
|
104
|
+
applyOpenState(chart);
|
|
105
|
+
};
|
|
106
|
+
iconBtn.addEventListener("pointerdown", (e) => {
|
|
107
|
+
e.stopPropagation();
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
toggle();
|
|
110
|
+
}, { capture: true, signal: ac.signal });
|
|
111
|
+
closeBtn.addEventListener("pointerdown", (e) => {
|
|
112
|
+
e.stopPropagation();
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
s.open = false;
|
|
115
|
+
applyOpenState(chart);
|
|
116
|
+
}, { capture: true, signal: ac.signal });
|
|
117
|
+
}
|
|
118
|
+
applyStyles(chart);
|
|
119
|
+
syncSeries(chart);
|
|
120
|
+
applyOpenState(chart);
|
|
121
|
+
},
|
|
122
|
+
afterDraw(_, chart) {
|
|
123
|
+
applyStyles(chart);
|
|
124
|
+
syncSeries(chart);
|
|
125
|
+
},
|
|
126
|
+
uninstall(chart) {
|
|
127
|
+
const s = states.get(chart);
|
|
128
|
+
if (s) {
|
|
129
|
+
s.abort.abort();
|
|
130
|
+
s.overlay.remove();
|
|
131
|
+
states.delete(chart);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function applyStyles(chart) {
|
|
136
|
+
const s = states.get(chart);
|
|
137
|
+
if (!s)
|
|
138
|
+
return;
|
|
139
|
+
const styles = getLegendStyles(chart);
|
|
140
|
+
const border = `1px solid ${styles.panelBorder}`;
|
|
141
|
+
s.container.style.background = styles.panelBg;
|
|
142
|
+
s.container.style.border = border;
|
|
143
|
+
s.container.style.fontFamily = styles.font;
|
|
144
|
+
s.container.style.fontSize = `${styles.labelSize}px`;
|
|
145
|
+
s.container.style.color = styles.text;
|
|
146
|
+
s.iconBtn.style.background = styles.closeBg;
|
|
147
|
+
s.iconBtn.style.border = "none";
|
|
148
|
+
s.iconBtn.style.boxShadow = "none";
|
|
149
|
+
s.iconBtn.style.color = styles.text;
|
|
150
|
+
s.panel.style.background = styles.panelBg;
|
|
151
|
+
s.panel.style.fontFamily = styles.font;
|
|
152
|
+
s.panel.style.fontSize = `${styles.labelSize}px`;
|
|
153
|
+
s.panel.style.color = styles.text;
|
|
154
|
+
s.closeBtn.style.background = styles.closeBgSolid;
|
|
155
|
+
s.closeBtn.style.border = border;
|
|
156
|
+
s.closeBtn.style.boxShadow = "none";
|
|
157
|
+
s.closeBtn.style.color = styles.text;
|
|
158
|
+
}
|
|
159
|
+
function seriesKey(chart) {
|
|
160
|
+
return chart.series.map((s, i) => `${i}:${s.label}`).join("|");
|
|
161
|
+
}
|
|
162
|
+
function measureTextWidth(text, font, fontSize) {
|
|
163
|
+
const canvas = document.createElement("canvas");
|
|
164
|
+
const ctx = canvas.getContext("2d");
|
|
165
|
+
if (!ctx)
|
|
166
|
+
return 0;
|
|
167
|
+
ctx.font = `${fontSize}px ${font}`;
|
|
168
|
+
return ctx.measureText(text).width;
|
|
169
|
+
}
|
|
170
|
+
function computePanelWidth(chart, labels) {
|
|
171
|
+
const styles = getLegendStyles(chart);
|
|
172
|
+
const font = styles.font;
|
|
173
|
+
const fontSize = styles.labelSize;
|
|
174
|
+
const maxChars = getLegendConfig(chart).maxLabelChars ?? DEFAULT_MAX_LABEL_CHARS;
|
|
175
|
+
let maxW = 0;
|
|
176
|
+
for (const label of labels) {
|
|
177
|
+
const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "…" : label;
|
|
178
|
+
const w = measureTextWidth(truncated, font, fontSize);
|
|
179
|
+
if (w > maxW)
|
|
180
|
+
maxW = w;
|
|
181
|
+
}
|
|
182
|
+
const swatchGap = 18;
|
|
183
|
+
const padding = 44;
|
|
184
|
+
const target = Math.ceil(maxW) + swatchGap + padding;
|
|
185
|
+
return Math.min(Math.max(target, PANEL_MIN_WIDTH), PANEL_MAX_WIDTH);
|
|
186
|
+
}
|
|
187
|
+
function syncSeries(chart) {
|
|
188
|
+
const s = states.get(chart);
|
|
189
|
+
if (!s)
|
|
190
|
+
return;
|
|
191
|
+
const series = chart.series;
|
|
192
|
+
const key = seriesKey(chart);
|
|
193
|
+
if (key === s.lastSeriesKey)
|
|
194
|
+
return;
|
|
195
|
+
s.lastSeriesKey = key;
|
|
196
|
+
const maxChars = getLegendConfig(chart).maxLabelChars ?? DEFAULT_MAX_LABEL_CHARS;
|
|
197
|
+
const labels = series.map((ser, i) => ser.label || `Series ${i + 1}`);
|
|
198
|
+
s.computedWidth = computePanelWidth(chart, labels);
|
|
199
|
+
const rowBase = "display:flex;align-items:center;gap:8px;min-width:0;padding-right:8px";
|
|
200
|
+
const rowAnim = ";opacity:0;transform:translateY(6px);animation:chart-legend-row-in .25s cubic-bezier(.34,1.2,.64,1) forwards";
|
|
201
|
+
const swatchStyle = "width:10px;height:10px;border-radius:2px;flex-shrink:0";
|
|
202
|
+
const labelStyle = "min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
203
|
+
const rows = series.map((ser, i) => {
|
|
204
|
+
const r = Math.round(ser.color.r * 255);
|
|
205
|
+
const g = Math.round(ser.color.g * 255);
|
|
206
|
+
const b = Math.round(ser.color.b * 255);
|
|
207
|
+
let label = ser.label || `Series ${i + 1}`;
|
|
208
|
+
if (label.length > maxChars)
|
|
209
|
+
label = label.slice(0, maxChars - 1) + "…";
|
|
210
|
+
const animDelay = Math.min(0.02 + i * 0.02, 0.02 + 7 * 0.02);
|
|
211
|
+
return `<div class="chart-legend-row" style="${rowBase}${rowAnim};animation-delay:${animDelay}s"><span class="chart-legend-swatch" style="${swatchStyle};background:rgb(${r},${g},${b})"></span><span class="chart-legend-label" style="${labelStyle}">${escapeHtml(label)}</span></div>`;
|
|
212
|
+
}).join("");
|
|
213
|
+
s.list.innerHTML = rows;
|
|
214
|
+
if (s.open) {
|
|
215
|
+
const packedH = s.list.scrollHeight + 20;
|
|
216
|
+
s.container.style.width = `${s.computedWidth}px`;
|
|
217
|
+
s.container.style.height = `${Math.min(PANEL_MAX_HEIGHT, packedH)}px`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function escapeHtml(s) {
|
|
221
|
+
const div = document.createElement("div");
|
|
222
|
+
div.textContent = s;
|
|
223
|
+
return div.innerHTML;
|
|
224
|
+
}
|
|
225
|
+
function applyOpenState(chart) {
|
|
226
|
+
const s = states.get(chart);
|
|
227
|
+
if (!s)
|
|
228
|
+
return;
|
|
229
|
+
const alwaysOpen = getLegendConfig(chart).alwaysOpen ?? false;
|
|
230
|
+
const open = alwaysOpen || s.open;
|
|
231
|
+
s.container.style.width = open ? `${s.computedWidth}px` : `${ICON_SIZE}px`;
|
|
232
|
+
s.container.style.height = `${ICON_SIZE}px`;
|
|
233
|
+
s.container.style.borderRadius = open ? "8px" : "50%";
|
|
234
|
+
s.container.style.overflow = "hidden";
|
|
235
|
+
s.iconBtn.style.opacity = alwaysOpen ? "0" : open ? "0" : "1";
|
|
236
|
+
s.iconBtn.style.pointerEvents = alwaysOpen ? "none" : open ? "none" : "auto";
|
|
237
|
+
s.iconBtn.style.visibility = alwaysOpen ? "hidden" : "visible";
|
|
238
|
+
s.panel.style.display = open ? "flex" : "none";
|
|
239
|
+
s.closeBtn.style.opacity = alwaysOpen ? "0" : open ? "0" : "0";
|
|
240
|
+
s.closeBtn.style.pointerEvents = alwaysOpen ? "none" : open ? "auto" : "none";
|
|
241
|
+
s.closeBtn.style.visibility = alwaysOpen ? "hidden" : open ? "visible" : "hidden";
|
|
242
|
+
s.scrollArea.style.overflowY = "hidden";
|
|
243
|
+
if (open) {
|
|
244
|
+
const packedH = s.list.scrollHeight + 20;
|
|
245
|
+
s.container.style.height = `${Math.min(PANEL_MAX_HEIGHT, packedH)}px`;
|
|
246
|
+
const onHeightDone = (e) => {
|
|
247
|
+
if (e.propertyName !== "height")
|
|
248
|
+
return;
|
|
249
|
+
s.container.removeEventListener("transitionend", onHeightDone);
|
|
250
|
+
s.scrollArea.style.overflowY = "auto";
|
|
251
|
+
};
|
|
252
|
+
s.container.addEventListener("transitionend", onHeightDone);
|
|
253
|
+
if (!alwaysOpen) {
|
|
254
|
+
requestAnimationFrame(() => {
|
|
255
|
+
requestAnimationFrame(() => {
|
|
256
|
+
s.closeBtn.style.opacity = "1";
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function injectLegendKeyframes() {
|
|
263
|
+
if (document.getElementById("chart-legend-keyframes"))
|
|
264
|
+
return;
|
|
265
|
+
const style = document.createElement("style");
|
|
266
|
+
style.id = "chart-legend-keyframes";
|
|
267
|
+
style.textContent = `
|
|
268
|
+
@keyframes chart-legend-row-in {
|
|
269
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
270
|
+
to { opacity: 1; transform: translateY(0); }
|
|
271
|
+
}
|
|
272
|
+
.chart-legend-scroll::-webkit-scrollbar { width: 6px; }
|
|
273
|
+
.chart-legend-scroll::-webkit-scrollbar-track { background: transparent; }
|
|
274
|
+
.chart-legend-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 3px; }
|
|
275
|
+
.chart-legend-scroll::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
|
|
276
|
+
`;
|
|
277
|
+
document.head.appendChild(style);
|
|
278
|
+
}
|
|
279
|
+
injectLegendKeyframes();
|
|
280
|
+
export {
|
|
281
|
+
legendPlugin
|
|
282
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import{g as N,h as f}from"../chunk-qr6mweck.js";import"../chunk-e7d3zgw5.js";import{l as T}from"../chunk-94kc81rr.js";import"../chunk-bfyv7z27.js";import"../chunk-me3qaz3m.js";var M=28,w=220,C=100,I=24,X=new WeakMap;function F(J){return J.config.legend??{}}function b(J){let q=T.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:F(J).textColor??J.config.textColor??(q?"#c0c0c0":"#333333"),textMuted:q?"#888":"#999",font:F(J).fontFamily??J.config.fontFamily??N,labelSize:F(J).labelSize??J.config.labelSize??f}}var k=Math.round(M*0.8),B=180,A=`
|
|
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;padding:10px 12px">
|
|
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">
|
|
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:-${k/2}px;right:-${k/2}px;width:${k}px;height:${k}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>`,p={name:"legend",install(J,q){let Q=new AbortController,V=document.createElement("div");V.innerHTML=A.trim();let Y=V.firstElementChild,j=Y.querySelector(".chart-legend-container"),$=j.querySelector(".chart-legend-icon"),v=j.querySelector(".chart-legend-panel"),U=j.querySelector(".chart-legend-scroll"),W=U.querySelector(".chart-legend-list"),R=Y.querySelector(".chart-legend-close");q.appendChild(Y),$.addEventListener("mouseenter",()=>{$.style.transform="scale(1.08)"}),$.addEventListener("mouseleave",()=>{$.style.transform="scale(1)"});let K="translate(-50%, 50%)";R.addEventListener("mouseenter",()=>{R.style.transform=`${K} scale(1.1)`}),R.addEventListener("mouseleave",()=>{R.style.transform=K}),U.addEventListener("wheel",(G)=>G.stopPropagation(),{passive:!1,signal:Q.signal});let z=F(J),Z=z.alwaysOpen??!1,D=z.defaultOpen??!1,P={overlay:Y,container:j,iconBtn:$,panel:v,closeBtn:R,scrollArea:U,list:W,open:Z||D,abort:Q,lastSeriesKey:"",computedWidth:w};if(X.set(J,P),!Z){let G=()=>{P.open=!P.open,x(J)};$.addEventListener("pointerdown",(u)=>{u.stopPropagation(),u.preventDefault(),G()},{capture:!0,signal:Q.signal}),R.addEventListener("pointerdown",(u)=>{u.stopPropagation(),u.preventDefault(),P.open=!1,x(J)},{capture:!0,signal:Q.signal})}m(J),H(J),x(J)},afterDraw(J,q){m(q),H(q)},uninstall(J){let q=X.get(J);if(q)q.abort.abort(),q.overlay.remove(),X.delete(J)}};function m(J){let q=X.get(J);if(!q)return;let Q=b(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 O(J){return J.series.map((q,Q)=>`${Q}:${q.label}`).join("|")}function E(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 S(J,q){let Q=b(J),V=Q.font,Y=Q.labelSize,j=F(J).maxLabelChars??I,$=0;for(let R of q){let K=R.length>j?R.slice(0,j-1)+"…":R,z=E(K,V,Y);if(z>$)$=z}let v=18,U=44,W=Math.ceil($)+v+U;return Math.min(Math.max(W,C),w)}function H(J){let q=X.get(J);if(!q)return;let Q=J.series,V=O(J);if(V===q.lastSeriesKey)return;q.lastSeriesKey=V;let Y=F(J).maxLabelChars??I,j=Q.map((K,z)=>K.label||`Series ${z+1}`);q.computedWidth=S(J,j);let $="display:flex;align-items:center;gap:8px;min-width:0;padding-right:8px",v=";opacity:0;transform:translateY(6px);animation:chart-legend-row-in .25s cubic-bezier(.34,1.2,.64,1) forwards",U="width:10px;height:10px;border-radius:2px;flex-shrink:0",W="min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap",R=Q.map((K,z)=>{let Z=Math.round(K.color.r*255),D=Math.round(K.color.g*255),P=Math.round(K.color.b*255),G=K.label||`Series ${z+1}`;if(G.length>Y)G=G.slice(0,Y-1)+"…";let u=Math.min(0.02+z*0.02,0.16);return`<div class="chart-legend-row" style="${$}${v};animation-delay:${u}s"><span class="chart-legend-swatch" style="${U};background:rgb(${Z},${D},${P})"></span><span class="chart-legend-label" style="${W}">${L(G)}</span></div>`}).join("");if(q.list.innerHTML=R,q.open){let K=q.list.scrollHeight+20;q.container.style.width=`${q.computedWidth}px`,q.container.style.height=`${Math.min(B,K)}px`}}function L(J){let q=document.createElement("div");return q.textContent=J,q.innerHTML}function x(J){let q=X.get(J);if(!q)return;let Q=F(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(B,Y)}px`;let j=($)=>{if($.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 d(){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
|
+
.chart-legend-scroll::-webkit-scrollbar { width: 6px; }
|
|
18
|
+
.chart-legend-scroll::-webkit-scrollbar-track { background: transparent; }
|
|
19
|
+
.chart-legend-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 3px; }
|
|
20
|
+
.chart-legend-scroll::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
|
|
21
|
+
`,document.head.appendChild(J)}d();export{p 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"}
|