chartai 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart-library.d.ts +34 -146
- package/dist/chart-library.d.ts.map +1 -1
- package/dist/chart-library.js +411 -322
- package/dist/chart-library.min.js +1 -1
- package/dist/charts/area.d.ts +6 -0
- package/dist/charts/area.d.ts.map +1 -0
- package/dist/charts/area.js +65 -0
- package/dist/charts/area.min.js +1 -0
- package/dist/charts/bar.d.ts +11 -0
- package/dist/charts/bar.d.ts.map +1 -0
- package/dist/charts/bar.js +65 -0
- package/dist/charts/bar.min.js +1 -0
- package/dist/charts/boids.js +167 -0
- package/dist/charts/boids.min.js +18 -0
- package/dist/charts/candlestick.d.ts +21 -0
- package/dist/charts/candlestick.d.ts.map +1 -0
- package/dist/charts/candlestick.js +10 -0
- package/dist/charts/candlestick.min.js +1 -0
- package/dist/charts/experimental/baseline-area.js +70 -0
- package/dist/charts/experimental/baseline-area.min.js +1 -0
- package/dist/charts/experimental/bubble.js +48 -0
- package/dist/charts/experimental/bubble.min.js +1 -0
- package/dist/charts/experimental/error-band.js +111 -0
- package/dist/charts/experimental/error-band.min.js +1 -0
- package/dist/charts/experimental/heatmap.js +69 -0
- package/dist/charts/experimental/heatmap.min.js +1 -0
- package/dist/charts/experimental/histogram.js +139 -0
- package/dist/charts/experimental/histogram.min.js +7 -0
- package/dist/charts/experimental/ohlc.js +132 -0
- package/dist/charts/experimental/ohlc.min.js +32 -0
- package/dist/charts/experimental/step.js +67 -0
- package/dist/charts/experimental/step.min.js +1 -0
- package/dist/charts/experimental/waterfall.js +121 -0
- package/dist/charts/experimental/waterfall.min.js +7 -0
- package/dist/charts/line.d.ts +12 -0
- package/dist/charts/line.d.ts.map +1 -0
- package/dist/charts/line.js +62 -0
- package/dist/charts/line.min.js +1 -0
- package/dist/charts/scatter.d.ts +11 -0
- package/dist/charts/scatter.d.ts.map +1 -0
- package/dist/charts/scatter.js +46 -0
- package/dist/charts/scatter.min.js +1 -0
- package/dist/chunk-0eh4rzy9.min.js +2 -0
- package/dist/chunk-0jepamv9.js +7 -0
- package/dist/chunk-1ngxm8t2.js +129 -0
- package/dist/chunk-50bcv2hw.min.js +2 -0
- package/dist/chunk-5gtx3pza.js +9 -0
- package/dist/chunk-64q9a7nw.min.js +2 -0
- package/dist/chunk-831dem4f.js +4 -0
- package/dist/chunk-93yrr7er.js +35 -0
- package/dist/chunk-bbyt23tw.min.js +2 -0
- package/dist/chunk-cbydth3q.min.js +2 -0
- package/dist/chunk-cvtt04m6.min.js +2 -0
- package/dist/chunk-g2qmt43n.min.js +33 -0
- package/dist/chunk-gm0d4cgx.min.js +2 -0
- package/dist/chunk-mmsy3yqt.js +27 -0
- package/dist/chunk-n8ew0z0e.js +637 -0
- package/dist/chunk-t0kdz02m.js +129 -0
- package/dist/chunk-wdfq2fpx.min.js +2 -0
- package/dist/chunk-yabjrff2.js +11 -0
- package/dist/gpu-worker.js +630 -686
- package/dist/gpu-worker.min.js +1 -1
- package/dist/msg.d.ts +33 -0
- package/dist/msg.d.ts.map +1 -0
- package/dist/plugins/coords.d.ts +18 -0
- package/dist/plugins/coords.d.ts.map +1 -0
- package/dist/plugins/experimental/annotations.js +164 -0
- package/dist/plugins/experimental/annotations.min.js +1 -0
- package/dist/plugins/experimental/crosshair.js +82 -0
- package/dist/plugins/experimental/crosshair.min.js +1 -0
- package/dist/plugins/experimental/minimap.js +190 -0
- package/dist/plugins/experimental/minimap.min.js +1 -0
- package/dist/plugins/experimental/range-selector.js +220 -0
- package/dist/plugins/experimental/range-selector.min.js +1 -0
- package/dist/plugins/experimental/ruler.js +434 -0
- package/dist/plugins/experimental/ruler.min.js +59 -0
- package/dist/plugins/experimental/stats.js +229 -0
- package/dist/plugins/experimental/stats.min.js +8 -0
- package/dist/plugins/experimental/threshold.js +96 -0
- package/dist/plugins/experimental/threshold.min.js +1 -0
- package/dist/plugins/experimental/tooltip-pin.js +177 -0
- package/dist/plugins/experimental/tooltip-pin.min.js +1 -0
- package/dist/plugins/experimental/watermark.js +76 -0
- package/dist/plugins/experimental/watermark.min.js +1 -0
- package/dist/plugins/hover.d.ts +15 -2
- package/dist/plugins/hover.d.ts.map +1 -1
- package/dist/plugins/hover.js +75 -14
- package/dist/plugins/hover.min.js +1 -1
- package/dist/plugins/labels-panel.d.ts +4 -0
- package/dist/plugins/labels-panel.d.ts.map +1 -0
- package/dist/plugins/labels-panel.js +122 -0
- package/dist/plugins/labels-panel.min.js +1 -0
- package/dist/plugins/labels.d.ts +17 -2
- package/dist/plugins/labels.d.ts.map +1 -1
- package/dist/plugins/labels.js +11 -99
- package/dist/plugins/labels.min.js +1 -1
- package/dist/plugins/legend.d.ts +16 -0
- package/dist/plugins/legend.d.ts.map +1 -0
- package/dist/plugins/legend.js +353 -0
- package/dist/plugins/legend.min.js +37 -0
- package/dist/plugins/shared.d.ts +7 -0
- package/dist/plugins/shared.d.ts.map +1 -0
- package/dist/plugins/zoom.d.ts +10 -2
- package/dist/plugins/zoom.d.ts.map +1 -1
- package/dist/plugins/zoom.js +63 -62
- package/dist/plugins/zoom.min.js +1 -1
- package/dist/types.d.ts +187 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/dist/types.min.js +0 -0
- package/dist/worker-inline.d.ts +1 -1
- package/dist/worker-inline.d.ts.map +1 -1
- package/package.json +11 -11
- package/readme.md +54 -42
- package/dist/chunk-bgfkgcmg.js +0 -25
- package/dist/chunk-cj3zanvs.min.js +0 -2
|
@@ -0,0 +1,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 ▼</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 ▲</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}">σ</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 ▼</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 ▲</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}">σ</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};
|