chartai 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/chart-library.d.ts +34 -146
  2. package/dist/chart-library.d.ts.map +1 -1
  3. package/dist/chart-library.js +411 -322
  4. package/dist/chart-library.min.js +1 -1
  5. package/dist/charts/area.d.ts +6 -0
  6. package/dist/charts/area.d.ts.map +1 -0
  7. package/dist/charts/area.js +65 -0
  8. package/dist/charts/area.min.js +1 -0
  9. package/dist/charts/bar.d.ts +11 -0
  10. package/dist/charts/bar.d.ts.map +1 -0
  11. package/dist/charts/bar.js +65 -0
  12. package/dist/charts/bar.min.js +1 -0
  13. package/dist/charts/boids.js +167 -0
  14. package/dist/charts/boids.min.js +18 -0
  15. package/dist/charts/candlestick.d.ts +21 -0
  16. package/dist/charts/candlestick.d.ts.map +1 -0
  17. package/dist/charts/candlestick.js +10 -0
  18. package/dist/charts/candlestick.min.js +1 -0
  19. package/dist/charts/experimental/baseline-area.js +70 -0
  20. package/dist/charts/experimental/baseline-area.min.js +1 -0
  21. package/dist/charts/experimental/bubble.js +48 -0
  22. package/dist/charts/experimental/bubble.min.js +1 -0
  23. package/dist/charts/experimental/error-band.js +111 -0
  24. package/dist/charts/experimental/error-band.min.js +1 -0
  25. package/dist/charts/experimental/heatmap.js +69 -0
  26. package/dist/charts/experimental/heatmap.min.js +1 -0
  27. package/dist/charts/experimental/histogram.js +139 -0
  28. package/dist/charts/experimental/histogram.min.js +7 -0
  29. package/dist/charts/experimental/ohlc.js +132 -0
  30. package/dist/charts/experimental/ohlc.min.js +32 -0
  31. package/dist/charts/experimental/step.js +67 -0
  32. package/dist/charts/experimental/step.min.js +1 -0
  33. package/dist/charts/experimental/waterfall.js +121 -0
  34. package/dist/charts/experimental/waterfall.min.js +7 -0
  35. package/dist/charts/line.d.ts +12 -0
  36. package/dist/charts/line.d.ts.map +1 -0
  37. package/dist/charts/line.js +62 -0
  38. package/dist/charts/line.min.js +1 -0
  39. package/dist/charts/scatter.d.ts +11 -0
  40. package/dist/charts/scatter.d.ts.map +1 -0
  41. package/dist/charts/scatter.js +46 -0
  42. package/dist/charts/scatter.min.js +1 -0
  43. package/dist/chunk-0eh4rzy9.min.js +2 -0
  44. package/dist/chunk-0jepamv9.js +7 -0
  45. package/dist/chunk-1ngxm8t2.js +129 -0
  46. package/dist/chunk-50bcv2hw.min.js +2 -0
  47. package/dist/chunk-5gtx3pza.js +9 -0
  48. package/dist/chunk-64q9a7nw.min.js +2 -0
  49. package/dist/chunk-831dem4f.js +4 -0
  50. package/dist/chunk-93yrr7er.js +35 -0
  51. package/dist/chunk-bbyt23tw.min.js +2 -0
  52. package/dist/chunk-cbydth3q.min.js +2 -0
  53. package/dist/chunk-cvtt04m6.min.js +2 -0
  54. package/dist/chunk-g2qmt43n.min.js +33 -0
  55. package/dist/chunk-gm0d4cgx.min.js +2 -0
  56. package/dist/chunk-mmsy3yqt.js +27 -0
  57. package/dist/chunk-n8ew0z0e.js +637 -0
  58. package/dist/chunk-t0kdz02m.js +129 -0
  59. package/dist/chunk-wdfq2fpx.min.js +2 -0
  60. package/dist/chunk-yabjrff2.js +11 -0
  61. package/dist/gpu-worker.js +630 -686
  62. package/dist/gpu-worker.min.js +1 -1
  63. package/dist/msg.d.ts +33 -0
  64. package/dist/msg.d.ts.map +1 -0
  65. package/dist/plugins/coords.d.ts +18 -0
  66. package/dist/plugins/coords.d.ts.map +1 -0
  67. package/dist/plugins/experimental/annotations.js +164 -0
  68. package/dist/plugins/experimental/annotations.min.js +1 -0
  69. package/dist/plugins/experimental/crosshair.js +82 -0
  70. package/dist/plugins/experimental/crosshair.min.js +1 -0
  71. package/dist/plugins/experimental/minimap.js +190 -0
  72. package/dist/plugins/experimental/minimap.min.js +1 -0
  73. package/dist/plugins/experimental/range-selector.js +220 -0
  74. package/dist/plugins/experimental/range-selector.min.js +1 -0
  75. package/dist/plugins/experimental/ruler.js +434 -0
  76. package/dist/plugins/experimental/ruler.min.js +59 -0
  77. package/dist/plugins/experimental/stats.js +229 -0
  78. package/dist/plugins/experimental/stats.min.js +8 -0
  79. package/dist/plugins/experimental/threshold.js +96 -0
  80. package/dist/plugins/experimental/threshold.min.js +1 -0
  81. package/dist/plugins/experimental/tooltip-pin.js +177 -0
  82. package/dist/plugins/experimental/tooltip-pin.min.js +1 -0
  83. package/dist/plugins/experimental/watermark.js +76 -0
  84. package/dist/plugins/experimental/watermark.min.js +1 -0
  85. package/dist/plugins/hover.d.ts +15 -2
  86. package/dist/plugins/hover.d.ts.map +1 -1
  87. package/dist/plugins/hover.js +75 -14
  88. package/dist/plugins/hover.min.js +1 -1
  89. package/dist/plugins/labels-panel.d.ts +4 -0
  90. package/dist/plugins/labels-panel.d.ts.map +1 -0
  91. package/dist/plugins/labels-panel.js +122 -0
  92. package/dist/plugins/labels-panel.min.js +1 -0
  93. package/dist/plugins/labels.d.ts +17 -2
  94. package/dist/plugins/labels.d.ts.map +1 -1
  95. package/dist/plugins/labels.js +11 -99
  96. package/dist/plugins/labels.min.js +1 -1
  97. package/dist/plugins/legend.d.ts +16 -0
  98. package/dist/plugins/legend.d.ts.map +1 -0
  99. package/dist/plugins/legend.js +353 -0
  100. package/dist/plugins/legend.min.js +37 -0
  101. package/dist/plugins/shared.d.ts +7 -0
  102. package/dist/plugins/shared.d.ts.map +1 -0
  103. package/dist/plugins/zoom.d.ts +10 -2
  104. package/dist/plugins/zoom.d.ts.map +1 -1
  105. package/dist/plugins/zoom.js +63 -62
  106. package/dist/plugins/zoom.min.js +1 -1
  107. package/dist/types.d.ts +187 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/dist/types.js +0 -0
  110. package/dist/types.min.js +0 -0
  111. package/dist/worker-inline.d.ts +1 -1
  112. package/dist/worker-inline.d.ts.map +1 -1
  113. package/package.json +11 -11
  114. package/readme.md +54 -42
  115. package/dist/chunk-bgfkgcmg.js +0 -25
  116. package/dist/chunk-cj3zanvs.min.js +0 -2
@@ -0,0 +1,59 @@
1
+ import{j as w,k as R}from"../../chunk-cbydth3q.js";import{l as L}from"../../chunk-cvtt04m6.js";import{o as E}from"../../chunk-0eh4rzy9.js";import{q as v}from"../../chunk-50bcv2hw.js";import"../../chunk-wdfq2fpx.js";import"../../chunk-bbyt23tw.js";var P=new WeakMap,X=12;function A(e,n){let t=e.hasAttribute("data-visible");if(n===t)return;if(e.style.transform="",n)e.setAttribute("data-visible","");else e.removeAttribute("data-visible")}function I(){if(document.getElementById("chart-ruler-styles"))return;let e=document.createElement("style");e.id="chart-ruler-styles",e.textContent=`
2
+ @layer chartai.ruler {
3
+ .chart-ruler-wrapper {
4
+ position: absolute;
5
+ z-index: 1000;
6
+ pointer-events: none;
7
+ display: inline-block;
8
+ }
9
+ .chart-ruler-btn {
10
+ position: relative;
11
+ width: 28px;
12
+ height: 28px;
13
+ border-radius: 50%;
14
+ border: 1.5px solid var(--ruler-btn-border);
15
+ background: var(--ruler-btn-bg);
16
+ color: var(--ruler-btn-color);
17
+ z-index: 100;
18
+ cursor: pointer;
19
+ pointer-events: auto;
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ padding: 0;
24
+ box-shadow: 0 1px 4px rgba(0,0,0,0.18);
25
+ }
26
+ .chart-ruler-btn[data-active] {
27
+ --ruler-btn-border: var(--ruler-active-border);
28
+ --ruler-btn-bg: var(--ruler-active-bg);
29
+ --ruler-btn-color: var(--ruler-active-color);
30
+ }
31
+ .chart-ruler-clear {
32
+ position: absolute;
33
+ top: -6px;
34
+ right: -6px;
35
+ width: 18px;
36
+ height: 18px;
37
+ border-radius: 50%;
38
+ border: 1px solid oklch(from var(--ruler-active-color) calc(l * 0.7) c h / 1);
39
+ background: oklch(from var(--ruler-active-color) calc(l * 0.22) c h / 1);
40
+ color: var(--ruler-active-color);
41
+ z-index: 101;
42
+ cursor: pointer;
43
+ pointer-events: none;
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ padding: 0;
48
+ box-shadow: 0 1px 3px rgba(0,0,0,0.22);
49
+ opacity: 0;
50
+ transform: scale(0.5);
51
+ transition: opacity 0.18s ease, transform 0.18s cubic-bezier(0.4, 0, 1, 1);
52
+ }
53
+ .chart-ruler-clear[data-visible] {
54
+ opacity: 1;
55
+ transform: scale(1);
56
+ pointer-events: auto;
57
+ transition: opacity 0.22s ease, transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
58
+ }
59
+ }`,document.head.appendChild(e)}function Y(e,n){let t=e.style;if(n)t.setProperty("--ruler-btn-border","rgba(255,255,255,0.2)"),t.setProperty("--ruler-btn-bg","rgba(30,30,32,0.88)"),t.setProperty("--ruler-btn-color","rgba(200,200,200,0.9)"),t.setProperty("--ruler-active-border","rgba(255,200,50,0.8)"),t.setProperty("--ruler-active-bg","rgba(255,200,50,0.2)"),t.setProperty("--ruler-active-color","rgba(255,200,50,0.95)"),t.setProperty("--ruler-clear-border","rgba(255,255,255,0.18)"),t.setProperty("--ruler-clear-bg","rgba(30,30,32,0.95)"),t.setProperty("--ruler-clear-color","rgba(200,200,200,0.9)");else t.setProperty("--ruler-btn-border","rgba(0,0,0,0.15)"),t.setProperty("--ruler-btn-bg","rgba(255,255,255,0.92)"),t.setProperty("--ruler-btn-color","rgba(80,80,80,0.9)"),t.setProperty("--ruler-active-border","rgba(180,100,0,0.8)"),t.setProperty("--ruler-active-bg","rgba(180,100,0,0.12)"),t.setProperty("--ruler-active-color","rgba(180,100,0,0.95)"),t.setProperty("--ruler-clear-border","rgba(0,0,0,0.13)"),t.setProperty("--ruler-clear-bg","rgba(255,255,255,0.97)"),t.setProperty("--ruler-clear-color","rgba(80,80,80,0.9)")}function M(e,n="bottom-right"){let t=E,c=8;switch(e.style.removeProperty("top"),e.style.removeProperty("bottom"),e.style.removeProperty("left"),e.style.removeProperty("right"),n){case"top-left":e.style.top=`${t.top+8}px`,e.style.left=`${t.left+8}px`;break;case"top-right":e.style.top=`${t.top+8}px`,e.style.right=`${t.right+8}px`;break;case"bottom-right":e.style.bottom=`${t.bottom+8}px`,e.style.right=`${t.right+8}px`;break;default:e.style.bottom=`${t.bottom+8}px`,e.style.left=`${t.left+8}px`}}function x(e,n,t,c,h,p,g){e.font=`500 11px ${p}`;let r=e.measureText(n).width+16,o=20,s=t-r/2,d=c-o/2;e.beginPath(),e.roundRect(s,d,r,o,5),e.fillStyle=g?"rgba(20,20,22,0.90)":"rgba(255,255,255,0.95)",e.fill(),e.strokeStyle=h,e.lineWidth=1.5,e.stroke(),e.fillStyle=h,e.textAlign="center",e.textBaseline="middle",e.fillText(n,t,c)}function C(e,n,t,c,h){e.beginPath(),e.arc(n,t,5,0,Math.PI*2),e.fillStyle=c,e.fill(),e.strokeStyle=h?"rgba(0,0,0,0.5)":"rgba(255,255,255,0.8)",e.lineWidth=1.5,e.stroke()}function B(e,n,t,c,h,p,g,u,r,o,s,d){let a=w(n.dataX,n.dataY,h,p,g),i=w(t.dataX,t.dataY,h,p,g);e.save(),e.strokeStyle=u,e.lineWidth=1.5,e.setLineDash([5,4]);let y=6;if(c==="x"){let l=(a.y+i.y)/2;e.beginPath(),e.moveTo(a.x,l),e.lineTo(i.x,l),e.stroke(),e.setLineDash([]),e.beginPath(),e.moveTo(a.x,l-y),e.lineTo(a.x,l+y),e.moveTo(i.x,l-y),e.lineTo(i.x,l+y),e.stroke(),C(e,a.x,a.y,u,d),C(e,i.x,i.y,u,d);let b=(a.x+i.x)/2,f=l-16,m=Math.abs(t.dataX-n.dataX);x(e,`ΔX: ${r(m)}`,b,f,u,s,d)}else if(c==="y"){let l=(a.x+i.x)/2;e.beginPath(),e.moveTo(l,a.y),e.lineTo(l,i.y),e.stroke(),e.setLineDash([]),e.beginPath(),e.moveTo(l-y,a.y),e.lineTo(l+y,a.y),e.moveTo(l-y,i.y),e.lineTo(l+y,i.y),e.stroke(),C(e,a.x,a.y,u,d),C(e,i.x,i.y,u,d);let b=l+20,f=(a.y+i.y)/2,m=Math.abs(t.dataY-n.dataY);x(e,`ΔY: ${o(m)}`,b,f,u,s,d)}else{e.beginPath(),e.moveTo(a.x,a.y),e.lineTo(i.x,i.y),e.stroke(),C(e,a.x,a.y,u,d),C(e,i.x,i.y,u,d);let l=(a.x+i.x)/2,b=(a.y+i.y)/2-18,f=Math.abs(t.dataX-n.dataX),m=Math.abs(t.dataY-n.dataY);x(e,`ΔX: ${r(f)} ΔY: ${o(m)}`,l,b,u,s,d)}e.restore()}var N={name:"ruler",install(e,n){I();let t=new AbortController,c=e.config,h=v.isDark,p=document.createElement("div");p.className="chart-ruler-wrapper",M(p,c.rulerPosition),Y(p,h);let g=document.createElement("button");g.type="button",g.className="chart-ruler-btn",g.title="Toggle ruler tool",g.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="4.5" width="12" height="5" rx="1" stroke="currentColor" stroke-width="1.3"/><line x1="3.5" y1="4.5" x2="3.5" y2="7" stroke="currentColor" stroke-width="1.2"/><line x1="5.5" y1="4.5" x2="5.5" y2="6" stroke="currentColor" stroke-width="1.2"/><line x1="7" y1="4.5" x2="7" y2="7" stroke="currentColor" stroke-width="1.2"/><line x1="8.5" y1="4.5" x2="8.5" y2="6" stroke="currentColor" stroke-width="1.2"/><line x1="10.5" y1="4.5" x2="10.5" y2="7" stroke="currentColor" stroke-width="1.2"/></svg>';let u=document.createElement("button");u.type="button",u.className="chart-ruler-clear",u.title="Clear all rulers",u.innerHTML='<svg width="5" height="5" viewBox="0 0 6 6" fill="none" xmlns="http://www.w3.org/2000/svg"><line x1="1" y1="1" x2="5" y2="5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><line x1="5" y1="1" x2="1" y2="5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',p.appendChild(g),p.appendChild(u),n.appendChild(p);let r={rulers:[],pending:null,cursorDataX:0,cursorDataY:0,active:!1,justToggledButton:!1,abort:t,button:g,clearBtn:u,wrapper:p};P.set(e,r),g.addEventListener("pointerdown",(o)=>{if(o.stopPropagation(),o.stopImmediatePropagation(),o.preventDefault(),r.active=!r.active,!r.active)r.pending=null;if(r.justToggledButton=!0,r.active)g.dataset.active="";else delete g.dataset.active;v.drawChart(e)},{signal:t.signal}),u.addEventListener("pointerdown",(o)=>{o.stopPropagation(),o.stopImmediatePropagation(),o.preventDefault(),u.style.transform="scale(0.78)",r.rulers=[],r.pending=null,r.justToggledButton=!0,v.drawChart(e)},{signal:t.signal}),u.addEventListener("click",(o)=>{o.stopPropagation(),o.stopImmediatePropagation(),o.preventDefault()},{signal:t.signal}),n.addEventListener("mousemove",(o)=>{let s=n.getBoundingClientRect(),{x:d,y:a}=R(o.clientX-s.left,o.clientY-s.top,e,s.width,s.height);if(r.cursorDataX=d,r.cursorDataY=a,r.active||r.pending!==null)v.drawChart(e);o.preventDefault()},{signal:t.signal}),n.addEventListener("click",(o)=>{if(!r.active)return;if(r.justToggledButton){r.justToggledButton=!1;return}if(e.dragging)return;o.preventDefault();let s=n.getBoundingClientRect(),d=o.clientX-s.left,a=o.clientY-s.top,{x:i,y}=R(d,a,e,s.width,s.height);for(let l=r.rulers.length-1;l>=0;l--){let b=r.rulers[l],f=w(b.a.dataX,b.a.dataY,e,s.width,s.height),m=w(b.b.dataX,b.b.dataY,e,s.width,s.height),k=Math.hypot(f.x-d,f.y-a),T=Math.hypot(m.x-d,m.y-a);if(k<=X||T<=X){r.rulers.splice(l,1),v.drawChart(e);return}}if(r.pending===null)r.pending={dataX:i,dataY:y};else{let l=e.config.rulerMax??10;if(r.rulers.length>=l)r.rulers.shift();r.rulers.push({a:r.pending,b:{dataX:i,dataY:y}}),r.pending=null,v.drawChart(e)}},{signal:t.signal}),n.addEventListener("contextmenu",(o)=>{if(o.preventDefault(),r.pending!==null)r.pending=null;else{let s=n.getBoundingClientRect(),d=o.clientX-s.left,a=o.clientY-s.top,i=-1,y=1/0;for(let l=0;l<r.rulers.length;l++){let b=r.rulers[l],f=w(b.a.dataX,b.a.dataY,e,s.width,s.height),m=w(b.b.dataX,b.b.dataY,e,s.width,s.height),k=Math.hypot(f.x-d,f.y-a),T=Math.hypot(m.x-d,m.y-a),D=Math.min(k,T);if(D<y)y=D,i=l}if(i!==-1)r.rulers.splice(i,1)}v.drawChart(e)},{signal:t.signal}),window.addEventListener("keydown",(o)=>{if(o.key==="Escape"&&r.active)r.pending=null,v.drawChart(e)},{signal:t.signal})},afterDraw(e,n){let t=P.get(n);if(!t)return;let{width:c,height:h}=n,p=v.isDark,g=n.config,u=g.rulerAxis??"x",r=g.rulerColor??(p?"rgba(255,200,50,0.9)":"rgba(180,100,0,0.9)"),o=g.formatX??String,s=g.formatY??String,d=g.fontFamily??L;if(M(t.wrapper,g.rulerPosition),Y(t.wrapper,p),t.active)t.button.dataset.active="";else delete t.button.dataset.active;A(t.clearBtn,t.rulers.length>0),e.save();for(let a of t.rulers)B(e,a.a,a.b,u,n,c,h,r,o,s,d,p);if(t.pending!==null){let a={dataX:t.cursorDataX,dataY:t.cursorDataY};B(e,t.pending,a,u,n,c,h,r,o,s,d,p);let i=w(t.cursorDataX,t.cursorDataY,n,c,h);e.save(),e.beginPath(),e.arc(i.x,i.y,5,0,Math.PI*2),e.strokeStyle=r,e.lineWidth=1.5,e.stroke(),e.restore()}e.restore()},uninstall(e){let n=P.get(e);if(!n)return;n.abort.abort(),n.wrapper.remove(),P.delete(e)}};export{N as rulerPlugin};
@@ -0,0 +1,229 @@
1
+ import {
2
+ DEFAULT_FONT
3
+ } from "../../chunk-1ngxm8t2.js";
4
+ import {
5
+ MARGIN
6
+ } from "../../chunk-831dem4f.js";
7
+ import {
8
+ ChartManager
9
+ } from "../../chunk-n8ew0z0e.js";
10
+ import"../../chunk-93yrr7er.js";
11
+ import"../../chunk-5gtx3pza.js";
12
+
13
+ // src/plugins/experimental/stats.ts
14
+ var states = new WeakMap;
15
+ function computeStats(values) {
16
+ if (values.length === 0)
17
+ return null;
18
+ let min = Infinity, max = -Infinity, sum = 0;
19
+ for (const v of values) {
20
+ if (v < min)
21
+ min = v;
22
+ if (v > max)
23
+ max = v;
24
+ sum += v;
25
+ }
26
+ const mean = sum / values.length;
27
+ let variance = 0;
28
+ for (const v of values) {
29
+ const d = v - mean;
30
+ variance += d * d;
31
+ }
32
+ const stddev = Math.sqrt(variance / values.length);
33
+ return { min, max, mean, stddev, count: values.length };
34
+ }
35
+ function updateOverlay(chart, state) {
36
+ const { overlay, header, body } = state;
37
+ const dark = ChartManager.isDark;
38
+ const cfg = chart.config;
39
+ const bgColor = cfg.bgColor ?? (dark ? [0.11, 0.11, 0.12] : [0.98, 0.98, 0.98]);
40
+ const rgb = bgColor.map((c) => Math.round(c * 255)).join(",");
41
+ const panelBg = dark ? `rgba(${rgb},0.92)` : "rgba(255,255,255,0.95)";
42
+ const border = dark ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.10)";
43
+ const text = cfg.textColor ?? (dark ? "#c0c0c0" : "#333333");
44
+ const muted = dark ? "#777" : "#aaa";
45
+ const font = cfg.fontFamily ?? DEFAULT_FONT;
46
+ const precision = cfg.statsPrecision ?? 2;
47
+ const fmt = cfg.formatValue ?? ((n) => n.toFixed(precision));
48
+ const pos = cfg.statsPosition ?? "top-left";
49
+ overlay.style.display = "block";
50
+ overlay.style.position = "absolute";
51
+ overlay.style.pointerEvents = "auto";
52
+ overlay.style.zIndex = "15";
53
+ overlay.style.background = panelBg;
54
+ overlay.style.border = `1px solid ${border}`;
55
+ overlay.style.borderRadius = "6px";
56
+ overlay.style.padding = "7px 10px";
57
+ overlay.style.fontFamily = font;
58
+ overlay.style.fontSize = "11px";
59
+ overlay.style.color = text;
60
+ overlay.style.minWidth = "100px";
61
+ overlay.style.userSelect = "none";
62
+ if (!state.dragOffset) {
63
+ const m = MARGIN;
64
+ const pad = 6;
65
+ if (state.customPos) {
66
+ overlay.style.top = `${state.customPos.y}px`;
67
+ overlay.style.left = `${state.customPos.x}px`;
68
+ overlay.style.right = "auto";
69
+ overlay.style.bottom = "auto";
70
+ } else {
71
+ overlay.style.right = "auto";
72
+ overlay.style.bottom = "auto";
73
+ overlay.style.top = "auto";
74
+ overlay.style.left = "auto";
75
+ if (pos === "top-left") {
76
+ overlay.style.top = `${m.top + pad}px`;
77
+ overlay.style.left = `${m.left + pad}px`;
78
+ }
79
+ if (pos === "top-right") {
80
+ overlay.style.top = `${m.top + pad}px`;
81
+ overlay.style.right = `${m.right + pad}px`;
82
+ overlay.style.left = "auto";
83
+ }
84
+ if (pos === "bottom-left") {
85
+ overlay.style.bottom = `${m.bottom + pad}px`;
86
+ overlay.style.left = `${m.left + pad}px`;
87
+ overlay.style.top = "auto";
88
+ }
89
+ if (pos === "bottom-right") {
90
+ overlay.style.bottom = `${m.bottom + pad}px`;
91
+ overlay.style.right = `${m.right + pad}px`;
92
+ overlay.style.top = "auto";
93
+ overlay.style.left = "auto";
94
+ }
95
+ }
96
+ }
97
+ if (state.collapsed) {
98
+ header.innerHTML = `<span style="color:${muted};font-size:10px;font-weight:600;letter-spacing:.04em;cursor:grab">STATS &#9660;</span>`;
99
+ body.innerHTML = "";
100
+ return;
101
+ }
102
+ const { bounds: b, view: v } = chart;
103
+ const fullX = b.maxX - b.minX;
104
+ const visMinX = b.minX + v.panX * fullX;
105
+ const visMaxX = visMinX + fullX / v.zoomX;
106
+ const allValues = [];
107
+ for (const s of chart.series) {
108
+ let lo = 0, hi = s.rawX.length;
109
+ while (lo < hi) {
110
+ const mid = lo + hi >> 1;
111
+ if (s.rawX[mid] < visMinX)
112
+ lo = mid + 1;
113
+ else
114
+ hi = mid;
115
+ }
116
+ const start = lo;
117
+ lo = 0;
118
+ hi = s.rawX.length;
119
+ while (lo < hi) {
120
+ const mid = lo + hi >> 1;
121
+ if (s.rawX[mid] <= visMaxX)
122
+ lo = mid + 1;
123
+ else
124
+ hi = mid;
125
+ }
126
+ const end = lo;
127
+ for (let i = start;i < end; i++)
128
+ allValues.push(s.rawY[i]);
129
+ }
130
+ const stats = computeStats(allValues);
131
+ if (!stats) {
132
+ overlay.style.display = "none";
133
+ return;
134
+ }
135
+ header.innerHTML = `<div style="margin-bottom:4px"><span style="color:${muted};font-size:10px;font-weight:600;letter-spacing:.04em;cursor:grab">STATS &#9650;</span></div>`;
136
+ body.innerHTML = `
137
+ <div style="display:grid;grid-template-columns:auto auto;gap:1px 10px">
138
+ <span style="color:${muted}">min</span><span>${fmt(stats.min)}</span>
139
+ <span style="color:${muted}">max</span><span>${fmt(stats.max)}</span>
140
+ <span style="color:${muted}">avg</span><span>${fmt(stats.mean)}</span>
141
+ <span style="color:${muted}">&#963;</span><span>${fmt(stats.stddev)}</span>
142
+ <span style="color:${muted}">n</span><span>${stats.count.toLocaleString()}</span>
143
+ </div>`;
144
+ }
145
+ var statsPlugin = {
146
+ name: "stats",
147
+ install(chart, el) {
148
+ const ac = new AbortController;
149
+ const overlay = document.createElement("div");
150
+ overlay.style.cssText = "position:absolute;pointer-events:auto;z-index:15;";
151
+ const header = document.createElement("div");
152
+ const body = document.createElement("div");
153
+ overlay.appendChild(header);
154
+ overlay.appendChild(body);
155
+ el.appendChild(overlay);
156
+ const state = { overlay, header, body, collapsed: false, abort: ac, dragOffset: null, customPos: null, tiltAngle: 0, tiltVelocity: 0, tiltRafId: null };
157
+ states.set(chart, state);
158
+ header.addEventListener("click", () => {
159
+ state.collapsed = !state.collapsed;
160
+ updateOverlay(chart, state);
161
+ }, { signal: ac.signal });
162
+ overlay.addEventListener("pointerdown", (e) => {
163
+ e.stopPropagation();
164
+ if (!state.customPos) {
165
+ state.customPos = { x: overlay.offsetLeft, y: overlay.offsetTop };
166
+ overlay.style.left = state.customPos.x + "px";
167
+ overlay.style.top = state.customPos.y + "px";
168
+ overlay.style.right = "auto";
169
+ overlay.style.bottom = "auto";
170
+ }
171
+ state.dragOffset = { x: 0, y: 0 };
172
+ if (state.tiltRafId !== null) {
173
+ cancelAnimationFrame(state.tiltRafId);
174
+ state.tiltRafId = null;
175
+ }
176
+ overlay.setPointerCapture(e.pointerId);
177
+ overlay.style.cursor = "grabbing";
178
+ }, { signal: ac.signal });
179
+ overlay.addEventListener("pointermove", (e) => {
180
+ if (!state.dragOffset || !state.customPos)
181
+ return;
182
+ const x = Math.max(0, Math.min(state.customPos.x + e.movementX, el.clientWidth - overlay.offsetWidth));
183
+ const y = Math.max(0, Math.min(state.customPos.y + e.movementY, el.clientHeight - overlay.offsetHeight));
184
+ state.customPos = { x, y };
185
+ overlay.style.left = x + "px";
186
+ overlay.style.top = y + "px";
187
+ state.tiltVelocity = state.tiltVelocity * 0.6 + e.movementX * 0.4;
188
+ state.tiltAngle = Math.max(-15, Math.min(15, state.tiltVelocity * 1.5));
189
+ overlay.style.transform = `rotate(${state.tiltAngle}deg)`;
190
+ }, { signal: ac.signal });
191
+ overlay.addEventListener("pointerup", () => {
192
+ state.dragOffset = null;
193
+ overlay.style.cursor = "";
194
+ const decayTilt = () => {
195
+ state.tiltAngle *= 0.78;
196
+ state.tiltVelocity *= 0.78;
197
+ if (Math.abs(state.tiltAngle) > 0.05) {
198
+ overlay.style.transform = `rotate(${state.tiltAngle}deg)`;
199
+ state.tiltRafId = requestAnimationFrame(decayTilt);
200
+ } else {
201
+ state.tiltAngle = 0;
202
+ state.tiltVelocity = 0;
203
+ overlay.style.transform = "";
204
+ state.tiltRafId = null;
205
+ }
206
+ };
207
+ state.tiltRafId = requestAnimationFrame(decayTilt);
208
+ }, { signal: ac.signal });
209
+ },
210
+ afterDraw(_, chart) {
211
+ const state = states.get(chart);
212
+ if (!state)
213
+ return;
214
+ updateOverlay(chart, state);
215
+ },
216
+ uninstall(chart) {
217
+ const state = states.get(chart);
218
+ if (state) {
219
+ if (state.tiltRafId !== null)
220
+ cancelAnimationFrame(state.tiltRafId);
221
+ state.abort.abort();
222
+ state.overlay.remove();
223
+ states.delete(chart);
224
+ }
225
+ }
226
+ };
227
+ export {
228
+ statsPlugin
229
+ };
@@ -0,0 +1,8 @@
1
+ import{l as V}from"../../chunk-cvtt04m6.js";import{o as N}from"../../chunk-0eh4rzy9.js";import{q as F}from"../../chunk-50bcv2hw.js";import"../../chunk-wdfq2fpx.js";import"../../chunk-bbyt23tw.js";var I=new WeakMap;function p(P){if(P.length===0)return null;let H=1/0,j=-1/0,z=0;for(let J of P){if(J<H)H=J;if(J>j)j=J;z+=J}let Z=z/P.length,Q=0;for(let J of P){let $=J-Z;Q+=$*$}let q=Math.sqrt(Q/P.length);return{min:H,max:j,mean:Z,stddev:q,count:P.length}}function A(P,H){let{overlay:j,header:z,body:Z}=H,Q=F.isDark,q=P.config,$=(q.bgColor??(Q?[0.11,0.11,0.12]:[0.98,0.98,0.98])).map((K)=>Math.round(K*255)).join(","),D=Q?`rgba(${$},0.92)`:"rgba(255,255,255,0.95)",O=Q?"rgba(255,255,255,0.14)":"rgba(0,0,0,0.10)",T=q.textColor??(Q?"#c0c0c0":"#333333"),w=Q?"#777":"#aaa",k=q.fontFamily??V,M=q.statsPrecision??2,E=q.formatValue??((K)=>K.toFixed(M)),G=q.statsPosition??"top-left";if(j.style.display="block",j.style.position="absolute",j.style.pointerEvents="auto",j.style.zIndex="15",j.style.background=D,j.style.border=`1px solid ${O}`,j.style.borderRadius="6px",j.style.padding="7px 10px",j.style.fontFamily=k,j.style.fontSize="11px",j.style.color=T,j.style.minWidth="100px",j.style.userSelect="none",!H.dragOffset){let K=N,Y=6;if(H.customPos)j.style.top=`${H.customPos.y}px`,j.style.left=`${H.customPos.x}px`,j.style.right="auto",j.style.bottom="auto";else{if(j.style.right="auto",j.style.bottom="auto",j.style.top="auto",j.style.left="auto",G==="top-left")j.style.top=`${K.top+6}px`,j.style.left=`${K.left+6}px`;if(G==="top-right")j.style.top=`${K.top+6}px`,j.style.right=`${K.right+6}px`,j.style.left="auto";if(G==="bottom-left")j.style.bottom=`${K.bottom+6}px`,j.style.left=`${K.left+6}px`,j.style.top="auto";if(G==="bottom-right")j.style.bottom=`${K.bottom+6}px`,j.style.right=`${K.right+6}px`,j.style.top="auto",j.style.left="auto"}}if(H.collapsed){z.innerHTML=`<span style="color:${w};font-size:10px;font-weight:600;letter-spacing:.04em;cursor:grab">STATS &#9660;</span>`,Z.innerHTML="";return}let{bounds:L,view:R}=P,S=L.maxX-L.minX,U=L.minX+R.panX*S,X=U+S/R.zoomX,_=[];for(let K of P.series){let Y=0,B=K.rawX.length;while(Y<B){let W=Y+B>>1;if(K.rawX[W]<U)Y=W+1;else B=W}let x=Y;Y=0,B=K.rawX.length;while(Y<B){let W=Y+B>>1;if(K.rawX[W]<=X)Y=W+1;else B=W}let b=Y;for(let W=x;W<b;W++)_.push(K.rawY[W])}let C=p(_);if(!C){j.style.display="none";return}z.innerHTML=`<div style="margin-bottom:4px"><span style="color:${w};font-size:10px;font-weight:600;letter-spacing:.04em;cursor:grab">STATS &#9650;</span></div>`,Z.innerHTML=`
2
+ <div style="display:grid;grid-template-columns:auto auto;gap:1px 10px">
3
+ <span style="color:${w}">min</span><span>${E(C.min)}</span>
4
+ <span style="color:${w}">max</span><span>${E(C.max)}</span>
5
+ <span style="color:${w}">avg</span><span>${E(C.mean)}</span>
6
+ <span style="color:${w}">&#963;</span><span>${E(C.stddev)}</span>
7
+ <span style="color:${w}">n</span><span>${C.count.toLocaleString()}</span>
8
+ </div>`}var u={name:"stats",install(P,H){let j=new AbortController,z=document.createElement("div");z.style.cssText="position:absolute;pointer-events:auto;z-index:15;";let Z=document.createElement("div"),Q=document.createElement("div");z.appendChild(Z),z.appendChild(Q),H.appendChild(z);let q={overlay:z,header:Z,body:Q,collapsed:!1,abort:j,dragOffset:null,customPos:null,tiltAngle:0,tiltVelocity:0,tiltRafId:null};I.set(P,q),Z.addEventListener("click",()=>{q.collapsed=!q.collapsed,A(P,q)},{signal:j.signal}),z.addEventListener("pointerdown",(J)=>{if(J.stopPropagation(),!q.customPos)q.customPos={x:z.offsetLeft,y:z.offsetTop},z.style.left=q.customPos.x+"px",z.style.top=q.customPos.y+"px",z.style.right="auto",z.style.bottom="auto";if(q.dragOffset={x:0,y:0},q.tiltRafId!==null)cancelAnimationFrame(q.tiltRafId),q.tiltRafId=null;z.setPointerCapture(J.pointerId),z.style.cursor="grabbing"},{signal:j.signal}),z.addEventListener("pointermove",(J)=>{if(!q.dragOffset||!q.customPos)return;let $=Math.max(0,Math.min(q.customPos.x+J.movementX,H.clientWidth-z.offsetWidth)),D=Math.max(0,Math.min(q.customPos.y+J.movementY,H.clientHeight-z.offsetHeight));q.customPos={x:$,y:D},z.style.left=$+"px",z.style.top=D+"px",q.tiltVelocity=q.tiltVelocity*0.6+J.movementX*0.4,q.tiltAngle=Math.max(-15,Math.min(15,q.tiltVelocity*1.5)),z.style.transform=`rotate(${q.tiltAngle}deg)`},{signal:j.signal}),z.addEventListener("pointerup",()=>{q.dragOffset=null,z.style.cursor="";let J=()=>{if(q.tiltAngle*=0.78,q.tiltVelocity*=0.78,Math.abs(q.tiltAngle)>0.05)z.style.transform=`rotate(${q.tiltAngle}deg)`,q.tiltRafId=requestAnimationFrame(J);else q.tiltAngle=0,q.tiltVelocity=0,z.style.transform="",q.tiltRafId=null};q.tiltRafId=requestAnimationFrame(J)},{signal:j.signal})},afterDraw(P,H){let j=I.get(H);if(!j)return;A(H,j)},uninstall(P){let H=I.get(P);if(H){if(H.tiltRafId!==null)cancelAnimationFrame(H.tiltRafId);H.abort.abort(),H.overlay.remove(),I.delete(P)}}};export{u as statsPlugin};
@@ -0,0 +1,96 @@
1
+ import {
2
+ dataToScreen
3
+ } from "../../chunk-mmsy3yqt.js";
4
+ import {
5
+ DEFAULT_FONT
6
+ } from "../../chunk-1ngxm8t2.js";
7
+ import {
8
+ MARGIN
9
+ } from "../../chunk-831dem4f.js";
10
+ import {
11
+ ChartManager
12
+ } from "../../chunk-n8ew0z0e.js";
13
+ import"../../chunk-93yrr7er.js";
14
+ import"../../chunk-5gtx3pza.js";
15
+
16
+ // src/plugins/experimental/threshold.ts
17
+ var thresholdPlugin = {
18
+ name: "threshold",
19
+ beforeDraw(ctx, chart) {
20
+ const cfg = chart.config;
21
+ const thresholds = cfg.thresholds;
22
+ if (!thresholds?.length)
23
+ return;
24
+ const w = chart.width;
25
+ const h = chart.height;
26
+ const m = MARGIN;
27
+ for (const threshold of thresholds) {
28
+ if (!threshold.fillAbove && !threshold.fillBelow)
29
+ continue;
30
+ const sy = dataToScreen(0, threshold.y, chart, w, h).y;
31
+ ctx.save();
32
+ ctx.beginPath();
33
+ ctx.rect(m.left, m.top, w - m.left - m.right, h - m.top - m.bottom);
34
+ ctx.clip();
35
+ if (threshold.fillAbove) {
36
+ ctx.fillStyle = threshold.fillAbove;
37
+ ctx.fillRect(m.left, m.top, w - m.left - m.right, sy - m.top);
38
+ }
39
+ if (threshold.fillBelow) {
40
+ ctx.fillStyle = threshold.fillBelow;
41
+ ctx.fillRect(m.left, sy, w - m.left - m.right, h - m.bottom - sy);
42
+ }
43
+ ctx.restore();
44
+ }
45
+ },
46
+ afterDraw(ctx, chart) {
47
+ const cfg = chart.config;
48
+ const thresholds = cfg.thresholds;
49
+ if (!thresholds?.length)
50
+ return;
51
+ const w = chart.width;
52
+ const h = chart.height;
53
+ const m = MARGIN;
54
+ const dark = ChartManager.isDark;
55
+ const fontFamily = cfg.fontFamily ?? DEFAULT_FONT;
56
+ for (const threshold of thresholds) {
57
+ const sy = dataToScreen(0, threshold.y, chart, w, h).y;
58
+ if (sy < m.top || sy > h - m.bottom)
59
+ continue;
60
+ ctx.save();
61
+ ctx.strokeStyle = threshold.color;
62
+ ctx.lineWidth = threshold.lineWidth ?? 1.5;
63
+ ctx.setLineDash(threshold.dash ?? [5, 3]);
64
+ ctx.beginPath();
65
+ ctx.moveTo(m.left, sy);
66
+ ctx.lineTo(w - m.right, sy);
67
+ ctx.stroke();
68
+ ctx.restore();
69
+ if (threshold.label) {
70
+ ctx.save();
71
+ ctx.font = `600 10px ${fontFamily}`;
72
+ const tw = ctx.measureText(threshold.label).width;
73
+ const pw = tw + 10;
74
+ const ph = 17;
75
+ const px = w - m.right - pw - 4;
76
+ const py = sy - ph / 2;
77
+ ctx.beginPath();
78
+ ctx.roundRect(px, py, pw, ph, 3);
79
+ ctx.fillStyle = dark ? "rgba(20,20,22,0.88)" : "rgba(255,255,255,0.92)";
80
+ ctx.fill();
81
+ ctx.strokeStyle = threshold.color;
82
+ ctx.lineWidth = 1;
83
+ ctx.setLineDash([]);
84
+ ctx.stroke();
85
+ ctx.fillStyle = threshold.color;
86
+ ctx.textAlign = "left";
87
+ ctx.textBaseline = "middle";
88
+ ctx.fillText(threshold.label, px + 5, sy);
89
+ ctx.restore();
90
+ }
91
+ }
92
+ }
93
+ };
94
+ export {
95
+ thresholdPlugin
96
+ };
@@ -0,0 +1 @@
1
+ import{j as d}from"../../chunk-cbydth3q.js";import{l as C}from"../../chunk-cvtt04m6.js";import{o as g}from"../../chunk-0eh4rzy9.js";import{q as y}from"../../chunk-50bcv2hw.js";import"../../chunk-wdfq2fpx.js";import"../../chunk-bbyt23tw.js";var S={name:"threshold",beforeDraw(e,l){let h=l.config.thresholds;if(!h?.length)return;let{width:r,height:n}=l,o=g;for(let t of h){if(!t.fillAbove&&!t.fillBelow)continue;let f=d(0,t.y,l,r,n).y;if(e.save(),e.beginPath(),e.rect(o.left,o.top,r-o.left-o.right,n-o.top-o.bottom),e.clip(),t.fillAbove)e.fillStyle=t.fillAbove,e.fillRect(o.left,o.top,r-o.left-o.right,f-o.top);if(t.fillBelow)e.fillStyle=t.fillBelow,e.fillRect(o.left,f,r-o.left-o.right,n-o.bottom-f);e.restore()}},afterDraw(e,l){let a=l.config,h=a.thresholds;if(!h?.length)return;let{width:r,height:n}=l,o=g,t=y.isDark,f=a.fontFamily??C;for(let i of h){let s=d(0,i.y,l,r,n).y;if(s<o.top||s>n-o.bottom)continue;if(e.save(),e.strokeStyle=i.color,e.lineWidth=i.lineWidth??1.5,e.setLineDash(i.dash??[5,3]),e.beginPath(),e.moveTo(o.left,s),e.lineTo(r-o.right,s),e.stroke(),e.restore(),i.label){e.save(),e.font=`600 10px ${f}`;let m=e.measureText(i.label).width+10,p=17,b=r-o.right-m-4,u=s-p/2;e.beginPath(),e.roundRect(b,u,m,p,3),e.fillStyle=t?"rgba(20,20,22,0.88)":"rgba(255,255,255,0.92)",e.fill(),e.strokeStyle=i.color,e.lineWidth=1,e.setLineDash([]),e.stroke(),e.fillStyle=i.color,e.textAlign="left",e.textBaseline="middle",e.fillText(i.label,b+5,s),e.restore()}}}};export{S as thresholdPlugin};
@@ -0,0 +1,177 @@
1
+ import {
2
+ dataToScreen,
3
+ screenToData
4
+ } from "../../chunk-mmsy3yqt.js";
5
+ import {
6
+ DEFAULT_FONT
7
+ } from "../../chunk-1ngxm8t2.js";
8
+ import {
9
+ MARGIN
10
+ } from "../../chunk-831dem4f.js";
11
+ import {
12
+ ChartManager
13
+ } from "../../chunk-n8ew0z0e.js";
14
+ import"../../chunk-93yrr7er.js";
15
+ import"../../chunk-5gtx3pza.js";
16
+
17
+ // src/plugins/experimental/tooltip-pin.ts
18
+ var states = new WeakMap;
19
+ var MAX_PIN_PX = 30;
20
+ function findNearestPin(chart, screenX, screenY, width, height) {
21
+ if (chart.series.length === 0)
22
+ return null;
23
+ const { x: dataX, y: dataY } = screenToData(screenX, screenY, chart, width, height);
24
+ let bestSi = -1;
25
+ let bestIdx = -1;
26
+ let bestDx = Infinity;
27
+ let bestDy = Infinity;
28
+ for (let s = 0;s < chart.series.length; s++) {
29
+ const sr2 = chart.series[s];
30
+ const n = sr2.rawX.length;
31
+ if (n === 0)
32
+ continue;
33
+ let lo = 0, hi = n - 1;
34
+ while (lo < hi) {
35
+ const mid = lo + hi >> 1;
36
+ if (sr2.rawX[mid] < dataX)
37
+ lo = mid + 1;
38
+ else
39
+ hi = mid;
40
+ }
41
+ let idx = lo;
42
+ if (lo > 0 && Math.abs(sr2.rawX[lo - 1] - dataX) < Math.abs(sr2.rawX[lo] - dataX)) {
43
+ idx = lo - 1;
44
+ }
45
+ const dx = Math.abs(sr2.rawX[idx] - dataX);
46
+ const dy = Math.abs(sr2.rawY[idx] - dataY);
47
+ if (dx < bestDx || dx === bestDx && dy < bestDy) {
48
+ bestDx = dx;
49
+ bestDy = dy;
50
+ bestSi = s;
51
+ bestIdx = idx;
52
+ }
53
+ }
54
+ if (bestSi === -1)
55
+ return null;
56
+ const sr = chart.series[bestSi];
57
+ const { x: candidateSx, y: candidateSy } = dataToScreen(sr.rawX[bestIdx], sr.rawY[bestIdx], chart, width, height);
58
+ if (Math.hypot(candidateSx - screenX, candidateSy - screenY) > MAX_PIN_PX)
59
+ return null;
60
+ return {
61
+ dataX: sr.rawX[bestIdx],
62
+ dataY: sr.rawY[bestIdx],
63
+ seriesIndex: bestSi,
64
+ seriesLabel: sr.label,
65
+ color: sr.color
66
+ };
67
+ }
68
+ var tooltipPinPlugin = {
69
+ name: "tooltip-pin",
70
+ install(chart, el) {
71
+ const ac = new AbortController;
72
+ const state = { pins: [], abort: ac };
73
+ states.set(chart, state);
74
+ el.addEventListener("click", (e) => {
75
+ if (chart.dragging)
76
+ return;
77
+ const r = el.getBoundingClientRect();
78
+ const sx = e.clientX - r.left;
79
+ const sy = e.clientY - r.top;
80
+ for (let i = state.pins.length - 1;i >= 0; i--) {
81
+ const pin = state.pins[i];
82
+ const { x: pinSx, y: pinSy } = dataToScreen(pin.dataX, pin.dataY, chart, r.width, r.height);
83
+ if (Math.hypot(pinSx - sx, pinSy - sy) < 20) {
84
+ state.pins.splice(i, 1);
85
+ e.preventDefault();
86
+ ChartManager.drawChart(chart);
87
+ return;
88
+ }
89
+ }
90
+ const nearest = findNearestPin(chart, sx, sy, r.width, r.height);
91
+ if (!nearest)
92
+ return;
93
+ e.preventDefault();
94
+ const cfg = chart.config;
95
+ const maxPins = cfg.pinMax ?? 5;
96
+ if (state.pins.length >= maxPins)
97
+ state.pins.shift();
98
+ state.pins.push(nearest);
99
+ ChartManager.drawChart(chart);
100
+ }, { signal: ac.signal });
101
+ },
102
+ afterDraw(ctx, chart) {
103
+ const state = states.get(chart);
104
+ if (!state || state.pins.length === 0)
105
+ return;
106
+ const w = chart.width;
107
+ const h = chart.height;
108
+ const m = MARGIN;
109
+ const dark = ChartManager.isDark;
110
+ const cfg = chart.config;
111
+ const formatX = cfg.formatX ?? String;
112
+ const formatY = cfg.formatY ?? String;
113
+ const fontFamily = cfg.fontFamily ?? DEFAULT_FONT;
114
+ ctx.save();
115
+ ctx.font = `500 10px ${fontFamily}`;
116
+ for (const pin of state.pins) {
117
+ const { x: pinSx, y: pinSy } = dataToScreen(pin.dataX, pin.dataY, chart, w, h);
118
+ const colRgb = `${Math.round(pin.color.r * 255)},${Math.round(pin.color.g * 255)},${Math.round(pin.color.b * 255)}`;
119
+ const col = `rgb(${colRgb})`;
120
+ ctx.save();
121
+ ctx.setLineDash([4, 3]);
122
+ ctx.strokeStyle = `rgba(${colRgb},0.4)`;
123
+ ctx.lineWidth = 1;
124
+ ctx.beginPath();
125
+ ctx.moveTo(pinSx, m.top);
126
+ ctx.lineTo(pinSx, h - m.bottom);
127
+ ctx.stroke();
128
+ ctx.restore();
129
+ ctx.beginPath();
130
+ ctx.arc(pinSx, pinSy, 5, 0, Math.PI * 2);
131
+ ctx.fillStyle = col;
132
+ ctx.fill();
133
+ ctx.strokeStyle = dark ? "rgba(0,0,0,0.5)" : "rgba(255,255,255,0.8)";
134
+ ctx.lineWidth = 1.5;
135
+ ctx.stroke();
136
+ const xLabel = formatX(pin.dataX);
137
+ const yLabel = `${pin.seriesLabel}: ${formatY(pin.dataY)}`;
138
+ ctx.font = `500 10px ${fontFamily}`;
139
+ const cardW = Math.max(ctx.measureText(xLabel).width, ctx.measureText(yLabel).width) + 20;
140
+ const cardH = 14 + 2 * 17;
141
+ let bx = pinSx + 10;
142
+ let by = pinSy - cardH - 8;
143
+ if (bx + cardW > w)
144
+ bx = pinSx - cardW - 10;
145
+ by = Math.max(m.top + 4, Math.min(h - m.bottom - cardH - 4, by));
146
+ ctx.beginPath();
147
+ ctx.roundRect(bx, by, cardW, cardH, 5);
148
+ ctx.fillStyle = dark ? "rgba(28,28,30,0.94)" : "rgba(255,255,255,0.96)";
149
+ ctx.fill();
150
+ ctx.strokeStyle = `rgba(${colRgb},0.4)`;
151
+ ctx.lineWidth = 1.5;
152
+ ctx.stroke();
153
+ ctx.fillStyle = col;
154
+ ctx.beginPath();
155
+ ctx.roundRect(bx, by, cardW, 3, [5, 5, 0, 0]);
156
+ ctx.fill();
157
+ ctx.font = `500 10px ${fontFamily}`;
158
+ ctx.textAlign = "left";
159
+ ctx.textBaseline = "middle";
160
+ ctx.fillStyle = dark ? "#888" : "#999";
161
+ ctx.fillText(xLabel, bx + 10, by + 10);
162
+ ctx.fillStyle = dark ? "#eee" : "#1a1a1a";
163
+ ctx.fillText(yLabel, bx + 10, by + 27);
164
+ }
165
+ ctx.restore();
166
+ },
167
+ uninstall(chart) {
168
+ const state = states.get(chart);
169
+ if (state) {
170
+ state.abort.abort();
171
+ states.delete(chart);
172
+ }
173
+ }
174
+ };
175
+ export {
176
+ tooltipPinPlugin
177
+ };
@@ -0,0 +1 @@
1
+ import{j as X,k as $}from"../../chunk-cbydth3q.js";import{l as I}from"../../chunk-cvtt04m6.js";import{o as Y}from"../../chunk-0eh4rzy9.js";import{q as c}from"../../chunk-50bcv2hw.js";import"../../chunk-wdfq2fpx.js";import"../../chunk-bbyt23tw.js";var M=new WeakMap,k=30;function D(t,i,d,o,r){if(t.series.length===0)return null;let{x:e,y:p}=$(i,d,t,o,r),a=-1,l=-1,C=1/0,h=1/0;for(let g=0;g<t.series.length;g++){let m=t.series[g],S=m.rawX.length;if(S===0)continue;let s=0,y=S-1;while(s<y){let T=s+y>>1;if(m.rawX[T]<e)s=T+1;else y=T}let P=s;if(s>0&&Math.abs(m.rawX[s-1]-e)<Math.abs(m.rawX[s]-e))P=s-1;let b=Math.abs(m.rawX[P]-e),u=Math.abs(m.rawY[P]-p);if(b<C||b===C&&u<h)C=b,h=u,a=g,l=P}if(a===-1)return null;let n=t.series[a],{x:f,y:w}=X(n.rawX[l],n.rawY[l],t,o,r);if(Math.hypot(f-i,w-d)>k)return null;return{dataX:n.rawX[l],dataY:n.rawY[l],seriesIndex:a,seriesLabel:n.label,color:n.color}}var F={name:"tooltip-pin",install(t,i){let d=new AbortController,o={pins:[],abort:d};M.set(t,o),i.addEventListener("click",(r)=>{if(t.dragging)return;let e=i.getBoundingClientRect(),p=r.clientX-e.left,a=r.clientY-e.top;for(let n=o.pins.length-1;n>=0;n--){let f=o.pins[n],{x:w,y:g}=X(f.dataX,f.dataY,t,e.width,e.height);if(Math.hypot(w-p,g-a)<20){o.pins.splice(n,1),r.preventDefault(),c.drawChart(t);return}}let l=D(t,p,a,e.width,e.height);if(!l)return;r.preventDefault();let h=t.config.pinMax??5;if(o.pins.length>=h)o.pins.shift();o.pins.push(l),c.drawChart(t)},{signal:d.signal})},afterDraw(t,i){let d=M.get(i);if(!d||d.pins.length===0)return;let{width:o,height:r}=i,e=Y,p=c.isDark,a=i.config,l=a.formatX??String,C=a.formatY??String,h=a.fontFamily??I;t.save(),t.font=`500 10px ${h}`;for(let n of d.pins){let{x:f,y:w}=X(n.dataX,n.dataY,i,o,r),g=`${Math.round(n.color.r*255)},${Math.round(n.color.g*255)},${Math.round(n.color.b*255)}`,m=`rgb(${g})`;t.save(),t.setLineDash([4,3]),t.strokeStyle=`rgba(${g},0.4)`,t.lineWidth=1,t.beginPath(),t.moveTo(f,e.top),t.lineTo(f,r-e.bottom),t.stroke(),t.restore(),t.beginPath(),t.arc(f,w,5,0,Math.PI*2),t.fillStyle=m,t.fill(),t.strokeStyle=p?"rgba(0,0,0,0.5)":"rgba(255,255,255,0.8)",t.lineWidth=1.5,t.stroke();let S=l(n.dataX),s=`${n.seriesLabel}: ${C(n.dataY)}`;t.font=`500 10px ${h}`;let y=Math.max(t.measureText(S).width,t.measureText(s).width)+20,P=48,b=f+10,u=w-P-8;if(b+y>o)b=f-y-10;u=Math.max(e.top+4,Math.min(r-e.bottom-P-4,u)),t.beginPath(),t.roundRect(b,u,y,P,5),t.fillStyle=p?"rgba(28,28,30,0.94)":"rgba(255,255,255,0.96)",t.fill(),t.strokeStyle=`rgba(${g},0.4)`,t.lineWidth=1.5,t.stroke(),t.fillStyle=m,t.beginPath(),t.roundRect(b,u,y,3,[5,5,0,0]),t.fill(),t.font=`500 10px ${h}`,t.textAlign="left",t.textBaseline="middle",t.fillStyle=p?"#888":"#999",t.fillText(S,b+10,u+10),t.fillStyle=p?"#eee":"#1a1a1a",t.fillText(s,b+10,u+27)}t.restore()},uninstall(t){let i=M.get(t);if(i)i.abort.abort(),M.delete(t)}};export{F as tooltipPinPlugin};