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.
Files changed (78) hide show
  1. package/dist/chart-library.d.ts +33 -146
  2. package/dist/chart-library.d.ts.map +1 -1
  3. package/dist/chart-library.js +378 -321
  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 +132 -0
  18. package/dist/charts/candlestick.min.js +32 -0
  19. package/dist/charts/line.d.ts +12 -0
  20. package/dist/charts/line.d.ts.map +1 -0
  21. package/dist/charts/line.js +62 -0
  22. package/dist/charts/line.min.js +1 -0
  23. package/dist/charts/scatter.d.ts +11 -0
  24. package/dist/charts/scatter.d.ts.map +1 -0
  25. package/dist/charts/scatter.js +46 -0
  26. package/dist/charts/scatter.min.js +1 -0
  27. package/dist/chunk-0jepamv9.js +7 -0
  28. package/dist/chunk-1p45ex5n.min.js +2 -0
  29. package/dist/chunk-831dem4f.js +4 -0
  30. package/dist/chunk-93yrr7er.js +35 -0
  31. package/dist/chunk-94kc81rr.min.js +2 -0
  32. package/dist/chunk-a27be8p9.js +105 -0
  33. package/dist/chunk-bfyv7z27.min.js +2 -0
  34. package/dist/chunk-dmaxrg6s.min.js +2 -0
  35. package/dist/chunk-e7d3zgw5.min.js +2 -0
  36. package/dist/chunk-g6m56ptf.js +609 -0
  37. package/dist/chunk-m17t3vjq.js +9 -0
  38. package/dist/chunk-me3qaz3m.min.js +2 -0
  39. package/dist/chunk-qr6mweck.min.js +2 -0
  40. package/dist/chunk-yabjrff2.js +11 -0
  41. package/dist/gpu-worker.js +625 -686
  42. package/dist/gpu-worker.min.js +1 -1
  43. package/dist/msg.d.ts +33 -0
  44. package/dist/msg.d.ts.map +1 -0
  45. package/dist/plugins/coords.d.ts +18 -0
  46. package/dist/plugins/coords.d.ts.map +1 -0
  47. package/dist/plugins/hover.d.ts +15 -2
  48. package/dist/plugins/hover.d.ts.map +1 -1
  49. package/dist/plugins/hover.js +103 -16
  50. package/dist/plugins/hover.min.js +1 -1
  51. package/dist/plugins/labels-panel.d.ts +4 -0
  52. package/dist/plugins/labels-panel.d.ts.map +1 -0
  53. package/dist/plugins/labels-panel.js +122 -0
  54. package/dist/plugins/labels-panel.min.js +1 -0
  55. package/dist/plugins/labels.d.ts +17 -2
  56. package/dist/plugins/labels.d.ts.map +1 -1
  57. package/dist/plugins/labels.js +11 -99
  58. package/dist/plugins/labels.min.js +1 -1
  59. package/dist/plugins/legend.d.ts +16 -0
  60. package/dist/plugins/legend.d.ts.map +1 -0
  61. package/dist/plugins/legend.js +282 -0
  62. package/dist/plugins/legend.min.js +21 -0
  63. package/dist/plugins/shared.d.ts +7 -0
  64. package/dist/plugins/shared.d.ts.map +1 -0
  65. package/dist/plugins/zoom.d.ts +10 -2
  66. package/dist/plugins/zoom.d.ts.map +1 -1
  67. package/dist/plugins/zoom.js +227 -97
  68. package/dist/plugins/zoom.min.js +1 -1
  69. package/dist/types.d.ts +179 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +0 -0
  72. package/dist/types.min.js +0 -0
  73. package/dist/worker-inline.d.ts +1 -1
  74. package/dist/worker-inline.d.ts.map +1 -1
  75. package/package.json +13 -12
  76. package/readme.md +51 -42
  77. package/dist/chunk-bgfkgcmg.js +0 -25
  78. package/dist/chunk-cj3zanvs.min.js +0 -2
@@ -1,102 +1,14 @@
1
1
  import {
2
- ChartManager
3
- } from "../chart-library.js";
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 d}from"../chart-library.js";import"../chunk-cj3zanvs.js";var c=(t,m,s)=>{let r=m-t;if(r<=0)return[t];let o=r/s,e=10**Math.floor(Math.log10(o)),n=o/e,a=e*(n<=1.5?1:n<=3?2:n<=7?5:10),l=[];for(let b=Math.ceil(t/a)*a;b<=m;b+=a)l.push(b);return l},S=(t)=>{let m=d.getInstance(),s=t.width,r=t.height,o=d.MARGIN,{bounds:e,view:n}=t,a=e.maxX-e.minX,l=e.maxY-e.minY,b=a/n.zoomX,h=l/n.zoomY,i=e.minX+n.panX*a,p=e.minY+n.panY*l,u=t.bgColor??(m.isDark?[0.11,0.11,0.12]:[0.98,0.98,0.98]);return{w:s,h:r,m:o,rx:b,ry:h,mx:i,my:p,bg:`${Math.round(u[0]*255)},${Math.round(u[1]*255)},${Math.round(u[2]*255)}`,font:t.fontFamily??d.DEFAULT_FONT,text:t.textColor??(m.isDark?"#c0c0c0":"#333333"),grid:t.gridColor??(m.isDark?"rgba(255,255,255,0.06)":"rgba(0,0,0,0.06)")}},$={name:"labels",beforeDraw(t,m){let{w:s,h:r,m:o,rx:e,ry:n,mx:a,my:l,grid:b}=S(m);t.strokeStyle=b,t.lineWidth=1,t.beginPath(),c(l,l+n,7).forEach((h)=>{let i=r*(1-(h-l)/n);if(i>5&&i<r-o.bottom-5)t.moveTo(o.left,i),t.lineTo(s,i)}),c(a,a+e,8).forEach((h)=>{let i=s*((h-a)/e);if(i>o.left&&i<s)t.moveTo(i,0),t.lineTo(i,r-o.bottom)}),t.stroke()},afterDraw(t,m){let{w:s,h:r,m:o,rx:e,ry:n,mx:a,my:l,bg:b,font:h,text:i}=S(m),{formatX:p=String,formatY:u=String,labelSize:w=d.DEFAULT_LABEL_SIZE}=m.config,T=(g,f,y,C,E)=>{let M=g==="left"?t.createLinearGradient(f,0,f+C,0):t.createLinearGradient(0,y,0,y+E),k=g==="left"?[1,0.7,0.2,0.05,0]:[0,0.05,0.2,0.7,1];[0,0.35,0.55,0.7,1].forEach((D,X)=>M.addColorStop(D,`rgba(${b},${k[X]})`)),t.fillStyle=M,t.fillRect(f,y,C,E)};T("left",0,0,o.left+20,r),T("bottom",0,r-o.bottom-20,s,o.bottom+20),t.font=`${w}px ${h}`,t.fillStyle=i,t.textAlign="right",t.textBaseline="middle",c(l,l+n,7).forEach((g)=>{let f=r*(1-(g-l)/n);if(f>5&&f<r-o.bottom-5)t.fillText(u(g),o.left-5,f)}),t.textAlign="right",t.textBaseline="top",c(a,a+e,8).forEach((g)=>{let f=s*((g-a)/e);if(f<o.left-10||f>s+30)return;t.save(),t.translate(f,r-o.bottom+5),t.rotate(-Math.PI/14),t.fillText(p(g),0,0),t.restore()})}};export{$ as labelsPlugin};
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,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,CAkSpE"}
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"}