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
|
+
BINARY_SEARCH,
|
|
3
|
+
COMPUTE_WG,
|
|
4
|
+
UNIFORM_STRUCT
|
|
5
|
+
} from "./chunk-0jepamv9.js";
|
|
6
|
+
|
|
7
|
+
// src/shaders/candlestick.ts
|
|
8
|
+
var CANDLE_TYPES = `
|
|
9
|
+
struct CandleUniforms {
|
|
10
|
+
maxSamples: f32,
|
|
11
|
+
upColor: u32,
|
|
12
|
+
downColor: u32,
|
|
13
|
+
binSize: u32,
|
|
14
|
+
interval: f32,
|
|
15
|
+
_p0: u32, _p1: u32, _p2: u32,
|
|
16
|
+
};
|
|
17
|
+
struct CandleData {
|
|
18
|
+
screenX: f32,
|
|
19
|
+
barWidth: f32,
|
|
20
|
+
low: f32,
|
|
21
|
+
bodyBottom: f32,
|
|
22
|
+
bodyTop: f32,
|
|
23
|
+
high: f32,
|
|
24
|
+
isUp: f32,
|
|
25
|
+
};`;
|
|
26
|
+
var EFFECTIVE_INTERVAL = `
|
|
27
|
+
fn effectiveInterval() -> f32 {
|
|
28
|
+
if (cu.interval > 0.0) { return cu.interval; }
|
|
29
|
+
let raw = (u.viewMaxX - u.viewMinX) / u.width * f32(cu.binSize);
|
|
30
|
+
let steps = array<f32, 20>(
|
|
31
|
+
1.0, 2.0, 5.0, 10.0, 15.0, 30.0,
|
|
32
|
+
60.0, 120.0, 300.0, 600.0, 900.0, 1800.0,
|
|
33
|
+
3600.0, 7200.0, 14400.0, 43200.0,
|
|
34
|
+
86400.0, 259200.0, 604800.0, 2592000.0
|
|
35
|
+
);
|
|
36
|
+
for (var i = 0u; i < 20u; i++) {
|
|
37
|
+
if (steps[i] >= raw) { return steps[i]; }
|
|
38
|
+
}
|
|
39
|
+
return raw;
|
|
40
|
+
}`;
|
|
41
|
+
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));}`;
|
|
42
|
+
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);}`;
|
|
43
|
+
|
|
44
|
+
// src/charts/candlestick.ts
|
|
45
|
+
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;
|
|
46
|
+
var BYTES_PER_CANDLE = 7 * 4;
|
|
47
|
+
var CandlestickChart = {
|
|
48
|
+
name: "candlestick",
|
|
49
|
+
shaders: {
|
|
50
|
+
compute: CANDLESTICK_COMPUTE_SHADER,
|
|
51
|
+
render: CANDLESTICK_RENDER_SHADER
|
|
52
|
+
},
|
|
53
|
+
uniforms: [
|
|
54
|
+
{ name: "maxSamples", type: "f32", default: 1e4 },
|
|
55
|
+
{ name: "upColor", type: "u32", default: packRGB(0.2, 0.7, 0.3) },
|
|
56
|
+
{ name: "downColor", type: "u32", default: packRGB(0.9, 0.3, 0.3) },
|
|
57
|
+
{ name: "binSize", type: "u32", default: 8 },
|
|
58
|
+
{ name: "interval", type: "f32", default: 0 }
|
|
59
|
+
],
|
|
60
|
+
buffers: [
|
|
61
|
+
{
|
|
62
|
+
name: "candleBuffer",
|
|
63
|
+
bytes: ({ width }) => Math.max(16, width * BYTES_PER_CANDLE),
|
|
64
|
+
usages: ["STORAGE"]
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
passes: [
|
|
68
|
+
{
|
|
69
|
+
type: "compute",
|
|
70
|
+
shader: "compute",
|
|
71
|
+
perSeries: true,
|
|
72
|
+
dispatch: ({ width }) => ({ x: Math.ceil(Math.max(1, width) / COMPUTE_WG) }),
|
|
73
|
+
bindings: [
|
|
74
|
+
{ binding: 0, source: "uniforms" },
|
|
75
|
+
{ binding: 1, source: "x-data" },
|
|
76
|
+
{ binding: 2, source: "y-data" },
|
|
77
|
+
{ binding: 3, source: "candleBuffer", write: true },
|
|
78
|
+
{ binding: 4, source: "series-info" },
|
|
79
|
+
{ binding: 5, source: "series-index" },
|
|
80
|
+
{ binding: 6, source: "custom-uniforms" },
|
|
81
|
+
{ binding: 7, source: "open-data" },
|
|
82
|
+
{ binding: 8, source: "high-data" },
|
|
83
|
+
{ binding: 9, source: "low-data" }
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: "render",
|
|
88
|
+
shader: "render",
|
|
89
|
+
topology: "triangle-list",
|
|
90
|
+
loadOp: "load",
|
|
91
|
+
blend: {
|
|
92
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha" },
|
|
93
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }
|
|
94
|
+
},
|
|
95
|
+
draw: ({ width }) => width * 30,
|
|
96
|
+
bindings: [
|
|
97
|
+
{ binding: 0, source: "uniforms" },
|
|
98
|
+
{ binding: 1, source: "candleBuffer" },
|
|
99
|
+
{ binding: 2, source: "custom-uniforms" }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
computeBounds(series) {
|
|
104
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
105
|
+
for (const s of series) {
|
|
106
|
+
for (const x of s.rawX) {
|
|
107
|
+
if (x < minX)
|
|
108
|
+
minX = x;
|
|
109
|
+
if (x > maxX)
|
|
110
|
+
maxX = x;
|
|
111
|
+
}
|
|
112
|
+
for (const y of s.extra.high ?? []) {
|
|
113
|
+
if (y > maxY)
|
|
114
|
+
maxY = y;
|
|
115
|
+
}
|
|
116
|
+
for (const y of s.extra.low ?? []) {
|
|
117
|
+
if (y < minY)
|
|
118
|
+
minY = y;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!isFinite(minX))
|
|
122
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
123
|
+
const px = (maxX - minX) * 0.05 || 1;
|
|
124
|
+
const py = (maxY - minY) * 0.1 || 1;
|
|
125
|
+
return { minX: minX - px, maxX: maxX + px, minY: minY - py, maxY: maxY + py };
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export { CANDLESTICK_COMPUTE_SHADER, packRGB, CandlestickChart };
|
|
@@ -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 r,g as s};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BINARY_SEARCH,
|
|
3
|
+
COMPUTE_WG,
|
|
4
|
+
UNIFORM_STRUCT
|
|
5
|
+
} from "./chunk-0jepamv9.js";
|
|
6
|
+
|
|
7
|
+
// src/shaders/line.ts
|
|
8
|
+
var LINE_COMPUTE_SHADER = `${UNIFORM_STRUCT}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;${BINARY_SEARCH}@compute @workgroup_size(${COMPUTE_WG})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);}`;
|
|
9
|
+
var LINE_RENDER_SHADER = `${UNIFORM_STRUCT}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);}`;
|
|
10
|
+
|
|
11
|
+
export { LINE_COMPUTE_SHADER, LINE_RENDER_SHADER };
|