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,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MARGIN
|
|
3
|
+
} from "./chunk-831dem4f.js";
|
|
4
|
+
import {
|
|
5
|
+
ChartManager
|
|
6
|
+
} from "./chunk-n8ew0z0e.js";
|
|
7
|
+
|
|
8
|
+
// src/plugins/labels.ts
|
|
9
|
+
var DEFAULT_FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';
|
|
10
|
+
var DEFAULT_LABEL_SIZE = 12;
|
|
11
|
+
function computeHomeView(width, height) {
|
|
12
|
+
const l = 32, t = 8, r = 8, b = 48;
|
|
13
|
+
const innerW = width - l - r;
|
|
14
|
+
const innerH = height - t - b;
|
|
15
|
+
return {
|
|
16
|
+
panX: innerW > 0 ? -l / innerW : 0,
|
|
17
|
+
panY: innerH > 0 ? -b / innerH : 0,
|
|
18
|
+
zoomX: innerW > 0 ? innerW / width : 1,
|
|
19
|
+
zoomY: innerH > 0 ? innerH / height : 1
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
var niceTicks = (min, max, count) => {
|
|
23
|
+
const range = max - min;
|
|
24
|
+
if (range <= 0)
|
|
25
|
+
return [min];
|
|
26
|
+
const rough = range / count, mag = 10 ** Math.floor(Math.log10(rough)), res = rough / mag;
|
|
27
|
+
const step = mag * (res <= 1.5 ? 1 : res <= 3 ? 2 : res <= 7 ? 5 : 10);
|
|
28
|
+
const ticks = [];
|
|
29
|
+
for (let v = Math.ceil(min / step) * step;v <= max; v += step)
|
|
30
|
+
ticks.push(v);
|
|
31
|
+
return ticks;
|
|
32
|
+
};
|
|
33
|
+
var getViewState = (chart) => {
|
|
34
|
+
const { width: w, height: h } = chart, m = MARGIN;
|
|
35
|
+
const { bounds: b, view: v } = chart, fullX = b.maxX - b.minX, fullY = b.maxY - b.minY;
|
|
36
|
+
const rx = fullX / v.zoomX, ry = fullY / v.zoomY;
|
|
37
|
+
const mx = b.minX + v.panX * fullX, my = b.minY + v.panY * fullY;
|
|
38
|
+
const bgc = chart.config.bgColor ?? (ChartManager.isDark ? [0.11, 0.11, 0.12] : [0.98, 0.98, 0.98]);
|
|
39
|
+
return {
|
|
40
|
+
w,
|
|
41
|
+
h,
|
|
42
|
+
m,
|
|
43
|
+
rx,
|
|
44
|
+
ry,
|
|
45
|
+
mx,
|
|
46
|
+
my,
|
|
47
|
+
bg: `${Math.round(bgc[0] * 255)},${Math.round(bgc[1] * 255)},${Math.round(bgc[2] * 255)}`,
|
|
48
|
+
font: chart.config.fontFamily ?? DEFAULT_FONT,
|
|
49
|
+
text: chart.config.textColor ?? (ChartManager.isDark ? "#c0c0c0" : "#333333"),
|
|
50
|
+
grid: chart.config.gridColor ?? (ChartManager.isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)")
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
var labelsPlugin = {
|
|
54
|
+
name: "labels",
|
|
55
|
+
install(chart) {
|
|
56
|
+
const hv = computeHomeView(chart.width, chart.height);
|
|
57
|
+
chart.homeView = hv;
|
|
58
|
+
chart.view = { ...hv };
|
|
59
|
+
ChartManager.requestRender(chart.id);
|
|
60
|
+
},
|
|
61
|
+
beforeDraw(ctx, chart) {
|
|
62
|
+
const hv = computeHomeView(chart.width, chart.height);
|
|
63
|
+
const old = chart.homeView;
|
|
64
|
+
chart.homeView = hv;
|
|
65
|
+
if (hv.zoomX !== old.zoomX || hv.zoomY !== old.zoomY || hv.panX !== old.panX || hv.panY !== old.panY) {
|
|
66
|
+
chart.view = { ...hv };
|
|
67
|
+
ChartManager.requestRender(chart.id);
|
|
68
|
+
}
|
|
69
|
+
const { w, h, m, rx, ry, mx, my, grid } = getViewState(chart);
|
|
70
|
+
ctx.strokeStyle = grid;
|
|
71
|
+
ctx.lineWidth = 1;
|
|
72
|
+
ctx.beginPath();
|
|
73
|
+
niceTicks(my, my + ry, 7).forEach((v) => {
|
|
74
|
+
const y = h * (1 - (v - my) / ry);
|
|
75
|
+
if (y > 5 && y < h - m.bottom - 5) {
|
|
76
|
+
ctx.moveTo(m.left, y);
|
|
77
|
+
ctx.lineTo(w, y);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
niceTicks(mx, mx + rx, 8).forEach((v) => {
|
|
81
|
+
const x = w * ((v - mx) / rx);
|
|
82
|
+
if (x > m.left && x < w) {
|
|
83
|
+
ctx.moveTo(x, 0);
|
|
84
|
+
ctx.lineTo(x, h - m.bottom);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
ctx.stroke();
|
|
88
|
+
},
|
|
89
|
+
afterDraw(ctx, chart) {
|
|
90
|
+
const { w, h, m, rx, ry, mx, my, bg, font, text } = getViewState(chart);
|
|
91
|
+
const {
|
|
92
|
+
formatX = String,
|
|
93
|
+
formatY = String,
|
|
94
|
+
labelSize = DEFAULT_LABEL_SIZE
|
|
95
|
+
} = chart.config;
|
|
96
|
+
const drawFade = (dir, x, y, fw, fh) => {
|
|
97
|
+
const g = dir === "left" ? ctx.createLinearGradient(x, 0, x + fw, 0) : ctx.createLinearGradient(0, y, 0, y + fh);
|
|
98
|
+
const alphas = dir === "left" ? [1, 0.7, 0.2, 0.05, 0] : [0, 0.05, 0.2, 0.7, 1];
|
|
99
|
+
[0, 0.35, 0.55, 0.7, 1].forEach((s, i) => g.addColorStop(s, `rgba(${bg},${alphas[i]})`));
|
|
100
|
+
ctx.fillStyle = g;
|
|
101
|
+
ctx.fillRect(x, y, fw, fh);
|
|
102
|
+
};
|
|
103
|
+
drawFade("left", 0, 0, m.left + 20, h);
|
|
104
|
+
drawFade("bottom", 0, h - m.bottom - 20, w, m.bottom + 20);
|
|
105
|
+
ctx.font = `${labelSize}px ${font}`;
|
|
106
|
+
ctx.fillStyle = text;
|
|
107
|
+
ctx.textAlign = "right";
|
|
108
|
+
ctx.textBaseline = "middle";
|
|
109
|
+
niceTicks(my, my + ry, 7).forEach((v) => {
|
|
110
|
+
const y = h * (1 - (v - my) / ry);
|
|
111
|
+
if (y > 5 && y < h - m.bottom - 5)
|
|
112
|
+
ctx.fillText(formatY(v), m.left - 5, y);
|
|
113
|
+
});
|
|
114
|
+
ctx.textAlign = "right";
|
|
115
|
+
ctx.textBaseline = "top";
|
|
116
|
+
niceTicks(mx, mx + rx, 8).forEach((v) => {
|
|
117
|
+
const x = w * ((v - mx) / rx);
|
|
118
|
+
if (x < m.left - 10 || x > w + 30)
|
|
119
|
+
return;
|
|
120
|
+
ctx.save();
|
|
121
|
+
ctx.translate(x, h - m.bottom + 5);
|
|
122
|
+
ctx.rotate(-Math.PI / 14);
|
|
123
|
+
ctx.fillText(formatX(v), 0, 0);
|
|
124
|
+
ctx.restore();
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export { DEFAULT_FONT, DEFAULT_LABEL_SIZE, labelsPlugin };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as j}from"./chunk-wdfq2fpx.js";import{t as _}from"./chunk-bbyt23tw.js";class Y{id;_mgr;constructor(q,A){this.id=q,this._mgr=A}get _c(){return this._mgr.charts.get(this.id)}setData(q){this._mgr.updateSeries(this.id,q)}configure(q){let A=this._c;if(!A)return;Object.assign(A.config,q);let F=new Set((A.renderer.uniforms??[]).map((J)=>J.name)),G={};for(let J of Object.keys(q)){let T=q[J];if(typeof T==="number"&&F.has(J))G[J]=T}if(Object.keys(G).length>0)Object.assign(A.customUniforms,G),this._mgr.worker?.postMessage({type:j.SET_UNIFORMS,id:this.id,values:G});if("hiddenSeries"in q)this._mgr.worker?.postMessage({type:j.SET_STYLE,id:this.id,hiddenSeries:q.hiddenSeries??new Set});if("bgColor"in q&&q.bgColor!==void 0){let[J,T,N]=q.bgColor,K=A.el.querySelector("div");if(K)K.style.background=`rgb(${Math.round(J*255)},${Math.round(T*255)},${Math.round(N*255)})`;this._mgr.worker?.postMessage({type:j.SET_STYLE,id:this.id,bgColor:q.bgColor})}this._mgr.requestRender(this.id),this._mgr.drawChart(A)}addPlugin(q){let A=this._c;if(!A||A.plugins.some((G)=>G.name===q.name))return;let F=A.el.querySelector("div");q.install?.(A,F),A.plugins.push(q),this._mgr.drawChart(A)}removePlugin(q){let A=this._c;if(!A)return;let F=A.plugins.findIndex((G)=>G.name===q);if(F>=0)A.plugins[F].uninstall?.(A),A.plugins.splice(F,1),this._mgr.drawChart(A)}hasPlugin(q){return this._c?.plugins.some((A)=>A.name===q)??!1}resetView(){this._mgr.resetView(this.id)}destroy(){this._mgr.destroy(this.id)}}var S=null;function z(q){if(typeof q!=="string")return q;if(!S)S=document.createElement("i"),S.style.cssText="display:none",document.body.appendChild(S);S.style.color=q;let A=getComputedStyle(S).color.match(/\d+/g);return{r:+A[0]/255,g:+A[1]/255,b:+A[2]/255}}function X(q,A,F){let G=devicePixelRatio||1;if(q.width=Math.round(A*G),q.height=Math.round(F*G),q instanceof HTMLCanvasElement)q.style.width=`${A}px`,q.style.height=`${F}px`}class W{static instance=null;worker=null;charts=new Map;renderers=new Map;uiPlugins=[];pendingRenderers=[];chartIdCounter=0;_isDark=!1;_syncViews=!1;statsCallbacks=[];currentStats={fps:0,renderMs:0,total:0,active:0};visibilityObserver;resizeObserver;constructor(){this._isDark=document.documentElement.classList.contains("dark"),this.visibilityObserver=new IntersectionObserver((q)=>{for(let A of q){let F=A.target.dataset.chartId;if(!F)continue;let G=this.charts.get(F);if(!G)continue;if(G.visible=A.isIntersecting,this.worker?.postMessage({type:j.SET_VISIBILITY,id:F,visible:A.isIntersecting}),A.isIntersecting)this.drawChart(G)}},{threshold:0.01}),this.resizeObserver=new ResizeObserver((q)=>{for(let A of q){let F=A.target.dataset.chartId;if(!F)continue;let G=this.charts.get(F);if(!G)continue;let{width:J,height:T}=A.contentRect;if(J<=0||T<=0)continue;G.width=J,G.height=T;let N=devicePixelRatio||1;X(G.backCanvas,J,T),X(G.frontCanvas,J,T);let{bufferSizes:K,perSeriesPassMeta:$}=this.computeRendererMeta(G.renderer,G);this.worker?.postMessage({type:j.RESIZE,id:F,width:Math.round(J*N),height:Math.round(T*N),bufferSizes:K,perSeriesPassMeta:$}),this.drawChart(G)}})}static getInstance(){if(!W.instance)W.instance=new W;return W.instance}get isDark(){return this._isDark}get syncViews(){return this._syncViews}use(q){if("passes"in q){let A=q;if(this.renderers.set(A.name,A),this.worker)this.sendRendererRegistration(A);else this.pendingRenderers.push(A)}else{let A=q;if(!this.uiPlugins.some((F)=>F.name===A.name))this.uiPlugins.push(A)}}async init(){if(this.worker)return!0;return new Promise((q)=>{import("./worker-inline.js").then(({WORKER_CODE:A})=>{let F=new Blob([A],{type:"application/javascript"});this.worker=new Worker(URL.createObjectURL(F),{type:"module"}),this.setupWorkerHandlers(q)}).catch(()=>{this.worker=new Worker(new URL("./gpu-worker.js",import.meta.url),{type:"module"}),this.setupWorkerHandlers(q)})})}setupWorkerHandlers(q){if(!this.worker)return;this.worker.onmessage=(A)=>{let{type:F,...G}=A.data;switch(F){case j.GPU_READY:for(let J of this.pendingRenderers)this.sendRendererRegistration(J);this.pendingRenderers=[],q(!0);break;case j.ERROR:console.error("chartai:",G.code),q(!1);break;case j.STATS:this.currentStats={fps:G.fps,renderMs:G.renderMs,total:G.totalCharts,active:G.activeCharts};for(let J of this.statsCallbacks)J(this.currentStats);break}},this.worker.onerror=(A)=>{console.error("chartai:",A),q(!1)},this.worker.postMessage({type:j.INIT,isDark:this._isDark})}sendRendererRegistration(q){let A=(q.buffers??[]).map((F)=>({name:F.name,usages:F.usages,perSeries:q.passes.some((G)=>G.perSeries!==!1&&G.bindings.some((J)=>J.source===F.name))}));this.worker?.postMessage({type:j.REGISTER_RENDERER,name:q.name,shaders:q.shaders,passes:q.passes.map((F)=>({type:F.type,shader:F.shader,bindings:F.bindings,perSeries:F.perSeries!==!1,topology:F.topology,loadOp:F.loadOp,blend:F.blend})),bufferDefs:A,uniformDefs:q.uniforms??[]})}computeRendererMeta(q,A){let F={},G=[],J=A.series.length>0?A.series:[{rawX:[],rawY:[],extra:{},label:"",color:{r:0,g:0,b:0}}],T=devicePixelRatio||1,N=Math.round(A.width*T),K=Math.round(A.height*T);for(let $ of J){let O={width:N,height:K,samples:$.rawX.length,seriesCount:J.length,bounds:A.bounds,view:A.view};for(let R of q.buffers??[]){let P=R.bytes(O);F[R.name]=Math.max(F[R.name]??0,P)}G.push(q.passes.map((R)=>({dispatch:R.dispatch?.(O),draw:R.draw?.(O)})))}return{bufferSizes:F,perSeriesPassMeta:G}}create(q){if(!this.worker)throw Error("No worker. Call init().");let A=this.renderers.get(q.type);if(!A)throw Error(`No renderer "${q.type}". Call manager.use() first.`);let F=`chart-${++this.chartIdCounter}`,G=document.createElement("div");G.dataset.chartId=F,G.style.cssText="width:100%;height:100%;position:relative;";let J=document.createElement("div");J.dataset.chartId=F,J.style.cssText="width:100%;height:100%;position:relative;";let T=(B,Q)=>{let Z=document.createElement("canvas");return Z.style.cssText=`position:absolute;inset:0;width:100%;height:100%;pointer-events:${Q};z-index:${B};`,Z},N=T(0,"none"),K=T(1,"auto"),$=T(2,"none");J.append(N,K,$),G.appendChild(J),q.container.appendChild(G);let O;try{O=K.transferControlToOffscreen()}catch(B){throw Error(`Failed OffscreenCanvas: ${B}`)}let R=J.getBoundingClientRect(),P=R.width||400,V=R.height||200;if(X(O,P,V),X(N,P,V),X($,P,V),q.bgColor){let[B,Q,Z]=q.bgColor;J.style.background=`rgb(${Math.round(B*255)},${Math.round(Q*255)},${Math.round(Z*255)})`}let E={};for(let B of A.uniforms??[]){let Q=q[B.name];E[B.name]=typeof Q==="number"?Q:B.default}let L={id:F,config:q,el:G,backCanvas:N,frontCanvas:$,width:P,height:V,series:[],bounds:{minX:0,maxX:1,minY:0,maxY:1},view:{panX:0,panY:0,zoomX:1,zoomY:1},homeView:{panX:0,panY:0,zoomX:1,zoomY:1},visible:!0,dragging:!1,plugins:[...this.uiPlugins],renderer:A,customUniforms:E};this.charts.set(F,L);let I=devicePixelRatio||1,{bufferSizes:U,perSeriesPassMeta:D}=this.computeRendererMeta(A,L);this.worker.postMessage({type:j.REGISTER_CHART,id:F,canvas:O,rendererName:q.type,bgColor:q.bgColor??null,bufferSizes:U,perSeriesPassMeta:D,customUniformValues:E,width:Math.round(P*I),height:Math.round(V*I)},[O]),this.visibilityObserver.observe(G),this.resizeObserver.observe(J);for(let B of L.plugins)B.install?.(L,J);return A.install?.(L,J),this.updateSeries(F,q.series),new Y(F,this)}destroy(q){let A=this.charts.get(q);if(!A)return;A.renderer.uninstall?.(A);for(let G of A.plugins)G.uninstall?.(A);this.visibilityObserver.unobserve(A.el);let F=A.el.querySelector("div");if(F)this.resizeObserver.unobserve(F);A.el.remove(),this.worker?.postMessage({type:j.UNREGISTER_CHART,id:q}),this.charts.delete(q)}updateSeries(q,A){let F=this.charts.get(q);if(!F||!this.worker||A.length===0)return;F.config.hiddenSeries=A.reduce((L,I,U)=>{if(I.hidden)L.add(U);return L},new Set),F.series=A.map((L)=>{let I=L.x.length,U=z(L.color);if(I===0)return{label:L.label,color:U,rawX:[],rawY:[],extra:{}};let D=Array.from({length:I},(Q,Z)=>Z).sort((Q,Z)=>L.x[Q]-L.x[Z]),B={};for(let Q in L)if(Q!=="label"&&Q!=="color"&&Q!=="x"&&Q!=="y"&&Array.isArray(L[Q]))B[Q]=D.map((Z)=>L[Q][Z]);return{label:L.label,color:U,rawX:D.map((Q)=>L.x[Q]),rawY:D.map((Q)=>L.y[Q]),extra:B}});let G=F.renderer.computeBounds?.(F.series),{minX:J,maxX:T,minY:N,maxY:K}=G??(()=>{let L=1/0,I=-1/0,U=1/0,D=-1/0;for(let Z of F.series)for(let H=0;H<Z.rawX.length;H++){if(Z.rawX[H]<L)L=Z.rawX[H];if(Z.rawX[H]>I)I=Z.rawX[H];if(Z.rawY[H]<U)U=Z.rawY[H];if(Z.rawY[H]>D)D=Z.rawY[H]}let B=(I-L)*0.05||1,Q=(D-U)*0.1||1;return{minX:L-B,maxX:I+B,minY:U-Q,maxY:D+Q}})(),$=F.config.defaultBounds;if($){if($.minX!==void 0)J=$.minX;if($.maxX!==void 0)T=$.maxX;if($.minY!==void 0)N=$.minY;if($.maxY!==void 0)K=$.maxY}F.bounds={minX:J,maxX:T,minY:N,maxY:K};let{bufferSizes:O,perSeriesPassMeta:R}=this.computeRendererMeta(F.renderer,F),P=F.config.hiddenSeries??new Set,V=F.series.map((L,I)=>{let U={};for(let D in L.extra)U[D]=new Float32Array(L.extra[D]);return{label:L.label,colorR:L.color.r,colorG:L.color.g,colorB:L.color.b,dataX:new Float32Array(L.rawX),dataY:new Float32Array(L.rawY),extra:U,hidden:P.has(I)}}),E=V.flatMap((L)=>[L.dataX.buffer,L.dataY.buffer,...Object.values(L.extra).map((I)=>I.buffer)]);this.worker.postMessage({type:j.UPDATE_SERIES,id:q,series:V,bounds:F.bounds,bufferSizes:O,perSeriesPassMeta:R},E),this.sendViewTransform(F),this.drawChart(F)}setSyncViews(q){this._syncViews=q}setTheme(q){this._isDark=q,this.worker?.postMessage({type:j.THEME,isDark:q});for(let A of this.charts.values())this.drawChart(A)}onStats(q){return this.statsCallbacks.push(q),()=>{let A=this.statsCallbacks.indexOf(q);if(A>=0)this.statsCallbacks.splice(A,1)}}getStats(){return{...this.currentStats}}resetView(q){let A=this.charts.get(q);if(!A)return;for(let V of A.plugins)V.resetView?.(A);let{panX:F,panY:G,zoomX:J,zoomY:T}=A.view,{panX:N,panY:K,zoomX:$,zoomY:O}=A.homeView,R=performance.now(),P=()=>{let V=Math.min(1,(performance.now()-R)/300),E=1-Math.pow(1-V,3);if(A.view.panX=F+(N-F)*E,A.view.panY=G+(K-G)*E,A.view.zoomX=J+($-J)*E,A.view.zoomY=T+(O-T)*E,this.sendViewTransform(A),this.drawChart(A),this._syncViews)this.syncAllViews(A);if(V<1)requestAnimationFrame(P)};requestAnimationFrame(P)}setHiddenSeries(q,A){let F=this.charts.get(q);if(!F)return;F.config.hiddenSeries=new Set(A),this.worker?.postMessage({type:j.SET_STYLE,id:q,hiddenSeries:F.config.hiddenSeries}),this.drawChart(F)}requestRender(q){let A=this.charts.get(q);if(A)this.sendViewTransform(A)}sendViewTransform(q){this.worker?.postMessage({type:j.VIEW_TRANSFORM,id:q.id,panX:q.view.panX,panY:q.view.panY,zoomX:q.view.zoomX,zoomY:q.view.zoomY})}syncAllViews(q){let A=[];for(let F of this.charts.values())if(F.id!==q.id)F.view={...q.view},A.push({id:F.id}),this.drawChart(F);if(A.length>0)this.worker?.postMessage({type:j.BATCH_VIEW_TRANSFORM,panX:q.view.panX,panY:q.view.panY,zoomX:q.view.zoomX,zoomY:q.view.zoomY,transforms:A})}drawChart(q){if(!q.visible)return;let A=devicePixelRatio||1,F=q.backCanvas.getContext("2d");if(F){F.clearRect(0,0,q.backCanvas.width,q.backCanvas.height),F.save(),F.scale(A,A);for(let J of q.plugins)J.beforeDraw?.(F,q);F.restore()}let G=q.frontCanvas.getContext("2d");if(G){G.clearRect(0,0,q.frontCanvas.width,q.frontCanvas.height),G.save(),G.scale(A,A);for(let J of q.plugins)J.afterDraw?.(G,q);G.restore()}}}var w=W.getInstance();
|
|
2
|
+
export{Y as p,w as q};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined")
|
|
5
|
+
return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export { __require };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=256,t="struct Uniforms{width: f32,height: f32,viewMinX: f32,viewMaxX: f32,viewMinY: f32,viewMaxY: f32,pointCount: u32,seriesCount: u32,isDark: u32,bgR: f32,bgG: f32,bgB: f32,dataMinX: f32,dataMaxX: f32,dataMinY: f32,dataMaxY: f32,};struct SeriesInfo{color: vec4f,visibleRange: vec2u,_pad0: f32,_pad1: f32,};struct SeriesIndex{index: u32,_pad0: u32,_pad1: u32,_pad2: u32,};",a="fn lowerBound(val: f32,count: u32)-> u32{var lo = 0u;var hi = count;while(lo < hi){let mid =(lo + hi)/ 2u;if(dataX[mid] < val){lo = mid + 1u;}else{hi = mid;}}return lo;}",l="fn luma(c:vec4f)->f32{return dot(c.rgb,vec3f(.299,.587,.114));}fn laaa(uv:vec2f,t:texture_2d<f32>,s:sampler)->vec4f{let r=1./vec2f(textureDimensions(t));let m=textureSample(t,s,uv);let n=textureSample(t,s,uv+vec2f(0.,-r.y));let e=textureSample(t,s,uv+vec2f(r.x,0.));let w=textureSample(t,s,uv+vec2f(-r.x,0.));let sv=textureSample(t,s,uv+vec2f(0.,r.y));let lm=luma(m);let ln=luma(n);let le=luma(e);let lw=luma(w);let ls=luma(sv);let lo=min(lm,min(min(ln,ls),min(le,lw)));let hi=max(lm,max(max(ln,ls),max(le,lw)));let rng=hi-lo;if(rng<max(.0833,hi*.166)){return m;}return mix(m,(m+n+e+w+sv)*.2,min(rng*3.,1.));}struct BV{@builtin(position)p:vec4f,@location(0)uv:vec2f}@group(0)@binding(0)var inputTex:texture_2d<f32>;@group(0)@binding(1)var samp:sampler;@vertex fn vs(@builtin(vertex_index)i:u32)->BV{var p=array<vec2f,4>(vec2f(-1,-1),vec2f(1,-1),vec2f(-1,1),vec2f(1,1));var u=array<vec2f,4>(vec2f(0,1),vec2f(1,1),vec2f(0,0),vec2f(1,0));return BV(vec4f(p[i],0,1),u[i]);}@fragment fn fs(v:BV)->@location(0)vec4f{return laaa(v.uv,inputTex,samp);}";
|
|
2
|
+
export{e as f,t as g,a as h,l as i};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/msg.ts
|
|
2
|
+
var M = {
|
|
3
|
+
INIT: 0,
|
|
4
|
+
THEME: 1,
|
|
5
|
+
REGISTER_RENDERER: 2,
|
|
6
|
+
REGISTER_CHART: 3,
|
|
7
|
+
UNREGISTER_CHART: 4,
|
|
8
|
+
UPDATE_SERIES: 5,
|
|
9
|
+
RESIZE: 6,
|
|
10
|
+
VIEW_TRANSFORM: 7,
|
|
11
|
+
BATCH_VIEW_TRANSFORM: 8,
|
|
12
|
+
SET_VISIBILITY: 9,
|
|
13
|
+
SET_STYLE: 10,
|
|
14
|
+
SET_UNIFORMS: 11,
|
|
15
|
+
GPU_READY: 12,
|
|
16
|
+
ERROR: 13,
|
|
17
|
+
STATS: 14
|
|
18
|
+
};
|
|
19
|
+
var E = {
|
|
20
|
+
NO_GPU: "e1:no-gpu",
|
|
21
|
+
NO_ADAPTER: "e2:no-adapter",
|
|
22
|
+
DEVICE_LOST: "e3:device-lost",
|
|
23
|
+
NOT_READY: "e4:not-ready",
|
|
24
|
+
COMPILE: "e5:compile",
|
|
25
|
+
CTX_GET: "e6:ctx-get",
|
|
26
|
+
CTX_CFG: "e7:ctx-cfg",
|
|
27
|
+
TEX: "e8:tex",
|
|
28
|
+
BIND_S: "e9:bind-s",
|
|
29
|
+
BIND_C: "e10:bind-c",
|
|
30
|
+
UPDATE: "e11:update",
|
|
31
|
+
NO_RENDERER: "e12:no-renderer",
|
|
32
|
+
RESIZE: "e13:resize"
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { M, E };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function I(y,z,j,A,B){let k=j.bounds.maxX-j.bounds.minX,q=j.bounds.maxY-j.bounds.minY,D=k/j.view.zoomX,E=q/j.view.zoomY,F=j.bounds.minX+j.view.panX*k,G=j.bounds.minY+j.view.panY*q;return{x:(y-F)/D*A,y:B*(1-(z-G)/E)}}function J(y,z,j,A,B){let k=j.bounds.maxX-j.bounds.minX,q=j.bounds.maxY-j.bounds.minY,D=k/j.view.zoomX,E=q/j.view.zoomY,F=j.bounds.minX+j.view.panX*k,G=j.bounds.minY+j.view.panY*q;return{x:F+y/A*D,y:G+(1-z/B)*E}}
|
|
2
|
+
export{I as j,J as k};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{o as z}from"./chunk-0eh4rzy9.js";import{q as d}from"./chunk-50bcv2hw.js";var k='-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif',D=12;function S(e,t){let n=e-32-8,r=t-8-48;return{panX:n>0?-32/n:0,panY:r>0?-48/r:0,zoomX:n>0?n/e:1,zoomY:r>0?r/t:1}}var C=(e,t,l)=>{let i=t-e;if(i<=0)return[e];let o=i/l,s=10**Math.floor(Math.log10(o)),n=o/s,r=s*(n<=1.5?1:n<=3?2:n<=7?5:10),a=[];for(let m=Math.ceil(e/r)*r;m<=t;m+=r)a.push(m);return a},v=(e)=>{let{width:t,height:l}=e,i=z,{bounds:o,view:s}=e,n=o.maxX-o.minX,r=o.maxY-o.minY,a=n/s.zoomX,m=r/s.zoomY,p=o.minX+s.panX*n,h=o.minY+s.panY*r,b=e.config.bgColor??(d.isDark?[0.11,0.11,0.12]:[0.98,0.98,0.98]);return{w:t,h:l,m:i,rx:a,ry:m,mx:p,my:h,bg:`${Math.round(b[0]*255)},${Math.round(b[1]*255)},${Math.round(b[2]*255)}`,font:e.config.fontFamily??k,text:e.config.textColor??(d.isDark?"#c0c0c0":"#333333"),grid:e.config.gridColor??(d.isDark?"rgba(255,255,255,0.06)":"rgba(0,0,0,0.06)")}},A={name:"labels",install(e){let t=S(e.width,e.height);e.homeView=t,e.view={...t},d.requestRender(e.id)},beforeDraw(e,t){let l=S(t.width,t.height),i=t.homeView;if(t.homeView=l,l.zoomX!==i.zoomX||l.zoomY!==i.zoomY||l.panX!==i.panX||l.panY!==i.panY)t.view={...l},d.requestRender(t.id);let{w:o,h:s,m:n,rx:r,ry:a,mx:m,my:p,grid:h}=v(t);e.strokeStyle=h,e.lineWidth=1,e.beginPath(),C(p,p+a,7).forEach((b)=>{let f=s*(1-(b-p)/a);if(f>5&&f<s-n.bottom-5)e.moveTo(n.left,f),e.lineTo(o,f)}),C(m,m+r,8).forEach((b)=>{let f=o*((b-m)/r);if(f>n.left&&f<o)e.moveTo(f,0),e.lineTo(f,s-n.bottom)}),e.stroke()},afterDraw(e,t){let{w:l,h:i,m:o,rx:s,ry:n,mx:r,my:a,bg:m,font:p,text:h}=v(t),{formatX:b=String,formatY:f=String,labelSize:L=D}=t.config,y=(u,g,c,w,X)=>{let Y=u==="left"?e.createLinearGradient(g,0,g+w,0):e.createLinearGradient(0,c,0,c+X),M=u==="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((T,E)=>Y.addColorStop(T,`rgba(${m},${M[E]})`)),e.fillStyle=Y,e.fillRect(g,c,w,X)};y("left",0,0,o.left+20,i),y("bottom",0,i-o.bottom-20,l,o.bottom+20),e.font=`${L}px ${p}`,e.fillStyle=h,e.textAlign="right",e.textBaseline="middle",C(a,a+n,7).forEach((u)=>{let g=i*(1-(u-a)/n);if(g>5&&g<i-o.bottom-5)e.fillText(f(u),o.left-5,g)}),e.textAlign="right",e.textBaseline="top",C(r,r+s,8).forEach((u)=>{let g=l*((u-r)/s);if(g<o.left-10||g>l+30)return;e.save(),e.translate(g,i-o.bottom+5),e.rotate(-Math.PI/14),e.fillText(b(u),0,0),e.restore()})}};
|
|
2
|
+
export{k as l,D as m,A as n};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import{f as v,g as K,h as H}from"./chunk-64q9a7nw.js";var b=`
|
|
2
|
+
struct CandleUniforms {
|
|
3
|
+
maxSamples: f32,
|
|
4
|
+
upColor: u32,
|
|
5
|
+
downColor: u32,
|
|
6
|
+
binSize: u32,
|
|
7
|
+
interval: f32,
|
|
8
|
+
_p0: u32, _p1: u32, _p2: u32,
|
|
9
|
+
};
|
|
10
|
+
struct CandleData {
|
|
11
|
+
screenX: f32,
|
|
12
|
+
barWidth: f32,
|
|
13
|
+
low: f32,
|
|
14
|
+
bodyBottom: f32,
|
|
15
|
+
bodyTop: f32,
|
|
16
|
+
high: f32,
|
|
17
|
+
isUp: f32,
|
|
18
|
+
};`,B=`
|
|
19
|
+
fn effectiveInterval() -> f32 {
|
|
20
|
+
if (cu.interval > 0.0) { return cu.interval; }
|
|
21
|
+
let raw = (u.viewMaxX - u.viewMinX) / u.width * f32(cu.binSize);
|
|
22
|
+
let steps = array<f32, 20>(
|
|
23
|
+
1.0, 2.0, 5.0, 10.0, 15.0, 30.0,
|
|
24
|
+
60.0, 120.0, 300.0, 600.0, 900.0, 1800.0,
|
|
25
|
+
3600.0, 7200.0, 14400.0, 43200.0,
|
|
26
|
+
86400.0, 259200.0, 604800.0, 2592000.0
|
|
27
|
+
);
|
|
28
|
+
for (var i = 0u; i < 20u; i++) {
|
|
29
|
+
if (steps[i] >= raw) { return steps[i]; }
|
|
30
|
+
}
|
|
31
|
+
return raw;
|
|
32
|
+
}`,G=`${K}${b}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> dataX: array<f32>;@group(0)@binding(2)var<storage,read> dataClose: array<f32>;@group(0)@binding(3)var<storage,read_write> candleData: array<CandleData>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(6)var<uniform> cu: CandleUniforms;@group(0)@binding(7)var<storage,read> dataOpen: array<f32>;@group(0)@binding(8)var<storage,read> dataHigh: array<f32>;@group(0)@binding(9)var<storage,read> dataLow: array<f32>;${H}${B}@compute @workgroup_size(${v})fn main(@builtin(global_invocation_id)id: vec3u){let binIdx = id.x;let totalPixels = u32(u.width);let count = u.pointCount;if(count == 0u){if(binIdx < totalPixels){candleData[binIdx] = CandleData(0.0,0.0,0.0,0.0,0.0,0.0,0.0);}return;}let viewRangeX = u.viewMaxX - u.viewMinX;let viewRangeY = u.viewMaxY - u.viewMinY;if(viewRangeX < 0.0001 || viewRangeY < 0.0001){if(binIdx < totalPixels){candleData[binIdx] = CandleData(0.0,0.0,0.0,0.0,0.0,0.0,0.0);}return;}let interval = effectiveInterval();let alignedStart = floor(u.viewMinX / interval)* interval;let numBins = min(u32(ceil(viewRangeX / interval))+ 2u,totalPixels);if(binIdx >= numBins){return;}let binMinX = alignedStart + f32(binIdx)* interval;let binMaxX = binMinX + interval;if(binMinX >= u.viewMaxX){candleData[binIdx] = CandleData(0.0,0.0,0.0,0.0,0.0,0.0,0.0);return;}let binMidX = binMinX + interval * 0.5;let screenX =(binMidX - u.viewMinX)/ viewRangeX;let barWidth = interval / viewRangeX;let onePixel = 1.0 / u.width;let bw = max(barWidth * 0.95,onePixel);let startIdx = lowerBound(binMinX,count);var endIdx = lowerBound(binMaxX,count);endIdx = min(endIdx,count);if(startIdx >= endIdx){var bestIdx: u32 = 0u;var bestDist: f32 = 1e10;var hit = false;if(startIdx < count){let bx = dataX[startIdx];let hw = interval * 0.5;if(binMinX < bx + hw && binMaxX > bx - hw){bestIdx = startIdx;bestDist = abs(bx - binMidX);hit = true;}}if(startIdx > 0u){let prev = startIdx - 1u;let bx = dataX[prev];let hw = interval * 0.5;if(binMinX < bx + hw && binMaxX > bx - hw){let d = abs(bx - binMidX);if(!hit || d < bestDist){bestIdx = prev;}hit = true;}}if(!hit){candleData[binIdx] = CandleData(0.0,0.0,0.0,0.0,0.0,0.0,0.0);return;}let o = dataOpen[bestIdx];let h = dataHigh[bestIdx];let l = dataLow[bestIdx];let c = dataClose[bestIdx];candleData[binIdx] = CandleData(screenX,bw,l,min(o,c),max(o,c),h,select(0.0,1.0,c>=o));return;}let o = dataOpen[startIdx];var h = dataHigh[startIdx];var l = dataLow[startIdx];let c = dataClose[endIdx - 1u];let rangeCount = endIdx - startIdx;let maxSamples = u32(cu.maxSamples);if(maxSamples > 0u && rangeCount > maxSamples){let stride = f32(rangeCount - 1u)/ f32(maxSamples - 1u);for(var s = 0u;s < maxSamples;s++){let idx = startIdx + u32(f32(s)* stride);if(idx < endIdx){h = max(h,dataHigh[idx]);l = min(l,dataLow[idx]);}}h = max(h,dataHigh[endIdx - 1u]);l = min(l,dataLow[endIdx - 1u]);}else{for(var i = startIdx;i < endIdx;i++){h = max(h,dataHigh[i]);l = min(l,dataLow[i]);}}candleData[binIdx] = CandleData(screenX,bw,l,min(o,c),max(o,c),h,select(0.0,1.0,c>=o));}`,V=`${K}${b}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> candleData: array<CandleData>;@group(0)@binding(2)var<uniform> cu: CandleUniforms;${B}struct VertexOutput{@builtin(position)pos: vec4f,@location(0)@interpolate(flat)isUp: f32,@location(1)@interpolate(flat)isWick: f32,};@vertex fn vs(@builtin(vertex_index)vi: u32)-> VertexOutput{var out: VertexOutput;let viewRangeX = u.viewMaxX - u.viewMinX;let interval = effectiveInterval();let numBins = min(u32(ceil(viewRangeX / interval))+ 2u,u32(u.width));let colIdx = vi / 30u;let localVi = vi % 30u;let section = localVi / 6u;let vertexType = localVi % 6u;if(colIdx >= numBins){out.pos = vec4f(0.0,0.0,0.0,0.0);out.isUp = 0.0;out.isWick = 0.0;return out;}let cd = candleData[colIdx];if(cd.barWidth <= 0.0){out.pos = vec4f(0.0,0.0,0.0,0.0);out.isUp = 0.0;out.isWick = 0.0;return out;}out.isUp = cd.isUp;out.isWick = select(0.0,1.0,section > 0u);let viewRangeY = u.viewMaxY - u.viewMinY;let safeRangeY = select(viewRangeY,1.0,viewRangeY < 0.0001);let onePixelX = 1.0 / u.width;let onePixelY = 1.0 / u.height;var sLeft: f32;var sRight: f32;var sTop: f32;var sBottom: f32;if(section == 0u){let nb =(cd.bodyBottom - u.viewMinY)/ safeRangeY;let nt =(cd.bodyTop - u.viewMinY)/ safeRangeY;sBottom = 1.0 - nb;sTop = 1.0 - nt;let hw = cd.barWidth * 0.5;sLeft = cd.screenX - hw;sRight = cd.screenX + hw;}else if(section == 1u){let nb =(cd.bodyTop - u.viewMinY)/ safeRangeY;let nt =(cd.high - u.viewMinY)/ safeRangeY;sBottom = 1.0 - nb;sTop = 1.0 - nt;let hw = max(onePixelX,cd.barWidth * 0.08);sLeft = cd.screenX - hw;sRight = cd.screenX + hw;}else if(section == 2u){let nb =(cd.low - u.viewMinY)/ safeRangeY;let nt =(cd.bodyBottom - u.viewMinY)/ safeRangeY;sBottom = 1.0 - nb;sTop = 1.0 - nt;let hw = max(onePixelX,cd.barWidth * 0.08);sLeft = cd.screenX - hw;sRight = cd.screenX + hw;}else if(section == 3u){let sy = 1.0 -(cd.high - u.viewMinY)/ safeRangeY;let wickHW = max(onePixelX,cd.barWidth * 0.08);let capHH = wickHW * u.width / u.height;sTop = sy - capHH;sBottom = sy + capHH;let hw = max(onePixelX * 2.0,cd.barWidth * 0.28);sLeft = cd.screenX - hw;sRight = cd.screenX + hw;}else{let sy = 1.0 -(cd.low - u.viewMinY)/ safeRangeY;let wickHW = max(onePixelX,cd.barWidth * 0.08);let capHH = wickHW * u.width / u.height;sTop = sy - capHH;sBottom = sy + capHH;let hw = max(onePixelX * 2.0,cd.barWidth * 0.28);sLeft = cd.screenX - hw;sRight = cd.screenX + hw;}var positions = array<vec2f,6>(vec2f(sLeft,sBottom),vec2f(sRight,sBottom),vec2f(sLeft,sTop),vec2f(sLeft,sTop),vec2f(sRight,sBottom),vec2f(sRight,sTop));let sp = positions[vertexType];out.pos = vec4f(sp.x * 2.0 - 1.0,1.0 - sp.y * 2.0,0.0,1.0);return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{let upRgb = unpack4x8unorm(cu.upColor).rgb;let downRgb = unpack4x8unorm(cu.downColor).rgb;let base = select(downRgb,upRgb,in.isUp > 0.5);let color = select(base,base * 0.65,in.isWick > 0.5);return vec4f(color,0.92);}`;var M=(q,J,Q)=>(Math.round(q*255)&255|(Math.round(J*255)&255)<<8|(Math.round(Q*255)&255)<<16|-16777216)>>>0,O=28,y={name:"candlestick",shaders:{compute:G,render:V},uniforms:[{name:"maxSamples",type:"f32",default:1e4},{name:"upColor",type:"u32",default:M(0.2,0.7,0.3)},{name:"downColor",type:"u32",default:M(0.9,0.3,0.3)},{name:"binSize",type:"u32",default:8},{name:"interval",type:"f32",default:0}],buffers:[{name:"candleBuffer",bytes:({width:q})=>Math.max(16,q*O),usages:["STORAGE"]}],passes:[{type:"compute",shader:"compute",perSeries:!0,dispatch:({width:q})=>({x:Math.ceil(Math.max(1,q)/v)}),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"x-data"},{binding:2,source:"y-data"},{binding:3,source:"candleBuffer",write:!0},{binding:4,source:"series-info"},{binding:5,source:"series-index"},{binding:6,source:"custom-uniforms"},{binding:7,source:"open-data"},{binding:8,source:"high-data"},{binding:9,source:"low-data"}]},{type:"render",shader:"render",topology:"triangle-list",loadOp:"load",blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha"}},draw:({width:q})=>q*30,bindings:[{binding:0,source:"uniforms"},{binding:1,source:"candleBuffer"},{binding:2,source:"custom-uniforms"}]}],computeBounds(q){let J=1/0,Q=-1/0,Z=1/0,$=-1/0;for(let z of q){for(let j of z.rawX){if(j<J)J=j;if(j>Q)Q=j}for(let j of z.extra.high??[])if(j>$)$=j;for(let j of z.extra.low??[])if(j<Z)Z=j}if(!isFinite(J))return{minX:0,maxX:1,minY:0,maxY:1};let W=(Q-J)*0.05||1,k=($-Z)*0.1||1;return{minX:J-W,maxX:Q+W,minY:Z-k,maxY:$+k}}};
|
|
33
|
+
export{G as a,M as b,y as c};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{f as a,g as e,h as t}from"./chunk-64q9a7nw.js";var n=`${e}struct LineUniforms{maxSamplesPerPixel: u32,_p1: u32,_p2: u32,_p3: u32};struct LineData{screenX: f32,minScreenY: f32,maxScreenY: f32,valid: f32,};@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> dataX: array<f32>;@group(0)@binding(2)var<storage,read> dataY: array<f32>;@group(0)@binding(3)var<storage,read_write> lineData: array<LineData>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> lu: LineUniforms;${t}@compute @workgroup_size(${a})fn main(@builtin(global_invocation_id)id: vec3u){let outputIdx = id.x;let maxCols = u32(u.width);let count = u.pointCount;if(outputIdx >= maxCols || count == 0u){if(outputIdx < maxCols){lineData[outputIdx] = LineData(-1.0,-1.0,-1.0,0.0);}return;}let viewRangeX = u.viewMaxX - u.viewMinX;let viewRangeY = u.viewMaxY - u.viewMinY;if(viewRangeX < 0.0001 || viewRangeY < 0.0001){lineData[outputIdx] = LineData(-1.0,-1.0,-1.0,0.0);return;}let relPx = f32(outputIdx);let pixelMinX = u.viewMinX +(relPx / u.width)* viewRangeX;let pixelMaxX = u.viewMinX +((relPx + 1.0)/ u.width)* viewRangeX;if(pixelMaxX < u.dataMinX || pixelMinX > u.dataMaxX){lineData[outputIdx] = LineData(-1.0,-1.0,-1.0,0.0);return;}let startIdx = lowerBound(pixelMinX,count);var endIdx = lowerBound(pixelMaxX,count);endIdx = min(endIdx,count);let centerX =(pixelMinX + pixelMaxX)* 0.5;if(startIdx >= endIdx){var bestIdx = startIdx;if(startIdx > 0u && startIdx < count){let distPrev = abs(dataX[startIdx - 1u] - centerX);let distCurr = abs(dataX[startIdx] - centerX);if(distPrev < distCurr){bestIdx = startIdx - 1u;}}else if(startIdx >= count && count > 0u){bestIdx = count - 1u;}if(bestIdx >= count){lineData[outputIdx] = LineData(-1.0,-1.0,-1.0,0.0);return;}let y = dataY[bestIdx];let normY =(y - u.viewMinY)/ viewRangeY;let screenY = 1.0 - normY;let normX =(dataX[bestIdx] - u.viewMinX)/ viewRangeX;let screenX = normX;lineData[outputIdx] = LineData(screenX,screenY,screenY,1.0);return;}var dataMinY = dataY[startIdx];var dataMaxY = dataY[startIdx];let rangeCount = endIdx - startIdx;let maxSamples = lu.maxSamplesPerPixel;if(maxSamples > 1u && rangeCount > maxSamples){let stride = f32(rangeCount - 1u)/ f32(maxSamples - 1u);for(var s = 0u;s < maxSamples;s++){let idx = startIdx + u32(f32(s)* stride);if(idx < endIdx){let y = dataY[idx];dataMinY = min(dataMinY,y);dataMaxY = max(dataMaxY,y);}}let lastY = dataY[endIdx - 1u];dataMinY = min(dataMinY,lastY);dataMaxY = max(dataMaxY,lastY);}else{for(var i = startIdx + 1u;i < endIdx;i++){let y = dataY[i];dataMinY = min(dataMinY,y);dataMaxY = max(dataMaxY,y);}}let normX =(centerX - u.viewMinX)/ viewRangeX;let screenX = normX;let normMaxY =(dataMaxY - u.viewMinY)/ viewRangeY;let normMinY =(dataMinY - u.viewMinY)/ viewRangeY;let minScreenY = 1.0 - normMaxY;let maxScreenY = 1.0 - normMinY;lineData[outputIdx] = LineData(screenX,minScreenY,maxScreenY,1.0);}`,r=`${e}struct LineData{screenX: f32,minScreenY: f32,maxScreenY: f32,valid: f32,};@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> lineData: array<LineData>;@group(0)@binding(2)var<storage,read> allSeries: array<SeriesInfo>;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)alpha: f32,@location(1)@interpolate(flat)seriesIdx: u32,};@vertex fn vs(@builtin(vertex_index)vi: u32,@builtin(instance_index)series_idx: u32)-> VertexOutput{var out: VertexOutput;out.seriesIdx = series_idx;let maxCols = u32(u.width);let segIdx = vi / 2u;let endpoint = vi % 2u;if(segIdx < maxCols){let d = lineData[segIdx];let y = select(d.maxScreenY,d.minScreenY,endpoint == 0u);out.pos = vec4f(d.screenX * 2.0 - 1.0,1.0 - y * 2.0,0.0,d.valid);out.alpha = d.valid;}else{let connIdx = segIdx - maxCols;if(connIdx + 1u >= maxCols){out.pos = vec4f(0.0,0.0,0.0,0.0);out.alpha = 0.0;return out;}let d0 = lineData[connIdx];let d1 = lineData[connIdx + 1u];let segValid = min(d0.valid,d1.valid);if(endpoint == 0u){let midY =(d0.minScreenY + d0.maxScreenY)* 0.5;out.pos = vec4f(d0.screenX * 2.0 - 1.0,1.0 - midY * 2.0,0.0,segValid);}else{let midY =(d1.minScreenY + d1.maxScreenY)* 0.5;out.pos = vec4f(d1.screenX * 2.0 - 1.0,1.0 - midY * 2.0,0.0,segValid);}out.alpha = segValid;}return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{if(in.alpha < 0.1){discard;}let series = allSeries[in.seriesIdx];return vec4f(series.color.rgb,1.0);}`;
|
|
2
|
+
export{n as d,r as e};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/plugins/coords.ts
|
|
2
|
+
function dataToScreen(dataX, dataY, chart, width, height) {
|
|
3
|
+
const rX = chart.bounds.maxX - chart.bounds.minX;
|
|
4
|
+
const rY = chart.bounds.maxY - chart.bounds.minY;
|
|
5
|
+
const vW = rX / chart.view.zoomX;
|
|
6
|
+
const vH = rY / chart.view.zoomY;
|
|
7
|
+
const vMinX = chart.bounds.minX + chart.view.panX * rX;
|
|
8
|
+
const vMinY = chart.bounds.minY + chart.view.panY * rY;
|
|
9
|
+
return {
|
|
10
|
+
x: (dataX - vMinX) / vW * width,
|
|
11
|
+
y: height * (1 - (dataY - vMinY) / vH)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function screenToData(screenX, screenY, chart, width, height) {
|
|
15
|
+
const rX = chart.bounds.maxX - chart.bounds.minX;
|
|
16
|
+
const rY = chart.bounds.maxY - chart.bounds.minY;
|
|
17
|
+
const vW = rX / chart.view.zoomX;
|
|
18
|
+
const vH = rY / chart.view.zoomY;
|
|
19
|
+
const vMinX = chart.bounds.minX + chart.view.panX * rX;
|
|
20
|
+
const vMinY = chart.bounds.minY + chart.view.panY * rY;
|
|
21
|
+
return {
|
|
22
|
+
x: vMinX + screenX / width * vW,
|
|
23
|
+
y: vMinY + (1 - screenY / height) * vH
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { dataToScreen, screenToData };
|