chartai 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart-library.d.ts +33 -146
- package/dist/chart-library.d.ts.map +1 -1
- package/dist/chart-library.js +378 -321
- package/dist/chart-library.min.js +1 -1
- package/dist/charts/area.d.ts +6 -0
- package/dist/charts/area.d.ts.map +1 -0
- package/dist/charts/area.js +65 -0
- package/dist/charts/area.min.js +1 -0
- package/dist/charts/bar.d.ts +11 -0
- package/dist/charts/bar.d.ts.map +1 -0
- package/dist/charts/bar.js +65 -0
- package/dist/charts/bar.min.js +1 -0
- package/dist/charts/boids.js +167 -0
- package/dist/charts/boids.min.js +18 -0
- package/dist/charts/candlestick.d.ts +21 -0
- package/dist/charts/candlestick.d.ts.map +1 -0
- package/dist/charts/candlestick.js +132 -0
- package/dist/charts/candlestick.min.js +32 -0
- package/dist/charts/line.d.ts +12 -0
- package/dist/charts/line.d.ts.map +1 -0
- package/dist/charts/line.js +62 -0
- package/dist/charts/line.min.js +1 -0
- package/dist/charts/scatter.d.ts +11 -0
- package/dist/charts/scatter.d.ts.map +1 -0
- package/dist/charts/scatter.js +46 -0
- package/dist/charts/scatter.min.js +1 -0
- package/dist/chunk-0jepamv9.js +7 -0
- package/dist/chunk-1p45ex5n.min.js +2 -0
- package/dist/chunk-831dem4f.js +4 -0
- package/dist/chunk-93yrr7er.js +35 -0
- package/dist/chunk-94kc81rr.min.js +2 -0
- package/dist/chunk-a27be8p9.js +105 -0
- package/dist/chunk-bfyv7z27.min.js +2 -0
- package/dist/chunk-dmaxrg6s.min.js +2 -0
- package/dist/chunk-e7d3zgw5.min.js +2 -0
- package/dist/chunk-g6m56ptf.js +609 -0
- package/dist/chunk-m17t3vjq.js +9 -0
- package/dist/chunk-me3qaz3m.min.js +2 -0
- package/dist/chunk-qr6mweck.min.js +2 -0
- package/dist/chunk-yabjrff2.js +11 -0
- package/dist/gpu-worker.js +625 -686
- package/dist/gpu-worker.min.js +1 -1
- package/dist/msg.d.ts +33 -0
- package/dist/msg.d.ts.map +1 -0
- package/dist/plugins/coords.d.ts +18 -0
- package/dist/plugins/coords.d.ts.map +1 -0
- package/dist/plugins/hover.d.ts +15 -2
- package/dist/plugins/hover.d.ts.map +1 -1
- package/dist/plugins/hover.js +92 -13
- package/dist/plugins/hover.min.js +1 -1
- package/dist/plugins/labels-panel.d.ts +4 -0
- package/dist/plugins/labels-panel.d.ts.map +1 -0
- package/dist/plugins/labels-panel.js +122 -0
- package/dist/plugins/labels-panel.min.js +1 -0
- package/dist/plugins/labels.d.ts +17 -2
- package/dist/plugins/labels.d.ts.map +1 -1
- package/dist/plugins/labels.js +11 -99
- package/dist/plugins/labels.min.js +1 -1
- package/dist/plugins/legend.d.ts +16 -0
- package/dist/plugins/legend.d.ts.map +1 -0
- package/dist/plugins/legend.js +282 -0
- package/dist/plugins/legend.min.js +21 -0
- package/dist/plugins/shared.d.ts +7 -0
- package/dist/plugins/shared.d.ts.map +1 -0
- package/dist/plugins/zoom.d.ts +10 -2
- package/dist/plugins/zoom.d.ts.map +1 -1
- package/dist/plugins/zoom.js +63 -62
- package/dist/plugins/zoom.min.js +1 -1
- package/dist/types.d.ts +179 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/dist/types.min.js +0 -0
- package/dist/worker-inline.d.ts +1 -1
- package/dist/worker-inline.d.ts.map +1 -1
- package/package.json +11 -11
- package/readme.md +51 -42
- package/dist/chunk-bgfkgcmg.js +0 -25
- package/dist/chunk-cj3zanvs.min.js +0 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BINARY_SEARCH,
|
|
3
|
+
COMPUTE_WG,
|
|
4
|
+
UNIFORM_STRUCT
|
|
5
|
+
} from "../chunk-0jepamv9.js";
|
|
6
|
+
import"../chunk-m17t3vjq.js";
|
|
7
|
+
|
|
8
|
+
// src/shaders/candlestick.ts
|
|
9
|
+
var CANDLE_TYPES = `
|
|
10
|
+
struct CandleUniforms {
|
|
11
|
+
maxSamples: f32,
|
|
12
|
+
upColor: u32,
|
|
13
|
+
downColor: u32,
|
|
14
|
+
binSize: u32,
|
|
15
|
+
interval: f32,
|
|
16
|
+
_p0: u32, _p1: u32, _p2: u32,
|
|
17
|
+
};
|
|
18
|
+
struct CandleData {
|
|
19
|
+
screenX: f32,
|
|
20
|
+
barWidth: f32,
|
|
21
|
+
low: f32,
|
|
22
|
+
bodyBottom: f32,
|
|
23
|
+
bodyTop: f32,
|
|
24
|
+
high: f32,
|
|
25
|
+
isUp: f32,
|
|
26
|
+
};`;
|
|
27
|
+
var EFFECTIVE_INTERVAL = `
|
|
28
|
+
fn effectiveInterval() -> f32 {
|
|
29
|
+
if (cu.interval > 0.0) { return cu.interval; }
|
|
30
|
+
let raw = (u.viewMaxX - u.viewMinX) / u.width * f32(cu.binSize);
|
|
31
|
+
let steps = array<f32, 20>(
|
|
32
|
+
1.0, 2.0, 5.0, 10.0, 15.0, 30.0,
|
|
33
|
+
60.0, 120.0, 300.0, 600.0, 900.0, 1800.0,
|
|
34
|
+
3600.0, 7200.0, 14400.0, 43200.0,
|
|
35
|
+
86400.0, 259200.0, 604800.0, 2592000.0
|
|
36
|
+
);
|
|
37
|
+
for (var i = 0u; i < 20u; i++) {
|
|
38
|
+
if (steps[i] >= raw) { return steps[i]; }
|
|
39
|
+
}
|
|
40
|
+
return raw;
|
|
41
|
+
}`;
|
|
42
|
+
var CANDLESTICK_COMPUTE_SHADER = `${UNIFORM_STRUCT}${CANDLE_TYPES}@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>;${BINARY_SEARCH}${EFFECTIVE_INTERVAL}@compute @workgroup_size(${COMPUTE_WG})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));}`;
|
|
43
|
+
var CANDLESTICK_RENDER_SHADER = `${UNIFORM_STRUCT}${CANDLE_TYPES}@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;${EFFECTIVE_INTERVAL}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);}`;
|
|
44
|
+
|
|
45
|
+
// src/charts/candlestick.ts
|
|
46
|
+
var packRGB = (r, g, b) => (Math.round(r * 255) & 255 | (Math.round(g * 255) & 255) << 8 | (Math.round(b * 255) & 255) << 16 | 255 << 24) >>> 0;
|
|
47
|
+
var BYTES_PER_CANDLE = 7 * 4;
|
|
48
|
+
var CandlestickChart = {
|
|
49
|
+
name: "candlestick",
|
|
50
|
+
shaders: {
|
|
51
|
+
compute: CANDLESTICK_COMPUTE_SHADER,
|
|
52
|
+
render: CANDLESTICK_RENDER_SHADER
|
|
53
|
+
},
|
|
54
|
+
uniforms: [
|
|
55
|
+
{ name: "maxSamples", type: "f32", default: 1e4 },
|
|
56
|
+
{ name: "upColor", type: "u32", default: packRGB(0.2, 0.7, 0.3) },
|
|
57
|
+
{ name: "downColor", type: "u32", default: packRGB(0.9, 0.3, 0.3) },
|
|
58
|
+
{ name: "binSize", type: "u32", default: 8 },
|
|
59
|
+
{ name: "interval", type: "f32", default: 0 }
|
|
60
|
+
],
|
|
61
|
+
buffers: [
|
|
62
|
+
{
|
|
63
|
+
name: "candleBuffer",
|
|
64
|
+
bytes: ({ width }) => Math.max(16, width * BYTES_PER_CANDLE),
|
|
65
|
+
usages: ["STORAGE"]
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
passes: [
|
|
69
|
+
{
|
|
70
|
+
type: "compute",
|
|
71
|
+
shader: "compute",
|
|
72
|
+
perSeries: true,
|
|
73
|
+
dispatch: ({ width }) => ({ x: Math.ceil(Math.max(1, width) / COMPUTE_WG) }),
|
|
74
|
+
bindings: [
|
|
75
|
+
{ binding: 0, source: "uniforms" },
|
|
76
|
+
{ binding: 1, source: "x-data" },
|
|
77
|
+
{ binding: 2, source: "y-data" },
|
|
78
|
+
{ binding: 3, source: "candleBuffer", write: true },
|
|
79
|
+
{ binding: 4, source: "series-info" },
|
|
80
|
+
{ binding: 5, source: "series-index" },
|
|
81
|
+
{ binding: 6, source: "custom-uniforms" },
|
|
82
|
+
{ binding: 7, source: "open-data" },
|
|
83
|
+
{ binding: 8, source: "high-data" },
|
|
84
|
+
{ binding: 9, source: "low-data" }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
type: "render",
|
|
89
|
+
shader: "render",
|
|
90
|
+
topology: "triangle-list",
|
|
91
|
+
loadOp: "load",
|
|
92
|
+
blend: {
|
|
93
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha" },
|
|
94
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }
|
|
95
|
+
},
|
|
96
|
+
draw: ({ width }) => width * 30,
|
|
97
|
+
bindings: [
|
|
98
|
+
{ binding: 0, source: "uniforms" },
|
|
99
|
+
{ binding: 1, source: "candleBuffer" },
|
|
100
|
+
{ binding: 2, source: "custom-uniforms" }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
computeBounds(series) {
|
|
105
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
106
|
+
for (const s of series) {
|
|
107
|
+
for (const x of s.rawX) {
|
|
108
|
+
if (x < minX)
|
|
109
|
+
minX = x;
|
|
110
|
+
if (x > maxX)
|
|
111
|
+
maxX = x;
|
|
112
|
+
}
|
|
113
|
+
for (const y of s.extra.high ?? []) {
|
|
114
|
+
if (y > maxY)
|
|
115
|
+
maxY = y;
|
|
116
|
+
}
|
|
117
|
+
for (const y of s.extra.low ?? []) {
|
|
118
|
+
if (y < minY)
|
|
119
|
+
minY = y;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!isFinite(minX))
|
|
123
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
124
|
+
const px = (maxX - minX) * 0.05 || 1;
|
|
125
|
+
const py = (maxY - minY) * 0.1 || 1;
|
|
126
|
+
return { minX: minX - px, maxX: maxX + px, minY: minY - py, maxY: maxY + py };
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
export {
|
|
130
|
+
packRGB,
|
|
131
|
+
CandlestickChart
|
|
132
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import{c as v,d as K,e as H}from"../chunk-dmaxrg6s.js";import"../chunk-me3qaz3m.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}}};export{M as packRGB,y as CandlestickChart};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RendererPlugin } from "../types.ts";
|
|
2
|
+
export interface LineConfig {
|
|
3
|
+
pointSize?: number;
|
|
4
|
+
maxSamplesPerPixel?: number;
|
|
5
|
+
}
|
|
6
|
+
declare module "../types.ts" {
|
|
7
|
+
interface ChartTypeRegistry {
|
|
8
|
+
line: LineConfig;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export declare const LineChart: RendererPlugin;
|
|
12
|
+
//# sourceMappingURL=line.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/charts/line.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,iBAAiB;QACzB,IAAI,EAAE,UAAU,CAAC;KAClB;CACF;AAED,eAAO,MAAM,SAAS,EAAE,cAiDvB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LINE_COMPUTE_SHADER,
|
|
3
|
+
LINE_RENDER_SHADER
|
|
4
|
+
} from "../chunk-yabjrff2.js";
|
|
5
|
+
import {
|
|
6
|
+
COMPUTE_WG
|
|
7
|
+
} from "../chunk-0jepamv9.js";
|
|
8
|
+
import"../chunk-m17t3vjq.js";
|
|
9
|
+
|
|
10
|
+
// src/charts/line.ts
|
|
11
|
+
var LineChart = {
|
|
12
|
+
name: "line",
|
|
13
|
+
shaders: {
|
|
14
|
+
compute: LINE_COMPUTE_SHADER,
|
|
15
|
+
render: LINE_RENDER_SHADER
|
|
16
|
+
},
|
|
17
|
+
uniforms: [
|
|
18
|
+
{ name: "maxSamplesPerPixel", type: "u32", default: 1e4 }
|
|
19
|
+
],
|
|
20
|
+
buffers: [
|
|
21
|
+
{
|
|
22
|
+
name: "lineBuffer",
|
|
23
|
+
bytes: ({ width }) => Math.max(16, width * 4 * 4),
|
|
24
|
+
usages: ["STORAGE"]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
passes: [
|
|
28
|
+
{
|
|
29
|
+
type: "compute",
|
|
30
|
+
shader: "compute",
|
|
31
|
+
perSeries: true,
|
|
32
|
+
dispatch: ({ width }) => ({ x: Math.ceil(Math.max(1, width) / COMPUTE_WG) }),
|
|
33
|
+
bindings: [
|
|
34
|
+
{ binding: 0, source: "uniforms" },
|
|
35
|
+
{ binding: 1, source: "x-data" },
|
|
36
|
+
{ binding: 2, source: "y-data" },
|
|
37
|
+
{ binding: 3, source: "lineBuffer", write: true },
|
|
38
|
+
{ binding: 4, source: "series-info" },
|
|
39
|
+
{ binding: 5, source: "custom-uniforms" }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "render",
|
|
44
|
+
shader: "render",
|
|
45
|
+
topology: "line-list",
|
|
46
|
+
loadOp: "load",
|
|
47
|
+
blend: {
|
|
48
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha" },
|
|
49
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }
|
|
50
|
+
},
|
|
51
|
+
draw: ({ width }) => Math.max(0, width * 4 - 2),
|
|
52
|
+
bindings: [
|
|
53
|
+
{ binding: 0, source: "uniforms" },
|
|
54
|
+
{ binding: 1, source: "lineBuffer" },
|
|
55
|
+
{ binding: 2, source: "series-info" }
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
export {
|
|
61
|
+
LineChart
|
|
62
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as k,b as q}from"../chunk-1p45ex5n.js";import{c as j}from"../chunk-dmaxrg6s.js";import"../chunk-me3qaz3m.js";var F={name:"line",shaders:{compute:k,render:q},uniforms:[{name:"maxSamplesPerPixel",type:"u32",default:1e4}],buffers:[{name:"lineBuffer",bytes:({width:b})=>Math.max(16,b*4*4),usages:["STORAGE"]}],passes:[{type:"compute",shader:"compute",perSeries:!0,dispatch:({width:b})=>({x:Math.ceil(Math.max(1,b)/j)}),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"x-data"},{binding:2,source:"y-data"},{binding:3,source:"lineBuffer",write:!0},{binding:4,source:"series-info"},{binding:5,source:"custom-uniforms"}]},{type:"render",shader:"render",topology:"line-list",loadOp:"load",blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha"}},draw:({width:b})=>Math.max(0,b*4-2),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"lineBuffer"},{binding:2,source:"series-info"}]}]};export{F as LineChart};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RendererPlugin } from "../types.ts";
|
|
2
|
+
export interface ScatterConfig {
|
|
3
|
+
pointSize?: number;
|
|
4
|
+
}
|
|
5
|
+
declare module "../types.ts" {
|
|
6
|
+
interface ChartTypeRegistry {
|
|
7
|
+
scatter: ScatterConfig;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare const ScatterChart: RendererPlugin;
|
|
11
|
+
//# sourceMappingURL=scatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scatter.d.ts","sourceRoot":"","sources":["../../src/charts/scatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,iBAAiB;QACzB,OAAO,EAAE,aAAa,CAAC;KACxB;CACF;AAID,eAAO,MAAM,YAAY,EAAE,cA+B1B,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMPUTE_WG,
|
|
3
|
+
UNIFORM_STRUCT
|
|
4
|
+
} from "../chunk-0jepamv9.js";
|
|
5
|
+
import"../chunk-m17t3vjq.js";
|
|
6
|
+
|
|
7
|
+
// src/shaders/scatter.ts
|
|
8
|
+
var SCATTER_COMPUTE_SHADER = `${UNIFORM_STRUCT}struct ScatterUniforms{dispatchXCount: u32,pointSize: 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 outputTex: texture_storage_2d<rgba8unorm,write>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(6)var<uniform> su: ScatterUniforms;@compute @workgroup_size(${COMPUTE_WG})fn main(@builtin(global_invocation_id)id: vec3u){let series = allSeries[seriesIdx.index];let visStart = series.visibleRange.x;let visCount = series.visibleRange.y;let localIdx = id.y * su.dispatchXCount + id.x;if(localIdx >= visCount){return;}let idx = visStart + localIdx;let count = u.pointCount;if(idx >= count){return;}let x = dataX[idx];let y = dataY[idx];if(y < u.viewMinY || y > u.viewMaxY){return;}let width = u32(u.width);let height = u32(u.height);let rangeX = u.viewMaxX - u.viewMinX;let rangeY = u.viewMaxY - u.viewMinY;if(rangeX < 0.0001 || rangeY < 0.0001){return;}let normX =(x - u.viewMinX)/ rangeX;let normY =(y - u.viewMinY)/ rangeY;let screenX = normX;let screenY = 1.0 - normY;let pixelX = i32(screenX * f32(width));let pixelY = i32(screenY * f32(height));if(idx > visStart){let prevX = dataX[idx - 1u];let prevY = dataY[idx - 1u];let prevNormX =(prevX - u.viewMinX)/ rangeX;let prevNormY =(prevY - u.viewMinY)/ rangeY;let prevPx = i32(prevNormX * f32(width));let prevPy = i32((1.0 - prevNormY)* f32(height));if(pixelX == prevPx && pixelY == prevPy){return;}}let iWidth = i32(width);let iHeight = i32(height);if(pixelX < 0 || pixelX >= iWidth){return;}if(pixelY < 0 || pixelY >= iHeight){return;}let color = series.color;let radius = i32(su.pointSize);for(var dy = -radius;dy <= radius;dy++){for(var dx = -radius;dx <= radius;dx++){if(dx * dx + dy * dy > radius * radius){continue;}let px = pixelX + dx;let py = pixelY + dy;if(px >= 0 && px < iWidth && py >= 0 && py < iHeight){textureStore(outputTex,vec2i(px,py),color);}}}}`;
|
|
9
|
+
|
|
10
|
+
// src/charts/scatter.ts
|
|
11
|
+
var MAX_WG_DIM = 65535;
|
|
12
|
+
var ScatterChart = {
|
|
13
|
+
name: "scatter",
|
|
14
|
+
shaders: {
|
|
15
|
+
compute: SCATTER_COMPUTE_SHADER
|
|
16
|
+
},
|
|
17
|
+
uniforms: [
|
|
18
|
+
{ name: "dispatchXCount", type: "u32", default: 1 },
|
|
19
|
+
{ name: "pointSize", type: "f32", default: 3 }
|
|
20
|
+
],
|
|
21
|
+
passes: [
|
|
22
|
+
{
|
|
23
|
+
type: "compute",
|
|
24
|
+
shader: "compute",
|
|
25
|
+
perSeries: true,
|
|
26
|
+
dispatch: ({ samples }) => {
|
|
27
|
+
const totalWG = Math.ceil(Math.max(1, samples) / COMPUTE_WG);
|
|
28
|
+
const wgX = Math.min(totalWG, MAX_WG_DIM);
|
|
29
|
+
const wgY = Math.ceil(totalWG / MAX_WG_DIM);
|
|
30
|
+
return { x: wgX, y: wgY, xCount: wgX * COMPUTE_WG };
|
|
31
|
+
},
|
|
32
|
+
bindings: [
|
|
33
|
+
{ binding: 0, source: "uniforms" },
|
|
34
|
+
{ binding: 1, source: "x-data" },
|
|
35
|
+
{ binding: 2, source: "y-data" },
|
|
36
|
+
{ binding: 3, source: "render-target", write: true },
|
|
37
|
+
{ binding: 4, source: "series-info" },
|
|
38
|
+
{ binding: 5, source: "series-index" },
|
|
39
|
+
{ binding: 6, source: "custom-uniforms" }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
|
+
export {
|
|
45
|
+
ScatterChart
|
|
46
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as e,d as t}from"../chunk-dmaxrg6s.js";import"../chunk-me3qaz3m.js";var n=`${t}struct ScatterUniforms{dispatchXCount: u32,pointSize: 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 outputTex: texture_storage_2d<rgba8unorm,write>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(6)var<uniform> su: ScatterUniforms;@compute @workgroup_size(${e})fn main(@builtin(global_invocation_id)id: vec3u){let series = allSeries[seriesIdx.index];let visStart = series.visibleRange.x;let visCount = series.visibleRange.y;let localIdx = id.y * su.dispatchXCount + id.x;if(localIdx >= visCount){return;}let idx = visStart + localIdx;let count = u.pointCount;if(idx >= count){return;}let x = dataX[idx];let y = dataY[idx];if(y < u.viewMinY || y > u.viewMaxY){return;}let width = u32(u.width);let height = u32(u.height);let rangeX = u.viewMaxX - u.viewMinX;let rangeY = u.viewMaxY - u.viewMinY;if(rangeX < 0.0001 || rangeY < 0.0001){return;}let normX =(x - u.viewMinX)/ rangeX;let normY =(y - u.viewMinY)/ rangeY;let screenX = normX;let screenY = 1.0 - normY;let pixelX = i32(screenX * f32(width));let pixelY = i32(screenY * f32(height));if(idx > visStart){let prevX = dataX[idx - 1u];let prevY = dataY[idx - 1u];let prevNormX =(prevX - u.viewMinX)/ rangeX;let prevNormY =(prevY - u.viewMinY)/ rangeY;let prevPx = i32(prevNormX * f32(width));let prevPy = i32((1.0 - prevNormY)* f32(height));if(pixelX == prevPx && pixelY == prevPy){return;}}let iWidth = i32(width);let iHeight = i32(height);if(pixelX < 0 || pixelX >= iWidth){return;}if(pixelY < 0 || pixelY >= iHeight){return;}let color = series.color;let radius = i32(su.pointSize);for(var dy = -radius;dy <= radius;dy++){for(var dx = -radius;dx <= radius;dx++){if(dx * dx + dy * dy > radius * radius){continue;}let px = pixelX + dx;let py = pixelY + dy;if(px >= 0 && px < iWidth && py >= 0 && py < iHeight){textureStore(outputTex,vec2i(px,py),color);}}}}`;var a=65535,g={name:"scatter",shaders:{compute:n},uniforms:[{name:"dispatchXCount",type:"u32",default:1},{name:"pointSize",type:"f32",default:3}],passes:[{type:"compute",shader:"compute",perSeries:!0,dispatch:({samples:o})=>{let i=Math.ceil(Math.max(1,o)/e),r=Math.min(i,a),u=Math.ceil(i/a);return{x:r,y:u,xCount:r*e}},bindings:[{binding:0,source:"uniforms"},{binding:1,source:"x-data"},{binding:2,source:"y-data"},{binding:3,source:"render-target",write:!0},{binding:4,source:"series-info"},{binding:5,source:"series-index"},{binding:6,source:"custom-uniforms"}]}]};export{g as ScatterChart};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// src/shaders/shared.ts
|
|
2
|
+
var COMPUTE_WG = 256;
|
|
3
|
+
var UNIFORM_STRUCT = `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,};`;
|
|
4
|
+
var BINARY_SEARCH = `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;}`;
|
|
5
|
+
var BLIT_SHADER = `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);}`;
|
|
6
|
+
|
|
7
|
+
export { COMPUTE_WG, UNIFORM_STRUCT, BINARY_SEARCH, BLIT_SHADER };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{c as a,d as e,e as t}from"./chunk-dmaxrg6s.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 a,r as b};
|
|
@@ -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
|
+
import{m as B}from"./chunk-bfyv7z27.js";import{o as Y}from"./chunk-me3qaz3m.js";class X{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:B.SET_UNIFORMS,id:this.id,values:G});if("bgColor"in q&&q.bgColor!==void 0){let[J,T,I]=q.bgColor,N=A.el.querySelector("div");if(N)N.style.background=`rgb(${Math.round(J*255)},${Math.round(T*255)},${Math.round(I*255)})`;this._mgr.worker?.postMessage({type:B.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 H=null;function z(q){if(typeof q!=="string")return q;if(!H)H=document.createElement("i"),H.style.cssText="display:none",document.body.appendChild(H);H.style.color=q;let A=getComputedStyle(H).color.match(/\d+/g);return{r:+A[0]/255,g:+A[1]/255,b:+A[2]/255}}function W(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 S{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:B.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 I=devicePixelRatio||1;W(G.backCanvas,J,T),W(G.frontCanvas,J,T);let{bufferSizes:N,perSeriesPassMeta:Z}=this.computeRendererMeta(G.renderer,G);this.worker?.postMessage({type:B.RESIZE,id:F,width:Math.round(J*I),height:Math.round(T*I),bufferSizes:N,perSeriesPassMeta:Z}),this.drawChart(G)}})}static getInstance(){if(!S.instance)S.instance=new S;return S.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 B.GPU_READY:for(let J of this.pendingRenderers)this.sendRendererRegistration(J);this.pendingRenderers=[],q(!0);break;case B.ERROR:console.error("chartai:",G.code),q(!1);break;case B.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:B.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:B.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,I=Math.round(A.width*T),N=Math.round(A.height*T);for(let Z of J){let K={width:I,height:N,samples:Z.rawX.length,seriesCount:J.length,bounds:A.bounds,view:A.view};for(let V of q.buffers??[]){let D=V.bytes(K);F[V.name]=Math.max(F[V.name]??0,D)}G.push(q.passes.map((V)=>({dispatch:V.dispatch?.(K),draw:V.draw?.(K)})))}return{bufferSizes:F,perSeriesPassMeta:G}}create(q){if(!this.worker)throw Error("Call init() before create().");let A=this.renderers.get(q.type);if(!A)throw Error(`No renderer "${q.type}". Call manager.use() with a matching RendererPlugin 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=(Q,$)=>{let U=document.createElement("canvas");return U.style.cssText=`position:absolute;inset:0;width:100%;height:100%;pointer-events:${$};z-index:${Q};`,U},I=T(0,"none"),N=T(1,"auto"),Z=T(2,"none");J.append(I,N,Z),G.appendChild(J),q.container.appendChild(G);let K;try{K=N.transferControlToOffscreen()}catch(Q){throw Error(`Failed to acquire OffscreenCanvas: ${Q}`)}let V=J.getBoundingClientRect(),D=V.width||400,P=V.height||200;if(W(K,D,P),W(I,D,P),W(Z,D,P),q.bgColor){let[Q,$,U]=q.bgColor;J.style.background=`rgb(${Math.round(Q*255)},${Math.round($*255)},${Math.round(U*255)})`}let L={};for(let Q of A.uniforms??[]){let $=q[Q.name];L[Q.name]=typeof $==="number"?$:Q.default}let j={id:F,config:q,el:G,backCanvas:I,frontCanvas:Z,width:D,height:P,series:[],bounds:{minX:0,maxX:1,minY:0,maxY:1},view:{panX:0,panY:0,zoomX:1,zoomY:1},visible:!0,dragging:!1,plugins:[...this.uiPlugins],renderer:A,customUniforms:L};this.charts.set(F,j);let R=devicePixelRatio||1,{bufferSizes:O,perSeriesPassMeta:E}=this.computeRendererMeta(A,j);this.worker.postMessage({type:B.REGISTER_CHART,id:F,canvas:K,rendererName:q.type,bgColor:q.bgColor??null,bufferSizes:O,perSeriesPassMeta:E,customUniformValues:L,width:Math.round(D*R),height:Math.round(P*R)},[K]),this.visibilityObserver.observe(G),this.resizeObserver.observe(J);for(let Q of j.plugins)Q.install?.(j,J);return A.install?.(j,J),this.updateSeries(F,q.series),new X(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:B.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.series=A.map((L)=>{let j=L.x.length,R=z(L.color);if(j===0)return{label:L.label,color:R,rawX:[],rawY:[],extra:{}};let O=Array.from({length:j},(Q,$)=>$).sort((Q,$)=>L.x[Q]-L.x[$]),E={};for(let Q in L)if(Q!=="label"&&Q!=="color"&&Q!=="x"&&Q!=="y"&&Array.isArray(L[Q]))E[Q]=O.map(($)=>L[Q][$]);return{label:L.label,color:R,rawX:O.map((Q)=>L.x[Q]),rawY:O.map((Q)=>L.y[Q]),extra:E}});let G=F.renderer.computeBounds?.(F.series),{minX:J,maxX:T,minY:I,maxY:N}=G??(()=>{let L=1/0,j=-1/0,R=1/0,O=-1/0;for(let $ of F.series)for(let U=0;U<$.rawX.length;U++){if($.rawX[U]<L)L=$.rawX[U];if($.rawX[U]>j)j=$.rawX[U];if($.rawY[U]<R)R=$.rawY[U];if($.rawY[U]>O)O=$.rawY[U]}let E=(j-L)*0.05||1,Q=(O-R)*0.1||1;return{minX:L-E,maxX:j+E,minY:R-Q,maxY:O+Q}})(),Z=F.config.defaultBounds;if(Z){if(Z.minX!==void 0)J=Z.minX;if(Z.maxX!==void 0)T=Z.maxX;if(Z.minY!==void 0)I=Z.minY;if(Z.maxY!==void 0)N=Z.maxY}F.bounds={minX:J,maxX:T,minY:I,maxY:N};let{bufferSizes:K,perSeriesPassMeta:V}=this.computeRendererMeta(F.renderer,F),D=F.series.map((L)=>{let j={};for(let R in L.extra)j[R]=new Float32Array(L.extra[R]);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:j}}),P=D.flatMap((L)=>[L.dataX.buffer,L.dataY.buffer,...Object.values(L.extra).map((j)=>j.buffer)]);this.worker.postMessage({type:B.UPDATE_SERIES,id:q,series:D,bounds:F.bounds,bufferSizes:K,perSeriesPassMeta:V},P),this.sendViewTransform(F),this.drawChart(F)}setSyncViews(q){this._syncViews=q}setTheme(q){this._isDark=q,this.worker?.postMessage({type:B.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 Z of A.plugins)Z.resetView?.(A);let{panX:F,panY:G,zoomX:J,zoomY:T}=A.view,I=performance.now(),N=()=>{let Z=Math.min(1,(performance.now()-I)/300),K=1-Math.pow(1-Z,3);if(A.view.panX=F*(1-K),A.view.panY=G*(1-K),A.view.zoomX=J+(1-J)*K,A.view.zoomY=T+(1-T)*K,this.sendViewTransform(A),this.drawChart(A),this._syncViews)this.syncAllViews(A);if(Z<1)requestAnimationFrame(N)};requestAnimationFrame(N)}requestRender(q){let A=this.charts.get(q);if(A)this.sendViewTransform(A)}sendViewTransform(q){this.worker?.postMessage({type:B.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:B.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 y=S.getInstance();
|
|
2
|
+
export{X as k,y as l};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MARGIN
|
|
3
|
+
} from "./chunk-831dem4f.js";
|
|
4
|
+
import {
|
|
5
|
+
ChartManager
|
|
6
|
+
} from "./chunk-g6m56ptf.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
|
+
var niceTicks = (min, max, count) => {
|
|
12
|
+
const range = max - min;
|
|
13
|
+
if (range <= 0)
|
|
14
|
+
return [min];
|
|
15
|
+
const rough = range / count, mag = 10 ** Math.floor(Math.log10(rough)), res = rough / mag;
|
|
16
|
+
const step = mag * (res <= 1.5 ? 1 : res <= 3 ? 2 : res <= 7 ? 5 : 10);
|
|
17
|
+
const ticks = [];
|
|
18
|
+
for (let v = Math.ceil(min / step) * step;v <= max; v += step)
|
|
19
|
+
ticks.push(v);
|
|
20
|
+
return ticks;
|
|
21
|
+
};
|
|
22
|
+
var getViewState = (chart) => {
|
|
23
|
+
const { width: w, height: h } = chart, m = MARGIN;
|
|
24
|
+
const { bounds: b, view: v } = chart, fullX = b.maxX - b.minX, fullY = b.maxY - b.minY;
|
|
25
|
+
const rx = fullX / v.zoomX, ry = fullY / v.zoomY;
|
|
26
|
+
const mx = b.minX + v.panX * fullX, my = b.minY + v.panY * fullY;
|
|
27
|
+
const bgc = chart.config.bgColor ?? (ChartManager.isDark ? [0.11, 0.11, 0.12] : [0.98, 0.98, 0.98]);
|
|
28
|
+
return {
|
|
29
|
+
w,
|
|
30
|
+
h,
|
|
31
|
+
m,
|
|
32
|
+
rx,
|
|
33
|
+
ry,
|
|
34
|
+
mx,
|
|
35
|
+
my,
|
|
36
|
+
bg: `${Math.round(bgc[0] * 255)},${Math.round(bgc[1] * 255)},${Math.round(bgc[2] * 255)}`,
|
|
37
|
+
font: chart.config.fontFamily ?? DEFAULT_FONT,
|
|
38
|
+
text: chart.config.textColor ?? (ChartManager.isDark ? "#c0c0c0" : "#333333"),
|
|
39
|
+
grid: chart.config.gridColor ?? (ChartManager.isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)")
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
var labelsPlugin = {
|
|
43
|
+
name: "labels",
|
|
44
|
+
beforeDraw(ctx, chart) {
|
|
45
|
+
const { w, h, m, rx, ry, mx, my, grid } = getViewState(chart);
|
|
46
|
+
ctx.strokeStyle = grid;
|
|
47
|
+
ctx.lineWidth = 1;
|
|
48
|
+
ctx.beginPath();
|
|
49
|
+
niceTicks(my, my + ry, 7).forEach((v) => {
|
|
50
|
+
const y = h * (1 - (v - my) / ry);
|
|
51
|
+
if (y > 5 && y < h - m.bottom - 5) {
|
|
52
|
+
ctx.moveTo(m.left, y);
|
|
53
|
+
ctx.lineTo(w, y);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
niceTicks(mx, mx + rx, 8).forEach((v) => {
|
|
57
|
+
const x = w * ((v - mx) / rx);
|
|
58
|
+
if (x > m.left && x < w) {
|
|
59
|
+
ctx.moveTo(x, 0);
|
|
60
|
+
ctx.lineTo(x, h - m.bottom);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
ctx.stroke();
|
|
64
|
+
},
|
|
65
|
+
afterDraw(ctx, chart) {
|
|
66
|
+
const { w, h, m, rx, ry, mx, my, bg, font, text } = getViewState(chart);
|
|
67
|
+
const {
|
|
68
|
+
formatX = String,
|
|
69
|
+
formatY = String,
|
|
70
|
+
labelSize = DEFAULT_LABEL_SIZE
|
|
71
|
+
} = chart.config;
|
|
72
|
+
const drawFade = (dir, x, y, fw, fh) => {
|
|
73
|
+
const g = dir === "left" ? ctx.createLinearGradient(x, 0, x + fw, 0) : ctx.createLinearGradient(0, y, 0, y + fh);
|
|
74
|
+
const alphas = dir === "left" ? [1, 0.7, 0.2, 0.05, 0] : [0, 0.05, 0.2, 0.7, 1];
|
|
75
|
+
[0, 0.35, 0.55, 0.7, 1].forEach((s, i) => g.addColorStop(s, `rgba(${bg},${alphas[i]})`));
|
|
76
|
+
ctx.fillStyle = g;
|
|
77
|
+
ctx.fillRect(x, y, fw, fh);
|
|
78
|
+
};
|
|
79
|
+
drawFade("left", 0, 0, m.left + 20, h);
|
|
80
|
+
drawFade("bottom", 0, h - m.bottom - 20, w, m.bottom + 20);
|
|
81
|
+
ctx.font = `${labelSize}px ${font}`;
|
|
82
|
+
ctx.fillStyle = text;
|
|
83
|
+
ctx.textAlign = "right";
|
|
84
|
+
ctx.textBaseline = "middle";
|
|
85
|
+
niceTicks(my, my + ry, 7).forEach((v) => {
|
|
86
|
+
const y = h * (1 - (v - my) / ry);
|
|
87
|
+
if (y > 5 && y < h - m.bottom - 5)
|
|
88
|
+
ctx.fillText(formatY(v), m.left - 5, y);
|
|
89
|
+
});
|
|
90
|
+
ctx.textAlign = "right";
|
|
91
|
+
ctx.textBaseline = "top";
|
|
92
|
+
niceTicks(mx, mx + rx, 8).forEach((v) => {
|
|
93
|
+
const x = w * ((v - mx) / rx);
|
|
94
|
+
if (x < m.left - 10 || x > w + 30)
|
|
95
|
+
return;
|
|
96
|
+
ctx.save();
|
|
97
|
+
ctx.translate(x, h - m.bottom + 5);
|
|
98
|
+
ctx.rotate(-Math.PI / 14);
|
|
99
|
+
ctx.fillText(formatX(v), 0, 0);
|
|
100
|
+
ctx.restore();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export { DEFAULT_FONT, DEFAULT_LABEL_SIZE, labelsPlugin };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var a={INIT:0,THEME:1,REGISTER_RENDERER:2,REGISTER_CHART:3,UNREGISTER_CHART:4,UPDATE_SERIES:5,RESIZE:6,VIEW_TRANSFORM:7,BATCH_VIEW_TRANSFORM:8,SET_VISIBILITY:9,SET_STYLE:10,SET_UNIFORMS:11,GPU_READY:12,ERROR:13,STATS:14},g={NO_GPU:"e1:no-gpu",NO_ADAPTER:"e2:no-adapter",DEVICE_LOST:"e3:device-lost",NOT_READY:"e4:not-ready",COMPILE:"e5:compile",CTX_GET:"e6:ctx-get",CTX_CFG:"e7:ctx-cfg",TEX:"e8:tex",BIND_S:"e9:bind-s",BIND_C:"e10:bind-c",UPDATE:"e11:update",NO_RENDERER:"e12:no-renderer",RESIZE:"e13:resize"};
|
|
2
|
+
export{a as m,g as n};
|
|
@@ -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 c,t as d,a as e,l as f};
|