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
|
@@ -1 +1 @@
|
|
|
1
|
-
var F=Object.defineProperty;var H=(t,e)=>{for(var i in e)F(t,i,{get:e[i],enumerable:!0,configurable:!0,set:(r)=>e[i]=()=>r})};var O={};H(O,{WORKER_CODE:()=>k});var k='var m=256,X="struct Uniforms{width: f32,height: f32,viewMinX: f32,viewMaxX: f32,viewMinY: f32,viewMaxY: f32,pointCount: u32,isDark: f32,bgR: f32,bgG: f32,bgB: f32,pointRadius: f32,dataMinY: f32,dataMaxY: f32,dataMinX: f32,dataMaxX: f32,visibleStart: u32,visibleCount: u32,dispatchXCount: u32,maxSamplesPerPixel: u32,seriesCount: u32,_pad2: u32,_pad3: u32,_pad4: u32,};struct SeriesInfo{color: vec4f,visibleRange: vec2u,pointSize: f32,_pad: f32,};struct SeriesIndex{index: u32,_pad0: u32,_pad1: u32,_pad2: u32,};",w="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;}";var C="struct Uniforms{width: f32,height: f32,viewMinX: f32,viewMaxX: f32,viewMinY: f32,viewMaxY: f32,pointCount: u32,isDark: f32,bgR: f32,bgG: f32,bgB: f32,pointRadius: f32,dataMinY: f32,dataMaxY: f32,dataMinX: f32,dataMaxX: f32,visibleStart: u32,visibleCount: u32,dispatchXCount: u32,maxSamplesPerPixel: u32,seriesCount: u32,_pad2: u32,_pad3: u32,_pad4: u32,};struct SeriesInfo{color: vec4f,visibleRange: vec2u,pointSize: f32,_pad: f32,};struct SeriesIndex{index: u32,_pad0: u32,_pad1: u32,_pad2: u32,};fn l(c:vec4f)->f32{return dot(c.rgb,vec3f(.299,.587,.114))+c.a*.25;}fn fxaa(u:vec2f,t:texture_2d<f32>,s:sampler)->vec4f{let r=1./vec2f(textureDimensions(t));let rM=textureSampleLevel(t,s,u,0.);let rN=textureSampleLevel(t,s,u+vec2f(0.,-r.y),0.);let rS=textureSampleLevel(t,s,u+vec2f(0.,r.y),0.);let rE=textureSampleLevel(t,s,u+vec2f(r.x,0.),0.);let rW=textureSampleLevel(t,s,u+vec2f(-r.x,0.),0.);let lM=l(rM);let lN=l(rN);let lS=l(rS);let lE=l(rE);let lW=l(rW);let mi=min(lM,min(min(lN,lS),min(lE,lW)));let ma=max(lM,max(max(lN,lS),max(lE,lW)));let ra=ma-mi;if(ra<max(.0833,ma*.166)){return rM;}let lNW=l(textureSampleLevel(t,s,u+vec2f(-r.x,-r.y),0.));let lNE=l(textureSampleLevel(t,s,u+vec2f(r.x,-r.y),0.));let lSW=l(textureSampleLevel(t,s,u+vec2f(-r.x,r.y),0.));let lSE=l(textureSampleLevel(t,s,u+vec2f(r.x,r.y),0.));let sB=min(.35,max(0.,abs((lN+lS+lE+lW)*.25-lM)/ra-.25)*1.33);let iH=abs(lNW+lNE-2.*lN)+abs(lW+lE-2.*lM)*2.+abs(lSW+lSE-2.*lS)>=abs(lNW+lSW-2.*lW)+abs(lN+lS-2.*lM)*2.+abs(lNE+lSE-2.*lE);let l1=select(lW,lN,iH);let l2=select(lE,lS,iH);let pD=abs(l2-lM)>abs(l1-lM);let sL=select(r.x,r.y,iH);let lA=.5*(select(l1,l2,pD)+lM);let gS=max(abs(l1-lM),abs(l2-lM))*.25;var eU=u;if(iH){eU.y+=select(-.5,.5,pD)*sL;}else{eU.x+=select(-.5,.5,pD)*sL;}let eS=select(vec2f(r.x,0.),vec2f(0.,r.y),iH);var uN=eU-eS;var uP=eU+eS;var eN=l(textureSampleLevel(t,s,uN,0.))-lA;var eP=l(textureSampleLevel(t,s,uP,0.))-lA;var dN=abs(eN)>=gS;var dP=abs(eP)>=gS;for(var i=1;i<8;i++){if(!dN){uN-=eS*1.5;eN=l(textureSampleLevel(t,s,uN,0.))-lA;dN=abs(eN)>=gS;}if(!dP){uP+=eS*1.5;eP=l(textureSampleLevel(t,s,uP,0.))-lA;dP=abs(eP)>=gS;}if(dN&&dP){break;}}let dtN=select(u.x-uN.x,u.y-uN.y,iH);let dtP=select(uP.x-u.x,uP.y-u.y,iH);let eB=select(0.,.5-min(dtN,dtP)/(dtN+dtP),(lM-lA<0.)!=(select(eP<0.,eN<0.,dtN<dtP)));var fU=u;let fL=max(eB,sB);if(iH){fU.y+=select(-1.,1.,pD)*fL*sL;}else{fU.x+=select(-1.,1.,pD)*fL*sL;}return textureSampleLevel(t,s,fU,0.);}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var inputTex: texture_2d<f32>;@group(0)@binding(2)var samp: sampler;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)uv: vec2f,};@vertex fn vs(@builtin(vertex_index)vi: u32)-> VertexOutput{var positions = array<vec2f,4>(vec2f(-1.0,-1.0),vec2f(1.0,-1.0),vec2f(-1.0,1.0),vec2f(1.0,1.0));var uvs = array<vec2f,4>(vec2f(0.0,1.0),vec2f(1.0,1.0),vec2f(0.0,0.0),vec2f(1.0,0.0));var out: VertexOutput;out.pos = vec4f(positions[vi],0.0,1.0);out.uv = uvs[vi];return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{return fxaa(in.uv,inputTex,samp);}";var y=`${X}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>;${w}@compute @workgroup_size(${m})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;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 = u.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);}`,L=`${X}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);}`;var D=`${X}@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;@compute @workgroup_size(${m})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 * u.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(series.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 H=`${X}struct BarData{screenX: f32,minY: f32,maxY: f32,barWidth: 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> barData: array<BarData>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> seriesIdx: SeriesIndex;${w}fn barHalfWidth(idx: u32,count: u32)-> f32{if(count <= 1u){return(u.viewMaxX - u.viewMinX)* 0.4;}var spacing: f32;if(idx == 0u){spacing = dataX[1u] - dataX[0u];}else if(idx >= count - 1u){spacing = dataX[count - 1u] - dataX[count - 2u];}else{spacing = min(dataX[idx + 1u] - dataX[idx],dataX[idx] - dataX[idx - 1u]);}let seriesCount = max(1u,u.seriesCount);return(spacing * 0.4)/ f32(seriesCount);}@compute @workgroup_size(${m})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){barData[outputIdx] = BarData(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){barData[outputIdx] = BarData(0.0,0.0,0.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;let startIdx = lowerBound(pixelMinX,count);var endIdx = lowerBound(pixelMaxX,count);endIdx = min(endIdx,count);let centerX =(pixelMinX + pixelMaxX)* 0.5;let onePixel = 1.0 / u.width;if(startIdx >= endIdx){var hit = false;var bestX: f32 = 0.0;var bestY: f32 = 0.0;var bestHW: f32 = 0.0;var bestDist: f32 = 1e10;if(startIdx < count){let bx = dataX[startIdx];let hw = barHalfWidth(startIdx,count);if(pixelMinX < bx + hw && pixelMaxX > bx - hw){let d = abs(bx - centerX);bestX = bx;bestY = dataY[startIdx];bestHW = hw;bestDist = d;hit = true;}}if(startIdx > 0u){let prev = startIdx - 1u;let bx = dataX[prev];let hw = barHalfWidth(prev,count);if(pixelMinX < bx + hw && pixelMaxX > bx - hw){let d = abs(bx - centerX);if(d < bestDist){bestX = bx;bestY = dataY[prev];bestHW = hw;bestDist = d;}hit = true;}}if(!hit){barData[outputIdx] = BarData(0.0,0.0,0.0,0.0);return;}let seriesCount = max(1u,u.seriesCount);let barOffset =(f32(seriesIdx.index)- f32(seriesCount - 1u)* 0.5)*(bestHW * 2.0);let offsetX = bestX + barOffset;let normX =(offsetX - u.viewMinX)/ viewRangeX;let fullWidth = bestHW * 2.0 / viewRangeX;let gapSize = max(onePixel,fullWidth * 0.05);let bw = max(fullWidth - gapSize,onePixel);barData[outputIdx] = BarData(normX,bestY,bestY,bw);return;}var dataMinY = dataY[startIdx];var dataMaxY = dataY[startIdx];let rangeCount = endIdx - startIdx;let maxSamples = u.maxSamplesPerPixel;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){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 hw = barHalfWidth(startIdx,count);let fullWidth = hw * 2.0 / viewRangeX;let gapSize = max(onePixel,fullWidth * 0.05);let bw = max(fullWidth - gapSize,onePixel);let seriesCount = max(1u,u.seriesCount);let barOffset =(f32(seriesIdx.index)- f32(seriesCount - 1u)* 0.5)*(hw * 2.0);let dataX_centered = dataX[startIdx] + barOffset;let normX =(dataX_centered - u.viewMinX)/ viewRangeX;barData[outputIdx] = BarData(normX,dataMinY,dataMaxY,bw);}`,U=`${X}struct BarData{screenX: f32,minY: f32,maxY: f32,barWidth: f32,};@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> barData: array<BarData>;@group(0)@binding(2)var<storage,read> allSeries: array<SeriesInfo>;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)normY: 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 colIdx = vi / 6u;let vertexType = vi % 6u;if(colIdx >= maxCols){out.pos = vec4f(0.0,0.0,0.0,0.0);out.normY = 0.0;return out;}let bd = barData[colIdx];if(bd.barWidth <= 0.0){out.pos = vec4f(0.0,0.0,0.0,0.0);out.normY = 0.0;return out;}let viewRangeY = u.viewMaxY - u.viewMinY;let safeRangeY = select(viewRangeY,1.0,viewRangeY < 0.0001);let normMinY =(min(bd.minY,0.0)- u.viewMinY)/ safeRangeY;let normMaxY =(max(bd.maxY,0.0)- u.viewMinY)/ safeRangeY;let top = 1.0 - normMaxY;let bottom = 1.0 - normMinY;let halfW = bd.barWidth * 0.5;let left = bd.screenX - halfW;let right = bd.screenX + halfW;var positions = array<vec2f,6>(vec2f(left,bottom),vec2f(right,bottom),vec2f(left,top),vec2f(left,top),vec2f(right,bottom),vec2f(right,top));let screenPos = positions[vertexType];let clipX = screenPos.x * 2.0 - 1.0;let clipY = 1.0 - screenPos.y * 2.0;out.pos = vec4f(clipX,clipY,0.0,1.0);out.normY = normMaxY;return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{let series = allSeries[in.seriesIdx];return vec4f(series.color.rgb,0.85);}`;var t,R,v=new Map,S=!1,p={},a={},N=0,P=0,_=!1,O=null,W=new ArrayBuffer(112),j=new Float32Array(W),F=new Uint32Array(W),A,q=(e,i)=>{if(!e.seriesStorageBuffer||e.series.length===0)return;let n=new Float32Array(e.series.length*8),l=new Uint32Array(n.buffer);for(let u=0;u<e.series.length;u++){let o=e.series[u],x=u*8;n[x+0]=o.colorR,n[x+1]=o.colorG,n[x+2]=o.colorB,n[x+3]=1,l[x+4]=o.visibleStart,l[x+5]=o.visibleCount,n[x+6]=i?.[u]??e.pointSize,n[x+7]=0}t.queue.writeBuffer(e.seriesStorageBuffer,0,n)},E=(e,i,n,l)=>{let u=j,o=F,x=e.maxX-e.minX,f=e.maxY-e.minY,Y=e.bgColor??(S?[0.11,0.11,0.12]:[0.98,0.98,0.98]);u.set([e.width,e.height,e.minX+e.panX*x,e.minX+e.panX*x+x/e.zoomX,e.minY+e.panY*f,e.minY+e.panY*f+f/e.zoomY],0),o[6]=i.pointCount,u.set([S?1:0,...Y,l??e.pointSize,e.minY,e.maxY,e.minX,e.maxX],7),o[16]=i.visibleStart,o[17]=i.visibleCount,o[18]=0,o[19]=e.maxSamplesPerPixel,o[20]=e.series.length,t.queue.writeBuffer(e.uniformBuffer,0,W)},T=(e,i,n,l,u)=>{let o=t.createShaderModule({code:i}),x=t.createShaderModule({code:n});a[`${e}Compute`]=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[p[`${e}Compute`]]}),compute:{module:o,entryPoint:"main"}}),a[`${e}Render`]=t.createRenderPipeline({layout:t.createPipelineLayout({bindGroupLayouts:[p[`${e}Render`]]}),vertex:{module:x,entryPoint:"vs"},fragment:{module:x,entryPoint:"fs",targets:[{format:"rgba8unorm",blend:u}]},primitive:{topology:l}})};async function J(){if(t)return!0;if(!navigator.gpu)return postMessage({type:"error",message:"WebGPU not supported"}),!1;let e=await navigator.gpu.requestAdapter();if(!e)return postMessage({type:"error",message:"No GPU adapter found"}),!1;return t=await e.requestDevice({requiredLimits:{maxBufferSize:e.limits.maxBufferSize,maxStorageBufferBindingSize:e.limits.maxStorageBufferBindingSize}}),R=navigator.gpu.getPreferredCanvasFormat(),t.lost.then((i)=>{postMessage({type:"error",message:`GPU device lost: ${i.reason} - ${i.message}`})}),K(),postMessage({type:"gpu-ready"}),!0}function K(){p.lineCompute=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:4,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}}]}),p.lineRender=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}}]}),p.scatterCompute=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:"rgba8unorm"}},{binding:4,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:5,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}}]}),p.fxaaRender=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,sampler:{}}]}),p.boxCompute=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:4,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:5,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}}]}),p.boxRender=p.lineRender,T("line",y,L,"line-list",{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha"}}),T("box",H,U,"triangle-list",{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha"}});let e=t.createShaderModule({code:D});a.scatterCompute=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[p.scatterCompute]}),compute:{module:e,entryPoint:"main"}});let i=t.createShaderModule({code:C});a.fxaaRender=t.createRenderPipeline({layout:t.createPipelineLayout({bindGroupLayouts:[p.fxaaRender]}),vertex:{module:i,entryPoint:"vs"},fragment:{module:i,entryPoint:"fs",targets:[{format:R}]},primitive:{topology:"triangle-strip"}}),A=t.createSampler({magFilter:"linear",minFilter:"linear"})}function Q(e,i,n,l=3,u=0,o=null){let x=t?i.getContext("webgpu"):null;if(!x){postMessage({type:"error",message:`Failed to initialize WebGPU context: ${e}`});return}try{x.configure({device:t,format:R,alphaMode:"premultiplied"})}catch(M){postMessage({type:"error",message:`Failed to configure WebGPU context: ${e}`,err:M.toString()});return}let f=t.limits.maxTextureDimension2D,Y=Math.min(Math.floor(Number(i.width)||800),f),d=Math.min(Math.floor(Number(i.height)||400),f),g=t.createBuffer({size:112,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),I={id:e,canvas:i,ctx:x,type:n,visible:!0,pointSize:l,maxSamplesPerPixel:u,series:[],uniformBuffer:g,seriesStorageBuffer:null,outputTexture:null,outputTextureView:null,fxaaBindGroup:null,width:Y,height:d,panX:0,panY:0,zoomX:1,zoomY:1,minX:0,maxX:1,minY:0,maxY:1,bgColor:o,dirty:!0};try{$(I)}catch(M){postMessage({type:"error",message:`Cannot create chart ${e}: resource creation failed - ${M}`});return}v.set(e,I),postMessage({type:"chart-registered",id:e})}function $(e){if(e.outputTexture)e.outputTexture.destroy();let i=Math.max(1,e.width),n=Math.max(1,e.height),l=e.type==="scatter"?GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT;e.outputTexture=t.createTexture({size:[i,n],format:"rgba8unorm",usage:l}),e.outputTextureView=e.outputTexture.createView(),e.fxaaBindGroup=t.createBindGroup({layout:p.fxaaRender,entries:[{binding:0,resource:{buffer:e.uniformBuffer}},{binding:1,resource:e.outputTextureView},{binding:2,resource:A}]})}function V(e,i,n){if(!e.seriesStorageBuffer)return;if(e.type==="scatter"){if(i.seriesIndexBuffer)i.seriesIndexBuffer.destroy();i.seriesIndexBuffer=t.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let l=new Uint32Array([n,0,0,0]);t.queue.writeBuffer(i.seriesIndexBuffer,0,l),i.computeBindGroup=t.createBindGroup({layout:p.scatterCompute,entries:[{binding:0,resource:{buffer:e.uniformBuffer}},{binding:1,resource:{buffer:i.dataX}},{binding:2,resource:{buffer:i.dataY}},{binding:3,resource:e.outputTextureView},{binding:4,resource:{buffer:e.seriesStorageBuffer}},{binding:5,resource:{buffer:i.seriesIndexBuffer}}]})}else{let l=e.type==="line"?p.lineCompute:p.boxCompute,u=e.type==="line"?p.lineRender:p.boxRender;if(i.lineBuffer)i.lineBuffer.destroy();if(i.lineBuffer=t.createBuffer({size:e.width*16,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX}),e.type==="box"){if(i.seriesIndexBuffer)i.seriesIndexBuffer.destroy();i.seriesIndexBuffer=t.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let x=new Uint32Array([n,0,0,0]);t.queue.writeBuffer(i.seriesIndexBuffer,0,x)}let o=[{binding:0,resource:{buffer:e.uniformBuffer}},{binding:1,resource:{buffer:i.dataX}},{binding:2,resource:{buffer:i.dataY}},{binding:3,resource:{buffer:i.lineBuffer}},{binding:4,resource:{buffer:e.seriesStorageBuffer}}];if(e.type==="box"&&i.seriesIndexBuffer)o.push({binding:5,resource:{buffer:i.seriesIndexBuffer}});i.computeBindGroup=t.createBindGroup({layout:l,entries:o}),i.renderBindGroup=t.createBindGroup({layout:u,entries:[{binding:0,resource:{buffer:e.uniformBuffer}},{binding:1,resource:{buffer:i.lineBuffer}},{binding:2,resource:{buffer:e.seriesStorageBuffer}}]})}}function Z(e,i,n){if(i===e.width&&n===e.height)return;if(i<=0||n<=0)return;e.width=i,e.height=n,e.canvas.width=i,e.canvas.height=n;try{$(e);for(let l=0;l<e.series.length;l++)V(e,e.series[l],l)}catch(l){postMessage({type:"error",message:`resize failed for chart ${e.id}: ${l}`})}}function G(e,i,n){let l=v.get(e);if(!l||!t){if(!l)postMessage({type:"error",message:`update-series failed: chart ${e} not found`});return}try{l.minX=n.minX,l.maxX=n.maxX,l.minY=n.minY,l.maxY=n.maxY;for(let u of l.series){if(u.dataX.destroy(),u.dataY.destroy(),u.lineBuffer)u.lineBuffer.destroy();if(u.seriesIndexBuffer)u.seriesIndexBuffer.destroy()}if(l.series=[],l.seriesStorageBuffer)l.seriesStorageBuffer.destroy();if(i.length>0)l.seriesStorageBuffer=t.createBuffer({size:Math.max(32,i.length*32),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST});for(let u of i){let o=t.createBuffer({size:Math.max(16,u.dataX.byteLength),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),x=t.createBuffer({size:Math.max(16,u.dataY.byteLength),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST});t.queue.writeBuffer(o,0,u.dataX),t.queue.writeBuffer(x,0,u.dataY);let f={label:u.label,colorR:u.colorR,colorG:u.colorG,colorB:u.colorB,dataX:o,dataY:x,lineBuffer:null,seriesIndexBuffer:null,pointCount:u.dataX.length,visibleStart:0,visibleCount:u.dataX.length,computeBindGroup:null,renderBindGroup:null};l.series.push(f)}for(let u=0;u<l.series.length;u++)V(l,l.series[u],u);postMessage({type:"bounds-update",id:e,...n})}catch(u){postMessage({type:"error",message:`update-series failed for chart ${e}: ${u}`})}}function z(e){if(!e.ctx)return;if(e.width===0||e.height===0)return;if(e.series.length===0)return;let i;try{i=e.ctx.getCurrentTexture().createView()}catch{return}k(e,i)}function k(e,i){let n=t.createCommandEncoder(),l;if(e.type==="scatter"){let f=e.width*e.height*4;l=e.series.map((Y)=>{let d=Math.max(1,Y.visibleCount),g=Math.PI*e.pointSize*e.pointSize;if(d*g>f)return Math.max(1,Math.sqrt(f/(d*Math.PI)));return e.pointSize})}if(q(e,l),e.series.length>0)E(e,e.series[0],0);n.beginRenderPass({colorAttachments:[{view:e.outputTextureView,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]}).end();for(let x=0;x<e.series.length;x++){let f=e.series[x];if(f.pointCount===0)continue;if(e.type==="scatter"){let d=Math.ceil(f.visibleCount/m),g=Math.min(d,65535),I=Math.ceil(d/65535),M=new Uint32Array([g*m]);t.queue.writeBuffer(e.uniformBuffer,72,M);let r=n.beginComputePass();r.setPipeline(a.scatterCompute),r.setBindGroup(0,f.computeBindGroup),r.dispatchWorkgroups(g,I),r.end()}else{E(e,f,x);let Y=e.type==="line"?a.lineCompute:a.boxCompute,d=n.beginComputePass();d.setPipeline(Y),d.setBindGroup(0,f.computeBindGroup),d.dispatchWorkgroups(Math.ceil(e.width/m)),d.end()}}if(e.type!=="scatter"){let x=e.type==="line"?a.lineRender:a.boxRender,f=e.type==="line"?Math.max(0,e.width*4-2):e.width*6,Y=n.beginRenderPass({colorAttachments:[{view:e.outputTextureView,loadOp:"load",storeOp:"store"}]});Y.setPipeline(x);for(let d=0;d<e.series.length;d++){let g=e.series[d];if(g.pointCount===0)continue;Y.setBindGroup(0,g.renderBindGroup),Y.draw(f,1,0,d)}Y.end()}let o=n.beginRenderPass({colorAttachments:[{view:i,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]});if(o.setPipeline(a.fxaaRender),e.fxaaBindGroup)o.setBindGroup(0,e.fxaaBindGroup);o.draw(4),o.end(),t.queue.submit([n.finish()])}function s(){if(!_)_=!0,requestAnimationFrame(ee)}function b(e){if(e.dirty=!0,e.visible)s()}function B(){let e=!1;for(let i of v.values())if(i.dirty=!0,i.visible)e=!0;if(e)s()}function c(){let e=0;for(let i of v.values())if(i.visible&&i.width>0)e++;return e}function h(){if(O!==null)return;O=setInterval(()=>{postMessage({type:"stats",fps:N,renderMs:P,totalCharts:v.size,activeCharts:c()}),N=0},1000)}function ee(){_=!1;let e=performance.now();for(let i of v.values())if(i.visible&&i.dirty&&i.width>0)z(i),i.dirty=!1;P=performance.now()-e,N++}self.onmessage=async(e)=>{let{type:i,...n}=e.data;switch(i){case"init":if(S=n.isDark||!1,await J())h();break;case"theme":S=n.isDark,B();break;case"register-chart":Q(n.id,n.canvas,n.chartType||"scatter",n.pointSize??3,n.maxSamplesPerPixel??100,n.bgColor??null);{let l=v.get(n.id);if(l)b(l)}break;case"unregister-chart":{let l=v.get(n.id);if(l){try{l.ctx.unconfigure()}catch{}if(l.uniformBuffer.destroy(),l.seriesStorageBuffer)l.seriesStorageBuffer.destroy();if(l.outputTexture)l.outputTexture.destroy();for(let u of l.series){if(u.dataX.destroy(),u.dataY.destroy(),u.lineBuffer)u.lineBuffer.destroy();if(u.seriesIndexBuffer)u.seriesIndexBuffer.destroy()}v.delete(n.id)}postMessage({type:"chart-unregistered",id:n.id});break}case"set-point-size":{let l=v.get(n.id);if(l)l.pointSize=Math.max(1,Math.min(8,n.pointSize)),b(l);break}case"set-max-samples":{let l=v.get(n.id);if(l)l.maxSamplesPerPixel=Math.max(0,n.maxSamplesPerPixel|0),b(l);break}case"set-style":{let l=v.get(n.id);if(l){if(n.bgColor!==void 0)l.bgColor=n.bgColor;b(l)}break}case"update-series":{G(n.id,n.series,n.bounds);let l=v.get(n.id);if(l)b(l);break}case"set-visibility":{let l=v.get(n.id);if(l){if(l.visible=n.visible,n.visible&&l.dirty)s()}break}case"view-transform":{let l=v.get(n.id);if(l)l.panX=n.panX,l.panY=n.panY,l.zoomX=Math.max(0.1,Math.min(1e6,n.zoomX)),l.zoomY=Math.max(0.1,Math.min(1e6,n.zoomY)),b(l);break}case"resize":{let l=v.get(n.id);if(l&&n.width>0&&n.height>0)Z(l,n.width,n.height),b(l);break}case"batch-view-transform":{let l=Math.max(0.1,Math.min(1e6,n.zoomX)),u=Math.max(0.1,Math.min(1e6,n.zoomY));for(let o of n.transforms){let x=v.get(o.id);if(x)x.panX=n.panX,x.panY=n.panY,x.zoomX=l,x.zoomY=u,x.dirty=!0}s();break}case"sync-view":for(let l of v.values())l.panX=n.panX,l.panY=n.panY,l.zoomX=n.zoomX,l.zoomY=n.zoomY;B();break}};\n';var m=[];function Z(t){if(!m.some((e)=>e.name===t.name))m.push(t)}function ee(t){let e=m.findIndex((i)=>i.name===t);if(e>=0)m.splice(e,1)}function te(){return m}class x{static instance=null;static MARGIN={left:55,right:10,top:8,bottom:45};static HOVER_MAX_DISTANCE_PX=50;static MIN_ZOOM=0.1;static MAX_ZOOM=1e7;static DEFAULT_LABEL_SIZE=12;static DEFAULT_FONT='-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';static resizeCanvas(t,e,i){let r=devicePixelRatio||1;if(t.width=Math.round(e*r),t.height=Math.round(i*r),t instanceof HTMLCanvasElement)t.style.width=`${e}px`,t.style.height=`${i}px`}worker=null;charts=new Map;chartIdCounter=0;_syncViews=!1;_isDark=!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((t)=>{for(let e of t){let i=e.target.dataset.chartId;if(i){let r=this.charts.get(i);if(r){if(r.visible=e.isIntersecting,this.worker?.postMessage({type:"set-visibility",id:i,visible:e.isIntersecting}),e.isIntersecting)this.drawChart(r)}}}},{threshold:0.01}),this.resizeObserver=new ResizeObserver((t)=>{for(let e of t){let i=e.target.dataset.chartId;if(!i)continue;let r=this.charts.get(i);if(!r)continue;let{width:a,height:u}=e.contentRect;if(a<=0||u<=0)continue;r.width=a,r.height=u;let o=devicePixelRatio||1;this.worker?.postMessage({type:"resize",id:i,width:Math.round(a*o),height:Math.round(u*o)}),x.resizeCanvas(r.backCanvas,a,u),x.resizeCanvas(r.axisCanvas,a,u),this.drawChart(r)}})}static getInstance(){if(!x.instance)x.instance=new x;return x.instance}get isDark(){return this._isDark}get syncViews(){return this._syncViews}async init(){if(this.worker)return!0;return new Promise((t)=>{Promise.resolve().then(() => O).then(({WORKER_CODE:e})=>{let i=new Blob([e],{type:"application/javascript"}),r=URL.createObjectURL(i);this.worker=new Worker(r,{type:"module"}),this.setupWorkerHandlers(t)}).catch(()=>{let e=new URL("./gpu-worker.js",import.meta.url);this.worker=new Worker(e,{type:"module"}),this.setupWorkerHandlers(t)})})}setupWorkerHandlers(t){if(!this.worker)return;this.worker.onmessage=(e)=>{let{type:i,...r}=e.data;switch(i){case"gpu-ready":t(!0);break;case"error":console.error("ChartManager GPU Error:",r.message),t(!1);break;case"stats":this.currentStats={fps:r.fps,renderMs:r.renderMs,total:r.totalCharts,active:r.activeCharts};for(let a of this.statsCallbacks)a(this.currentStats);break;case"bounds-update":{let a=this.charts.get(r.id);if(a)a.bounds={minX:r.minX,maxX:r.maxX,minY:r.minY,maxY:r.maxY},this.drawChart(a);break}default:break}},this.worker.onerror=(e)=>{console.error("ChartManager Worker Error:",e),t(!1)},this.worker.postMessage({type:"init",isDark:this._isDark})}create(t){if(!this.worker)throw new Error("ChartManager not initialized. Call init() first.");let e=`chart-${++this.chartIdCounter}`,i=document.createElement("div");i.dataset.chartId=e,i.style.cssText="width: 100%; height: 100%; position: relative;";let r=document.createElement("div");r.dataset.chartId=e,r.style.cssText="width: 100%; height: 100%; position: relative;";let a=document.createElement("canvas");a.style.cssText="position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none;";let u=document.createElement("canvas");u.style.cssText="position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: auto; z-index: 1;";let o=document.createElement("canvas");o.style.cssText="position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2;",r.appendChild(a),r.appendChild(u),r.appendChild(o),i.appendChild(r),t.container.appendChild(i);let p;try{p=u.transferControlToOffscreen()}catch(d){throw console.error(`ChartManager: Failed to create offscreen canvas for ${e}:`,d),new Error(`Failed to create chart ${e}: ${d}`)}let v=r.getBoundingClientRect(),l=v.width||400,c=v.height||200;if(x.resizeCanvas(p,l,c),x.resizeCanvas(a,l,c),x.resizeCanvas(o,l,c),t.bgColor){let[d,s,g]=t.bgColor;r.style.background=`rgb(${Math.round(d*255)},${Math.round(s*255)},${Math.round(g*255)})`}let n={id:e,config:t,el:i,backCanvas:a,axisCanvas:o,width:l,height:c,series:[],bounds:{minX:0,maxX:1,minY:0,maxY:1},view:{panX:0,panY:0,zoomX:1,zoomY:1},zoomMode:t.zoomMode||"both",visible:!0,dragging:!1,bgColor:t.bgColor,textColor:t.textColor,gridColor:t.gridColor,fontFamily:t.fontFamily,momentum:null,findNearestPoint(d,s,g,_){if(this.series.length===0)return null;let z=d/g,L=s/_,h=this.bounds.maxX-this.bounds.minX,R=this.bounds.maxY-this.bounds.minY,T=h/this.view.zoomX,A=R/this.view.zoomY,C=this.bounds.minX+this.view.panX*h,V=this.bounds.minY+this.view.panY*R,M=C+z*T,W=V+(1-L)*A,w=-1,y=-1,I=1/0,N=1/0;for(let P=0;P<this.series.length;P++){let S=this.series[P],E=S.rawX.length;if(E===0)continue;let b=0,U=E-1;while(b<U){let Y=b+U>>1;if(S.rawX[Y]<M)b=Y+1;else U=Y}let B=b;if(b>0){let Y=Math.abs(S.rawX[b]-M);if(Math.abs(S.rawX[b-1]-M)<Y)B=b-1}let G=Math.abs(S.rawX[B]-M),D=Math.abs(S.rawY[B]-W);if(G<I||G===I&&D<N)I=G,N=D,w=P,y=B}if(w===-1)return null;let X=this.series[w],$=(X.rawX[y]-C)/T*g;if(Math.abs($-d)>x.HOVER_MAX_DISTANCE_PX)return null;return{x:X.rawX[y],y:X.rawY[y],index:y,screenX:d,screenY:s,seriesIndex:w,seriesLabel:X.label}}};this.charts.set(e,n);let f=t.type==="bar"?"box":t.type;this.worker.postMessage({type:"register-chart",id:e,canvas:p,chartType:f,pointSize:t.pointSize??3,maxSamplesPerPixel:t.maxSamplesPerPixel??1e4,bgColor:t.bgColor??null},[p]),this.visibilityObserver.observe(i),this.resizeObserver.observe(r);for(let d of m)d.install?.(n,r);return this.updateSeries(e,t.series),e}destroy(t){let e=this.charts.get(t);if(!e)return;for(let r of m)r.uninstall?.(e);if(e.momentum)cancelAnimationFrame(e.momentum);this.visibilityObserver.unobserve(e.el);let i=e.el.querySelector(".gpu-chart-canvas-wrap");if(i)this.resizeObserver.unobserve(i);e.el.remove(),this.worker?.postMessage({type:"unregister-chart",id:t}),this.charts.delete(t)}updateSeries(t,e){let i=this.charts.get(t);if(!i||!this.worker)return;if(e.length===0)return;i.series=e.map((n)=>{let f=n.x.length;if(f===0)return{label:n.label,color:n.color,rawX:[],rawY:[]};let d=Array.from({length:f},(s,g)=>g);return d.sort((s,g)=>n.x[s]-n.x[g]),{label:n.label,color:n.color,rawX:d.map((s)=>n.x[s]),rawY:d.map((s)=>n.y[s])}});let r=1/0,a=-1/0,u=1/0,o=-1/0;for(let n of i.series)for(let f=0;f<n.rawX.length;f++){if(n.rawX[f]<r)r=n.rawX[f];if(n.rawX[f]>a)a=n.rawX[f];if(n.rawY[f]<u)u=n.rawY[f];if(n.rawY[f]>o)o=n.rawY[f]}let p=(a-r)*0.05||1,v=(o-u)*0.1||1;r-=p,a+=p,u-=v,o+=v;let l=i.config.defaultBounds;if(l){if(l.minX!==void 0)r=l.minX;if(l.maxX!==void 0)a=l.maxX;if(l.minY!==void 0)u=l.minY;if(l.maxY!==void 0)o=l.maxY}i.bounds={minX:r,maxX:a,minY:u,maxY:o};let c=i.series.map((n)=>({label:n.label,colorR:n.color.r,colorG:n.color.g,colorB:n.color.b,dataX:new Float32Array(n.rawX),dataY:new Float32Array(n.rawY)}));this.worker.postMessage({type:"update-series",id:t,series:c,bounds:i.bounds},c.flatMap((n)=>[n.dataX.buffer,n.dataY.buffer])),this.sendViewTransform(i),this.drawChart(i)}setPointSize(t,e){if(!this.charts.get(t))return;this.worker?.postMessage({type:"set-point-size",id:t,pointSize:Math.max(1,Math.min(8,Math.round(e)))})}setMaxSamplesPerPixel(t,e){if(!this.charts.get(t))return;this.worker?.postMessage({type:"set-max-samples",id:t,maxSamplesPerPixel:Math.max(0,e|0)})}setStyle(t,e){let i=this.charts.get(t);if(!i)return;if(e.bgColor!==void 0)i.bgColor=e.bgColor;if(e.textColor!==void 0)i.textColor=e.textColor;if(e.gridColor!==void 0)i.gridColor=e.gridColor;if(e.fontFamily!==void 0)i.fontFamily=e.fontFamily;if(e.bgColor!==void 0){let r=i.el.querySelector(".gpu-chart-canvas-wrap");if(r){let[a,u,o]=e.bgColor;r.style.background=`rgb(${Math.round(a*255)},${Math.round(u*255)},${Math.round(o*255)})`}this.worker?.postMessage({type:"set-style",id:t,bgColor:e.bgColor})}this.drawChart(i)}setZoomMode(t,e){let i=this.charts.get(t);if(i)i.zoomMode=e}getChartCount(){return this.charts.size}getZoomMode(t){return this.charts.get(t)?.zoomMode||"both"}setSyncViews(t){this._syncViews=t}setTheme(t){this._isDark=t,this.worker?.postMessage({type:"theme",isDark:t});for(let e of this.charts.values())this.drawChart(e)}onStats(t){return this.statsCallbacks.push(t),()=>{let e=this.statsCallbacks.indexOf(t);if(e>=0)this.statsCallbacks.splice(e,1)}}getStats(){return{...this.currentStats}}resetView(t){let e=this.charts.get(t);if(!e)return;if(e.momentum)cancelAnimationFrame(e.momentum),e.momentum=null;let i=e.view.panX,r=e.view.panY,a=e.view.zoomX,u=e.view.zoomY,o=performance.now(),p=()=>{let v=Math.min(1,(performance.now()-o)/300),l=1-Math.pow(1-v,3);if(e.view.panX=i*(1-l),e.view.panY=r*(1-l),e.view.zoomX=a+(1-a)*l,e.view.zoomY=u+(1-u)*l,this.sendViewTransform(e),this.drawChart(e),this._syncViews)this.syncAllViews(e);if(v<1)requestAnimationFrame(p)};requestAnimationFrame(p)}sendViewTransform(t){this.worker?.postMessage({type:"view-transform",id:t.id,panX:t.view.panX,panY:t.view.panY,zoomX:t.view.zoomX,zoomY:t.view.zoomY})}syncAllViews(t){let e=[];for(let i of this.charts.values())if(i.id!==t.id)i.view={...t.view},e.push({id:i.id}),this.drawChart(i);if(e.length>0)this.worker?.postMessage({type:"batch-view-transform",panX:t.view.panX,panY:t.view.panY,zoomX:t.view.zoomX,zoomY:t.view.zoomY,transforms:e})}drawChart(t){if(!t.visible)return;let e=devicePixelRatio||1,i=t.backCanvas.getContext("2d");if(i){i.clearRect(0,0,t.backCanvas.width,t.backCanvas.height),i.save(),i.scale(e,e);for(let a of m)a.beforeDraw?.(i,t);i.restore()}let r=t.axisCanvas.getContext("2d");if(r){r.clearRect(0,0,t.axisCanvas.width,t.axisCanvas.height),r.save(),r.scale(e,e);for(let a of m)a.afterDraw?.(r,t);r.restore()}}}export{ee as unregisterPlugin,Z as registerPlugin,te as getPlugins,x as ChartManager};
|
|
1
|
+
var X=Object.defineProperty;var b=(e)=>e;function v(e,t){this[e]=b.bind(null,t)}var I=(e,t)=>{for(var i in t)X(e,i,{get:t[i],enumerable:!0,configurable:!0,set:v.bind(t,i)})};var y={};I(y,{WORKER_CODE:()=>x});var x='var k="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);}";var T={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},Q={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"};var j,U,J=new Map,R=new Map,w=!1,I,B,l,P=0,M=0,C=!1,p=null,L=new ArrayBuffer(64),b=new Float32Array(L),n=new Uint32Array(L);function D(_){let O=GPUBufferUsage.COPY_DST;for(let N of _)switch(N.toUpperCase()){case"STORAGE":O|=GPUBufferUsage.STORAGE;break;case"VERTEX":O|=GPUBufferUsage.VERTEX;break;case"UNIFORM":O|=GPUBufferUsage.UNIFORM;break;case"COPY_SRC":O|=GPUBufferUsage.COPY_SRC;break;case"COPY_DST":O|=GPUBufferUsage.COPY_DST;break;case"INDEX":O|=GPUBufferUsage.INDEX;break;case"INDIRECT":O|=GPUBufferUsage.INDIRECT;break}return O}function i(_,O,N){let m=N==="compute"?GPUShaderStage.COMPUTE:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT;if(_==="uniforms"||_==="custom-uniforms"||_==="series-index")return{visibility:m,buffer:{type:"uniform"}};if(_==="render-target"){if(O)return{visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:"rgba8unorm"}};return{visibility:m,texture:{sampleType:"float"}}}if(O)return{visibility:m,buffer:{type:"storage"}};return{visibility:m,buffer:{type:"read-only-storage"}}}function z(_,O,N,m,W){switch(_){case"uniforms":return{buffer:N.uniformBuffer};case"custom-uniforms":return{buffer:N.customUniformBuffer};case"series-info":return{buffer:N.seriesStorageBuffer};case"render-target":return N.outputTextureView;case"x-data":return{buffer:m.dataX};case"y-data":return{buffer:m.dataY};case"series-index":return{buffer:m.seriesIndexBuffer}}if(_.endsWith("-data")){let Y=_.slice(0,-5);return{buffer:m.extraBuffers.get(Y)}}if(W.config.bufferDefs.find((Y)=>Y.name===_)?.perSeries)return{buffer:m.seriesBuffers.get(_)};return{buffer:N.chartBuffers.get(_)}}function d(_){let O=new Map,N=new Map;for(let m=0;m<_.passes.length;m++){let W=_.passes[m],X=W.bindings.map((v)=>({binding:v.binding,...i(v.source,v.write,W.type)})),Y=j.createBindGroupLayout({entries:X});N.set(`pass-${m}`,Y);let H=j.createPipelineLayout({bindGroupLayouts:[Y]}),G=j.createShaderModule({code:_.shaders[W.shader]});if(W.type==="compute")O.set(`pass-${m}`,j.createComputePipeline({layout:H,compute:{module:G,entryPoint:"main"}}));else O.set(`pass-${m}`,j.createRenderPipeline({layout:H,vertex:{module:G,entryPoint:"vs"},fragment:{module:G,entryPoint:"fs",targets:[{format:"rgba8unorm",blend:W.blend}]},primitive:{topology:W.topology??"triangle-list"}}))}return{config:_,pipelines:O,passLayouts:N}}function h(_){if(!_.seriesStorageBuffer||_.series.length===0)return;let O=new Float32Array(_.series.length*8),N=new Uint32Array(O.buffer);for(let m=0;m<_.series.length;m++){let W=_.series[m],X=m*8;O[X+0]=W.colorR,O[X+1]=W.colorG,O[X+2]=W.colorB,O[X+3]=1,N[X+4]=W.visibleStart,N[X+5]=W.visibleCount}j.queue.writeBuffer(_.seriesStorageBuffer,0,O)}function E(_,O){let N=b,m=n,W=_.maxX-_.minX,X=_.maxY-_.minY,Y=_.bgColor??(w?[0.11,0.11,0.12]:[0.98,0.98,0.98]);N[0]=_.width,N[1]=_.height,N[2]=_.minX+_.panX*W,N[3]=_.minX+_.panX*W+W/_.zoomX,N[4]=_.minY+_.panY*X,N[5]=_.minY+_.panY*X+X/_.zoomY,m[6]=O.pointCount,m[7]=_.series.length,m[8]=w?1:0,N[9]=Y[0],N[10]=Y[1],N[11]=Y[2],N[12]=_.minX,N[13]=_.maxX,N[14]=_.minY,N[15]=_.maxY,j.queue.writeBuffer(_.uniformBuffer,0,L)}function y(_,O){if(!_.customUniformBuffer||O.uniformDefs.length===0)return;let N=O.uniformDefs.length,m=Math.ceil(N*4/16)*16,W=new ArrayBuffer(m),X=new Float32Array(W),Y=new Uint32Array(W);for(let H=0;H<N;H++){let G=O.uniformDefs[H],v=_.customUniformValues[G.name]??G.default;if(G.type==="u32")Y[H]=v>>>0;else X[H]=v}j.queue.writeBuffer(_.customUniformBuffer,0,W)}function g(_,O,N){for(let[,m]of _.chartBuffers)m.destroy();_.chartBuffers.clear();for(let m of O.config.bufferDefs)if(!m.perSeries){let W=Math.max(16,N[m.name]??16);_.chartBuffers.set(m.name,j.createBuffer({size:W,usage:D(m.usages)}))}if(O.config.uniformDefs.length>0){if(_.customUniformBuffer)_.customUniformBuffer.destroy();let m=Math.max(16,Math.ceil(O.config.uniformDefs.length*4/16)*16);_.customUniformBuffer=j.createBuffer({size:m,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),y(_,O.config)}}function u(_,O,N,m){for(let[,W]of _.seriesBuffers)W.destroy();_.seriesBuffers.clear();for(let W of N.config.bufferDefs)if(W.perSeries){let X=Math.max(16,m[W.name]??16);_.seriesBuffers.set(W.name,j.createBuffer({size:X,usage:D(W.usages)}))}if(_.seriesIndexBuffer)_.seriesIndexBuffer.destroy();_.seriesIndexBuffer=j.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),j.queue.writeBuffer(_.seriesIndexBuffer,0,new Uint32Array([O,0,0,0]))}function f(_,O){if(!_.seriesStorageBuffer)return;for(let N=0;N<_.series.length;N++){let m=_.series[N];m.passBindGroups=[];for(let W=0;W<O.config.passes.length;W++){let X=O.config.passes[W];if(!X.perSeries){m.passBindGroups.push(null);continue}let Y=O.passLayouts.get(`pass-${W}`);try{let H=X.bindings.map((G)=>({binding:G.binding,resource:z(G.source,G.write,_,m,O)}));m.passBindGroups.push(j.createBindGroup({layout:Y,entries:H}))}catch(H){postMessage({type:T.ERROR,code:Q.BIND_S}),m.passBindGroups.push(null)}}}_.chartPassBindGroups=[];for(let N=0;N<O.config.passes.length;N++){let m=O.config.passes[N];if(m.perSeries){_.chartPassBindGroups.push(null);continue}let W=O.passLayouts.get(`pass-${N}`);try{let X=m.bindings.map((Y)=>({binding:Y.binding,resource:z(Y.source,Y.write,_,null,O)}));_.chartPassBindGroups.push(j.createBindGroup({layout:W,entries:X}))}catch(X){postMessage({type:T.ERROR,code:Q.BIND_C}),_.chartPassBindGroups.push(null)}}}function S(_){if(_.outputTexture)_.outputTexture.destroy();let O=Math.max(1,_.width),N=Math.max(1,_.height),m=R.get(_.rendererName),W=GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT;if(m){for(let X of m.config.passes)if(X.type==="compute"){for(let Y of X.bindings)if(Y.source==="render-target"&&Y.write){W|=GPUTextureUsage.STORAGE_BINDING;break}}}_.outputTexture=j.createTexture({size:[O,N],format:"rgba8unorm",usage:W}),_.outputTextureView=_.outputTexture.createView(),_.blitBindGroup=j.createBindGroup({layout:B,entries:[{binding:0,resource:_.outputTextureView},{binding:1,resource:l}]})}function c(_){let O=R.get(_.rendererName);if(!O)return;if(!_.ctx||_.width===0||_.height===0||_.series.length===0)return;let N;try{N=_.ctx.getCurrentTexture().createView()}catch{return}let m=j.createCommandEncoder();if(h(_),_.series.length>0)E(_,_.series[0]);m.beginRenderPass({colorAttachments:[{view:_.outputTextureView,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]}).end();for(let Y=0;Y<O.config.passes.length;Y++){let H=O.config.passes[Y],G=O.pipelines.get(`pass-${Y}`);if(!G)continue;if(H.type==="compute")if(H.perSeries)for(let v=0;v<_.series.length;v++){let V=_.series[v];if(V.pointCount===0||V.hidden)continue;E(_,V);let q=_.perSeriesPassMeta[v]?.[Y]?.dispatch??{x:1},$=V.passBindGroups[Y];if(!$)continue;let Z=m.beginComputePass();Z.setPipeline(G),Z.setBindGroup(0,$),Z.dispatchWorkgroups(q.x,q.y??1,q.z??1),Z.end()}else{let v=_.chartPassBindGroups[Y];if(!v)continue;let K=_.perSeriesPassMeta[0]?.[Y]?.dispatch??{x:1},q=m.beginComputePass();q.setPipeline(G),q.setBindGroup(0,v),q.dispatchWorkgroups(K.x,K.y??1,K.z??1),q.end()}else if(H.type==="render"){let V=_.perSeriesPassMeta[0]?.[Y]?.draw??0,K=m.beginRenderPass({colorAttachments:[{view:_.outputTextureView,loadOp:H.loadOp??"load",storeOp:"store"}]});if(K.setPipeline(G),H.perSeries)for(let q=0;q<_.series.length;q++){let $=_.series[q];if($.pointCount===0||$.hidden)continue;let Z=$.passBindGroups[Y];if(!Z)continue;K.setBindGroup(0,Z),K.draw(V,1,0,q)}else{let q=_.chartPassBindGroups[Y];if(q)K.setBindGroup(0,q),K.draw(V,1,0,0)}K.end()}}let X=m.beginRenderPass({colorAttachments:[{view:N,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]});if(X.setPipeline(I),_.blitBindGroup)X.setBindGroup(0,_.blitBindGroup);X.draw(4),X.end(),j.queue.submit([m.finish()])}function F(){if(!C)C=!0,requestAnimationFrame(t)}function A(_){if(_.dirty=!0,_.visible)F()}function s(){let _=!1;for(let O of J.values())if(O.dirty=!0,O.visible)_=!0;if(_)F()}function t(){C=!1;let _=performance.now();for(let O of J.values())if(O.visible&&O.dirty&&O.width>0)c(O),O.dirty=!1;M=performance.now()-_,P++}function e(){let _=0;for(let O of J.values())if(O.visible&&O.width>0)_++;return _}async function a(){if(j)return!0;if(!navigator.gpu)return postMessage({type:T.ERROR,code:Q.NO_GPU}),!1;let _=await navigator.gpu.requestAdapter();if(!_)return postMessage({type:T.ERROR,code:Q.NO_ADAPTER}),!1;j=await _.requestDevice({requiredLimits:{maxBufferSize:_.limits.maxBufferSize,maxStorageBufferBindingSize:_.limits.maxStorageBufferBindingSize}}),U=navigator.gpu.getPreferredCanvasFormat(),j.lost.then((N)=>{postMessage({type:T.ERROR,code:Q.DEVICE_LOST})}),B=j.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{}}]});let O=j.createShaderModule({code:k});return I=j.createRenderPipeline({layout:j.createPipelineLayout({bindGroupLayouts:[B]}),vertex:{module:O,entryPoint:"vs"},fragment:{module:O,entryPoint:"fs",targets:[{format:U}]},primitive:{topology:"triangle-strip"}}),l=j.createSampler({magFilter:"linear",minFilter:"linear"}),p=setInterval(()=>{postMessage({type:T.STATS,fps:P,renderMs:M,totalCharts:J.size,activeCharts:e()}),P=0},1000),postMessage({type:T.GPU_READY}),!0}function o(_){_.dataX.destroy(),_.dataY.destroy();for(let[,O]of _.extraBuffers)O.destroy();for(let[,O]of _.seriesBuffers)O.destroy();if(_.seriesIndexBuffer)_.seriesIndexBuffer.destroy()}function r(_,O,N,m,W){let X=J.get(_);if(!X||!j)return;let Y=R.get(X.rendererName);if(!Y){postMessage({type:T.ERROR,code:Q.NO_RENDERER});return}try{X.minX=N.minX,X.maxX=N.maxX,X.minY=N.minY,X.maxY=N.maxY,X.perSeriesPassMeta=W;for(let H of X.series)o(H);if(X.series=[],X.seriesStorageBuffer)X.seriesStorageBuffer.destroy();if(O.length>0)X.seriesStorageBuffer=j.createBuffer({size:Math.max(32,O.length*32),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST});g(X,Y,m);for(let H=0;H<O.length;H++){let G=O[H],v=j.createBuffer({size:Math.max(16,G.dataX.byteLength),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),V=j.createBuffer({size:Math.max(16,G.dataY.byteLength),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST});j.queue.writeBuffer(v,0,G.dataX),j.queue.writeBuffer(V,0,G.dataY);let K=new Map;for(let[$,Z]of Object.entries(G.extra??{})){let x=j.createBuffer({size:Math.max(16,Z.byteLength),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST});j.queue.writeBuffer(x,0,Z),K.set($,x)}let q={label:G.label,colorR:G.colorR,colorG:G.colorG,colorB:G.colorB,dataX:v,dataY:V,extraBuffers:K,seriesBuffers:new Map,seriesIndexBuffer:null,pointCount:G.dataX.length,visibleStart:0,visibleCount:G.dataX.length,hidden:G.hidden??!1,passBindGroups:[]};X.series.push(q),u(q,H,Y,m)}f(X,Y)}catch(H){postMessage({type:T.ERROR,code:Q.UPDATE})}}self.onmessage=async(_)=>{let{type:O,...N}=_.data;switch(O){case T.INIT:w=N.isDark||!1,await a();break;case T.THEME:w=N.isDark,s();break;case T.REGISTER_RENDERER:{if(!j){postMessage({type:T.ERROR,code:Q.NOT_READY});break}let m={name:N.name,shaders:N.shaders,passes:N.passes,bufferDefs:N.bufferDefs??[],uniformDefs:N.uniformDefs??[]};try{R.set(N.name,d(m))}catch(W){postMessage({type:T.ERROR,code:Q.COMPILE})}break}case T.REGISTER_CHART:{if(!j)break;let m=N.canvas.getContext("webgpu");if(!m){postMessage({type:T.ERROR,code:Q.CTX_GET});break}try{m.configure({device:j,format:U,alphaMode:"premultiplied"})}catch(G){postMessage({type:T.ERROR,code:Q.CTX_CFG});break}let W=j.limits.maxTextureDimension2D,X=Math.min(Math.max(1,Math.floor(Number(N.canvas.width)||800)),W),Y=Math.min(Math.max(1,Math.floor(Number(N.canvas.height)||400)),W),H={id:N.id,canvas:N.canvas,ctx:m,rendererName:N.rendererName,visible:!0,series:[],uniformBuffer:j.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),seriesStorageBuffer:null,outputTexture:null,outputTextureView:null,blitBindGroup:null,chartBuffers:new Map,customUniformBuffer:null,customUniformValues:N.customUniformValues??{},chartPassBindGroups:[],perSeriesPassMeta:N.perSeriesPassMeta??[],width:X,height:Y,panX:0,panY:0,zoomX:1,zoomY:1,minX:0,maxX:1,maxY:1,minY:0,bgColor:N.bgColor??null,dirty:!0};try{S(H)}catch(G){postMessage({type:T.ERROR,code:Q.TEX});break}J.set(N.id,H);break}case T.UNREGISTER_CHART:{let m=J.get(N.id);if(m){try{m.ctx.unconfigure()}catch{}if(m.uniformBuffer.destroy(),m.seriesStorageBuffer)m.seriesStorageBuffer.destroy();if(m.outputTexture)m.outputTexture.destroy();if(m.customUniformBuffer)m.customUniformBuffer.destroy();for(let[,W]of m.chartBuffers)W.destroy();for(let W of m.series)o(W);J.delete(N.id)}break}case T.UPDATE_SERIES:{r(N.id,N.series,N.bounds,N.bufferSizes??{},N.perSeriesPassMeta??[]);let m=J.get(N.id);if(m)A(m);break}case T.RESIZE:{let m=J.get(N.id);if(!m||N.width<=0||N.height<=0)break;let W=j.limits.maxTextureDimension2D,X=Math.min(N.width,W),Y=Math.min(N.height,W);if(X===m.width&&Y===m.height)break;if(m.width=X,m.height=Y,m.canvas.width=X,m.canvas.height=Y,N.perSeriesPassMeta?.length>0)m.perSeriesPassMeta=N.perSeriesPassMeta;let H=R.get(m.rendererName);try{if(S(m),H&&N.bufferSizes){g(m,H,N.bufferSizes);for(let G=0;G<m.series.length;G++)u(m.series[G],G,H,N.bufferSizes);f(m,H)}}catch(G){postMessage({type:T.ERROR,code:Q.RESIZE})}A(m);break}case T.VIEW_TRANSFORM:{let m=J.get(N.id);if(m)m.panX=N.panX,m.panY=N.panY,m.zoomX=Math.max(0.1,Math.min(1e6,N.zoomX)),m.zoomY=Math.max(0.1,Math.min(1e6,N.zoomY)),A(m);break}case T.BATCH_VIEW_TRANSFORM:{let m=Math.max(0.1,Math.min(1e6,N.zoomX)),W=Math.max(0.1,Math.min(1e6,N.zoomY));for(let X of N.transforms){let Y=J.get(X.id);if(Y)Y.panX=N.panX,Y.panY=N.panY,Y.zoomX=m,Y.zoomY=W,Y.dirty=!0}F();break}case T.SET_VISIBILITY:{let m=J.get(N.id);if(m){if(m.visible=N.visible,N.visible&&m.dirty)F()}break}case T.SET_STYLE:{let m=J.get(N.id);if(m){if(N.bgColor!==void 0)m.bgColor=N.bgColor;if(N.hiddenSeries!==void 0)for(let W=0;W<m.series.length;W++)m.series[W].hidden=N.hiddenSeries.has(W);A(m)}break}case T.SET_UNIFORMS:{let m=J.get(N.id);if(!m)break;Object.assign(m.customUniformValues,N.values);let W=R.get(m.rendererName);if(W)y(m,W.config);A(m);break}}};\n';var l={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};class Y{id;_mgr;constructor(e,t){this.id=e,this._mgr=t}get _c(){return this._mgr.charts.get(this.id)}setData(e){this._mgr.updateSeries(this.id,e)}configure(e){let t=this._c;if(!t)return;Object.assign(t.config,e);let i=new Set((t.renderer.uniforms??[]).map((r)=>r.name)),f={};for(let r of Object.keys(e)){let o=e[r];if(typeof o==="number"&&i.has(r))f[r]=o}if(Object.keys(f).length>0)Object.assign(t.customUniforms,f),this._mgr.worker?.postMessage({type:l.SET_UNIFORMS,id:this.id,values:f});if("hiddenSeries"in e)this._mgr.worker?.postMessage({type:l.SET_STYLE,id:this.id,hiddenSeries:e.hiddenSeries??new Set});if("bgColor"in e&&e.bgColor!==void 0){let[r,o,N]=e.bgColor,g=t.el.querySelector("div");if(g)g.style.background=`rgb(${Math.round(r*255)},${Math.round(o*255)},${Math.round(N*255)})`;this._mgr.worker?.postMessage({type:l.SET_STYLE,id:this.id,bgColor:e.bgColor})}this._mgr.requestRender(this.id),this._mgr.drawChart(t)}addPlugin(e){let t=this._c;if(!t||t.plugins.some((f)=>f.name===e.name))return;let i=t.el.querySelector("div");e.install?.(t,i),t.plugins.push(e),this._mgr.drawChart(t)}removePlugin(e){let t=this._c;if(!t)return;let i=t.plugins.findIndex((f)=>f.name===e);if(i>=0)t.plugins[i].uninstall?.(t),t.plugins.splice(i,1),this._mgr.drawChart(t)}hasPlugin(e){return this._c?.plugins.some((t)=>t.name===e)??!1}resetView(){this._mgr.resetView(this.id)}destroy(){this._mgr.destroy(this.id)}}var S=null;function A(e){if(typeof e!=="string")return e;if(!S)S=document.createElement("i"),S.style.cssText="display:none",document.body.appendChild(S);S.style.color=e;let t=getComputedStyle(S).color.match(/\d+/g);return{r:+t[0]/255,g:+t[1]/255,b:+t[2]/255}}function P(e,t,i){let f=devicePixelRatio||1;if(e.width=Math.round(t*f),e.height=Math.round(i*f),e instanceof HTMLCanvasElement)e.style.width=`${t}px`,e.style.height=`${i}px`}class U{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((e)=>{for(let t of e){let i=t.target.dataset.chartId;if(!i)continue;let f=this.charts.get(i);if(!f)continue;if(f.visible=t.isIntersecting,this.worker?.postMessage({type:l.SET_VISIBILITY,id:i,visible:t.isIntersecting}),t.isIntersecting)this.drawChart(f)}},{threshold:0.01}),this.resizeObserver=new ResizeObserver((e)=>{for(let t of e){let i=t.target.dataset.chartId;if(!i)continue;let f=this.charts.get(i);if(!f)continue;let{width:r,height:o}=t.contentRect;if(r<=0||o<=0)continue;f.width=r,f.height=o;let N=devicePixelRatio||1;P(f.backCanvas,r,o),P(f.frontCanvas,r,o);let{bufferSizes:g,perSeriesPassMeta:m}=this.computeRendererMeta(f.renderer,f);this.worker?.postMessage({type:l.RESIZE,id:i,width:Math.round(r*N),height:Math.round(o*N),bufferSizes:g,perSeriesPassMeta:m}),this.drawChart(f)}})}static getInstance(){if(!U.instance)U.instance=new U;return U.instance}get isDark(){return this._isDark}get syncViews(){return this._syncViews}use(e){if("passes"in e){let t=e;if(this.renderers.set(t.name,t),this.worker)this.sendRendererRegistration(t);else this.pendingRenderers.push(t)}else{let t=e;if(!this.uiPlugins.some((i)=>i.name===t.name))this.uiPlugins.push(t)}}async init(){if(this.worker)return!0;return new Promise((e)=>{Promise.resolve().then(() => y).then(({WORKER_CODE:t})=>{let i=new Blob([t],{type:"application/javascript"});this.worker=new Worker(URL.createObjectURL(i),{type:"module"}),this.setupWorkerHandlers(e)}).catch(()=>{this.worker=new Worker(new URL("./gpu-worker.js",import.meta.url),{type:"module"}),this.setupWorkerHandlers(e)})})}setupWorkerHandlers(e){if(!this.worker)return;this.worker.onmessage=(t)=>{let{type:i,...f}=t.data;switch(i){case l.GPU_READY:for(let r of this.pendingRenderers)this.sendRendererRegistration(r);this.pendingRenderers=[],e(!0);break;case l.ERROR:console.error("chartai:",f.code),e(!1);break;case l.STATS:this.currentStats={fps:f.fps,renderMs:f.renderMs,total:f.totalCharts,active:f.activeCharts};for(let r of this.statsCallbacks)r(this.currentStats);break}},this.worker.onerror=(t)=>{console.error("chartai:",t),e(!1)},this.worker.postMessage({type:l.INIT,isDark:this._isDark})}sendRendererRegistration(e){let t=(e.buffers??[]).map((i)=>({name:i.name,usages:i.usages,perSeries:e.passes.some((f)=>f.perSeries!==!1&&f.bindings.some((r)=>r.source===i.name))}));this.worker?.postMessage({type:l.REGISTER_RENDERER,name:e.name,shaders:e.shaders,passes:e.passes.map((i)=>({type:i.type,shader:i.shader,bindings:i.bindings,perSeries:i.perSeries!==!1,topology:i.topology,loadOp:i.loadOp,blend:i.blend})),bufferDefs:t,uniformDefs:e.uniforms??[]})}computeRendererMeta(e,t){let i={},f=[],r=t.series.length>0?t.series:[{rawX:[],rawY:[],extra:{},label:"",color:{r:0,g:0,b:0}}],o=devicePixelRatio||1,N=Math.round(t.width*o),g=Math.round(t.height*o);for(let m of r){let R={width:N,height:g,samples:m.rawX.length,seriesCount:r.length,bounds:t.bounds,view:t.view};for(let T of e.buffers??[]){let G=T.bytes(R);i[T.name]=Math.max(i[T.name]??0,G)}f.push(e.passes.map((T)=>({dispatch:T.dispatch?.(R),draw:T.draw?.(R)})))}return{bufferSizes:i,perSeriesPassMeta:f}}create(e){if(!this.worker)throw Error("No worker. Call init().");let t=this.renderers.get(e.type);if(!t)throw Error(`No renderer "${e.type}". Call manager.use() first.`);let i=`chart-${++this.chartIdCounter}`,f=document.createElement("div");f.dataset.chartId=i,f.style.cssText="width:100%;height:100%;position:relative;";let r=document.createElement("div");r.dataset.chartId=i,r.style.cssText="width:100%;height:100%;position:relative;";let o=(a,s)=>{let n=document.createElement("canvas");return n.style.cssText=`position:absolute;inset:0;width:100%;height:100%;pointer-events:${s};z-index:${a};`,n},N=o(0,"none"),g=o(1,"auto"),m=o(2,"none");r.append(N,g,m),f.appendChild(r),e.container.appendChild(f);let R;try{R=g.transferControlToOffscreen()}catch(a){throw Error(`Failed OffscreenCanvas: ${a}`)}let T=r.getBoundingClientRect(),G=T.width||400,B=T.height||200;if(P(R,G,B),P(N,G,B),P(m,G,B),e.bgColor){let[a,s,n]=e.bgColor;r.style.background=`rgb(${Math.round(a*255)},${Math.round(s*255)},${Math.round(n*255)})`}let p={};for(let a of t.uniforms??[]){let s=e[a.name];p[a.name]=typeof s==="number"?s:a.default}let u={id:i,config:e,el:f,backCanvas:N,frontCanvas:m,width:G,height:B,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:t,customUniforms:p};this.charts.set(i,u);let _=devicePixelRatio||1,{bufferSizes:O,perSeriesPassMeta:d}=this.computeRendererMeta(t,u);this.worker.postMessage({type:l.REGISTER_CHART,id:i,canvas:R,rendererName:e.type,bgColor:e.bgColor??null,bufferSizes:O,perSeriesPassMeta:d,customUniformValues:p,width:Math.round(G*_),height:Math.round(B*_)},[R]),this.visibilityObserver.observe(f),this.resizeObserver.observe(r);for(let a of u.plugins)a.install?.(u,r);return t.install?.(u,r),this.updateSeries(i,e.series),new Y(i,this)}destroy(e){let t=this.charts.get(e);if(!t)return;t.renderer.uninstall?.(t);for(let f of t.plugins)f.uninstall?.(t);this.visibilityObserver.unobserve(t.el);let i=t.el.querySelector("div");if(i)this.resizeObserver.unobserve(i);t.el.remove(),this.worker?.postMessage({type:l.UNREGISTER_CHART,id:e}),this.charts.delete(e)}updateSeries(e,t){let i=this.charts.get(e);if(!i||!this.worker||t.length===0)return;i.config.hiddenSeries=t.reduce((u,_,O)=>{if(_.hidden)u.add(O);return u},new Set),i.series=t.map((u)=>{let _=u.x.length,O=A(u.color);if(_===0)return{label:u.label,color:O,rawX:[],rawY:[],extra:{}};let d=Array.from({length:_},(s,n)=>n).sort((s,n)=>u.x[s]-u.x[n]),a={};for(let s in u)if(s!=="label"&&s!=="color"&&s!=="x"&&s!=="y"&&Array.isArray(u[s]))a[s]=d.map((n)=>u[s][n]);return{label:u.label,color:O,rawX:d.map((s)=>u.x[s]),rawY:d.map((s)=>u.y[s]),extra:a}});let f=i.renderer.computeBounds?.(i.series),{minX:r,maxX:o,minY:N,maxY:g}=f??(()=>{let u=1/0,_=-1/0,O=1/0,d=-1/0;for(let n of i.series)for(let E=0;E<n.rawX.length;E++){if(n.rawX[E]<u)u=n.rawX[E];if(n.rawX[E]>_)_=n.rawX[E];if(n.rawY[E]<O)O=n.rawY[E];if(n.rawY[E]>d)d=n.rawY[E]}let a=(_-u)*0.05||1,s=(d-O)*0.1||1;return{minX:u-a,maxX:_+a,minY:O-s,maxY:d+s}})(),m=i.config.defaultBounds;if(m){if(m.minX!==void 0)r=m.minX;if(m.maxX!==void 0)o=m.maxX;if(m.minY!==void 0)N=m.minY;if(m.maxY!==void 0)g=m.maxY}i.bounds={minX:r,maxX:o,minY:N,maxY:g};let{bufferSizes:R,perSeriesPassMeta:T}=this.computeRendererMeta(i.renderer,i),G=i.config.hiddenSeries??new Set,B=i.series.map((u,_)=>{let O={};for(let d in u.extra)O[d]=new Float32Array(u.extra[d]);return{label:u.label,colorR:u.color.r,colorG:u.color.g,colorB:u.color.b,dataX:new Float32Array(u.rawX),dataY:new Float32Array(u.rawY),extra:O,hidden:G.has(_)}}),p=B.flatMap((u)=>[u.dataX.buffer,u.dataY.buffer,...Object.values(u.extra).map((_)=>_.buffer)]);this.worker.postMessage({type:l.UPDATE_SERIES,id:e,series:B,bounds:i.bounds,bufferSizes:R,perSeriesPassMeta:T},p),this.sendViewTransform(i),this.drawChart(i)}setSyncViews(e){this._syncViews=e}setTheme(e){this._isDark=e,this.worker?.postMessage({type:l.THEME,isDark:e});for(let t of this.charts.values())this.drawChart(t)}onStats(e){return this.statsCallbacks.push(e),()=>{let t=this.statsCallbacks.indexOf(e);if(t>=0)this.statsCallbacks.splice(t,1)}}getStats(){return{...this.currentStats}}resetView(e){let t=this.charts.get(e);if(!t)return;for(let B of t.plugins)B.resetView?.(t);let{panX:i,panY:f,zoomX:r,zoomY:o}=t.view,{panX:N,panY:g,zoomX:m,zoomY:R}=t.homeView,T=performance.now(),G=()=>{let B=Math.min(1,(performance.now()-T)/300),p=1-Math.pow(1-B,3);if(t.view.panX=i+(N-i)*p,t.view.panY=f+(g-f)*p,t.view.zoomX=r+(m-r)*p,t.view.zoomY=o+(R-o)*p,this.sendViewTransform(t),this.drawChart(t),this._syncViews)this.syncAllViews(t);if(B<1)requestAnimationFrame(G)};requestAnimationFrame(G)}setHiddenSeries(e,t){let i=this.charts.get(e);if(!i)return;i.config.hiddenSeries=new Set(t),this.worker?.postMessage({type:l.SET_STYLE,id:e,hiddenSeries:i.config.hiddenSeries}),this.drawChart(i)}requestRender(e){let t=this.charts.get(e);if(t)this.sendViewTransform(t)}sendViewTransform(e){this.worker?.postMessage({type:l.VIEW_TRANSFORM,id:e.id,panX:e.view.panX,panY:e.view.panY,zoomX:e.view.zoomX,zoomY:e.view.zoomY})}syncAllViews(e){let t=[];for(let i of this.charts.values())if(i.id!==e.id)i.view={...e.view},t.push({id:i.id}),this.drawChart(i);if(t.length>0)this.worker?.postMessage({type:l.BATCH_VIEW_TRANSFORM,panX:e.view.panX,panY:e.view.panY,zoomX:e.view.zoomX,zoomY:e.view.zoomY,transforms:t})}drawChart(e){if(!e.visible)return;let t=devicePixelRatio||1,i=e.backCanvas.getContext("2d");if(i){i.clearRect(0,0,e.backCanvas.width,e.backCanvas.height),i.save(),i.scale(t,t);for(let r of e.plugins)r.beforeDraw?.(i,e);i.restore()}let f=e.frontCanvas.getContext("2d");if(f){f.clearRect(0,0,e.frontCanvas.width,e.frontCanvas.height),f.save(),f.scale(t,t);for(let r of e.plugins)r.afterDraw?.(f,e);f.restore()}}}var j=U.getInstance();export{j as ChartManager,Y as Chart};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../src/charts/area.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD,MAAM,WAAW,UAAU;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,SAAS,EAAE,cAiDvB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LINE_COMPUTE_SHADER
|
|
3
|
+
} from "../chunk-yabjrff2.js";
|
|
4
|
+
import {
|
|
5
|
+
COMPUTE_WG,
|
|
6
|
+
UNIFORM_STRUCT
|
|
7
|
+
} from "../chunk-0jepamv9.js";
|
|
8
|
+
import"../chunk-5gtx3pza.js";
|
|
9
|
+
|
|
10
|
+
// src/shaders/area.ts
|
|
11
|
+
var AREA_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)@interpolate(flat)seriesIdx: u32,@location(1)@interpolate(flat)valid: f32,};@vertex fn vs(@builtin(vertex_index)vi: u32,@builtin(instance_index)series_idx: u32)-> VertexOutput{var out: VertexOutput;out.seriesIdx = series_idx;out.valid = 0.0;let maxCols = u32(u.width);if(vi >= maxCols * 2u){out.pos = vec4f(0.0,0.0,0.0,0.0);return out;}let col = vi / 2u;let onLine =(vi % 2u)== 0u;let d = lineData[col];let viewRangeY = u.viewMaxY - u.viewMinY;let baseline = select(1.0,1.0 -(u.dataMinY - u.viewMinY)/ viewRangeY,viewRangeY > 0.0001);let viewRangeX = u.viewMaxX - u.viewMinX;let leftBound = select(0.0,clamp((u.dataMinX - u.viewMinX)/ viewRangeX,0.0,1.0),viewRangeX > 0.0001);let rightBound = select(1.0,clamp((u.dataMaxX - u.viewMinX)/ viewRangeX,0.0,1.0),viewRangeX > 0.0001);var sx = clamp(d.screenX,leftBound,rightBound);var py = select(baseline,(d.minScreenY + d.maxScreenY)* 0.5,onLine);if(d.valid < 0.5 && vi > 0u){let prevCol =(vi - 1u)/ 2u;let pd = lineData[prevCol];sx = clamp(pd.screenX,leftBound,rightBound);py = select(baseline,(pd.minScreenY + pd.maxScreenY)* 0.5,(vi - 1u)% 2u == 0u);}let clipX = sx * 2.0 - 1.0;let clipY = 1.0 - py * 2.0;out.valid = d.valid;out.pos = vec4f(clipX,clipY,0.0,1.0);return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{if(in.valid < 0.5){discard;}let series = allSeries[in.seriesIdx];return vec4f(series.color.rgb,1.0);}`;
|
|
12
|
+
|
|
13
|
+
// src/charts/area.ts
|
|
14
|
+
var AreaChart = {
|
|
15
|
+
name: "area",
|
|
16
|
+
shaders: {
|
|
17
|
+
compute: LINE_COMPUTE_SHADER,
|
|
18
|
+
render: AREA_RENDER_SHADER
|
|
19
|
+
},
|
|
20
|
+
uniforms: [
|
|
21
|
+
{ name: "maxSamplesPerPixel", type: "u32", default: 1e4 }
|
|
22
|
+
],
|
|
23
|
+
buffers: [
|
|
24
|
+
{
|
|
25
|
+
name: "lineBuffer",
|
|
26
|
+
bytes: ({ width }) => Math.max(16, width * 4 * 4),
|
|
27
|
+
usages: ["STORAGE"]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
passes: [
|
|
31
|
+
{
|
|
32
|
+
type: "compute",
|
|
33
|
+
shader: "compute",
|
|
34
|
+
perSeries: true,
|
|
35
|
+
dispatch: ({ width }) => ({ x: Math.ceil(Math.max(1, width) / COMPUTE_WG) }),
|
|
36
|
+
bindings: [
|
|
37
|
+
{ binding: 0, source: "uniforms" },
|
|
38
|
+
{ binding: 1, source: "x-data" },
|
|
39
|
+
{ binding: 2, source: "y-data" },
|
|
40
|
+
{ binding: 3, source: "lineBuffer", write: true },
|
|
41
|
+
{ binding: 4, source: "series-info" },
|
|
42
|
+
{ binding: 5, source: "custom-uniforms" }
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "render",
|
|
47
|
+
shader: "render",
|
|
48
|
+
topology: "triangle-strip",
|
|
49
|
+
loadOp: "load",
|
|
50
|
+
blend: {
|
|
51
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha" },
|
|
52
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }
|
|
53
|
+
},
|
|
54
|
+
draw: ({ width }) => Math.max(0, width * 2),
|
|
55
|
+
bindings: [
|
|
56
|
+
{ binding: 0, source: "uniforms" },
|
|
57
|
+
{ binding: 1, source: "lineBuffer" },
|
|
58
|
+
{ binding: 2, source: "series-info" }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
};
|
|
63
|
+
export {
|
|
64
|
+
AreaChart
|
|
65
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as x}from"../chunk-gm0d4cgx.js";import{f as v,g as k}from"../chunk-64q9a7nw.js";import"../chunk-bbyt23tw.js";var q=`${k}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)@interpolate(flat)seriesIdx: u32,@location(1)@interpolate(flat)valid: f32,};@vertex fn vs(@builtin(vertex_index)vi: u32,@builtin(instance_index)series_idx: u32)-> VertexOutput{var out: VertexOutput;out.seriesIdx = series_idx;out.valid = 0.0;let maxCols = u32(u.width);if(vi >= maxCols * 2u){out.pos = vec4f(0.0,0.0,0.0,0.0);return out;}let col = vi / 2u;let onLine =(vi % 2u)== 0u;let d = lineData[col];let viewRangeY = u.viewMaxY - u.viewMinY;let baseline = select(1.0,1.0 -(u.dataMinY - u.viewMinY)/ viewRangeY,viewRangeY > 0.0001);let viewRangeX = u.viewMaxX - u.viewMinX;let leftBound = select(0.0,clamp((u.dataMinX - u.viewMinX)/ viewRangeX,0.0,1.0),viewRangeX > 0.0001);let rightBound = select(1.0,clamp((u.dataMaxX - u.viewMinX)/ viewRangeX,0.0,1.0),viewRangeX > 0.0001);var sx = clamp(d.screenX,leftBound,rightBound);var py = select(baseline,(d.minScreenY + d.maxScreenY)* 0.5,onLine);if(d.valid < 0.5 && vi > 0u){let prevCol =(vi - 1u)/ 2u;let pd = lineData[prevCol];sx = clamp(pd.screenX,leftBound,rightBound);py = select(baseline,(pd.minScreenY + pd.maxScreenY)* 0.5,(vi - 1u)% 2u == 0u);}let clipX = sx * 2.0 - 1.0;let clipY = 1.0 - py * 2.0;out.valid = d.valid;out.pos = vec4f(clipX,clipY,0.0,1.0);return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{if(in.valid < 0.5){discard;}let series = allSeries[in.seriesIdx];return vec4f(series.color.rgb,1.0);}`;var V={name:"area",shaders:{compute:x,render:q},uniforms:[{name:"maxSamplesPerPixel",type:"u32",default:1e4}],buffers:[{name:"lineBuffer",bytes:({width:j})=>Math.max(16,j*4*4),usages:["STORAGE"]}],passes:[{type:"compute",shader:"compute",perSeries:!0,dispatch:({width:j})=>({x:Math.ceil(Math.max(1,j)/v)}),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:"triangle-strip",loadOp:"load",blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha"}},draw:({width:j})=>Math.max(0,j*2),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"lineBuffer"},{binding:2,source:"series-info"}]}]};export{V as AreaChart};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RendererPlugin } from "../types.ts";
|
|
2
|
+
export interface BarConfig {
|
|
3
|
+
maxSamplesPerPixel?: number;
|
|
4
|
+
}
|
|
5
|
+
declare module "../types.ts" {
|
|
6
|
+
interface ChartTypeRegistry {
|
|
7
|
+
bar: BarConfig;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare const BarChart: RendererPlugin;
|
|
11
|
+
//# sourceMappingURL=bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/charts/bar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,MAAM,WAAW,SAAS;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,iBAAiB;QACzB,GAAG,EAAE,SAAS,CAAC;KAChB;CACF;AAED,eAAO,MAAM,QAAQ,EAAE,cAkDtB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BINARY_SEARCH,
|
|
3
|
+
COMPUTE_WG,
|
|
4
|
+
UNIFORM_STRUCT
|
|
5
|
+
} from "../chunk-0jepamv9.js";
|
|
6
|
+
import"../chunk-5gtx3pza.js";
|
|
7
|
+
|
|
8
|
+
// src/shaders/box.ts
|
|
9
|
+
var BOX_COMPUTE_SHADER = `${UNIFORM_STRUCT}struct BarUniforms{maxSamplesPerPixel: u32,_p1: u32,_p2: u32,_p3: u32};struct BarData{screenX: f32,minY: f32,maxY: f32,barWidth: 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> barData: array<BarData>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(6)var<uniform> bu: BarUniforms;${BINARY_SEARCH}fn barHalfWidth(idx: u32,count: u32)-> f32{if(count <= 1u){return(u.viewMaxX - u.viewMinX)* 0.4;}var spacing: f32;if(idx == 0u){spacing = dataX[1u] - dataX[0u];}else if(idx >= count - 1u){spacing = dataX[count - 1u] - dataX[count - 2u];}else{spacing = min(dataX[idx + 1u] - dataX[idx],dataX[idx] - dataX[idx - 1u]);}let seriesCount = max(1u,u.seriesCount);return(spacing * 0.4)/ f32(seriesCount);}@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){barData[outputIdx] = BarData(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){barData[outputIdx] = BarData(0.0,0.0,0.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;let startIdx = lowerBound(pixelMinX,count);var endIdx = lowerBound(pixelMaxX,count);endIdx = min(endIdx,count);let centerX =(pixelMinX + pixelMaxX)* 0.5;let onePixel = 1.0 / u.width;if(startIdx >= endIdx){var hit = false;var bestX: f32 = 0.0;var bestY: f32 = 0.0;var bestHW: f32 = 0.0;var bestDist: f32 = 1e10;if(startIdx < count){let bx = dataX[startIdx];let hw = barHalfWidth(startIdx,count);if(pixelMinX < bx + hw && pixelMaxX > bx - hw){let d = abs(bx - centerX);bestX = bx;bestY = dataY[startIdx];bestHW = hw;bestDist = d;hit = true;}}if(startIdx > 0u){let prev = startIdx - 1u;let bx = dataX[prev];let hw = barHalfWidth(prev,count);if(pixelMinX < bx + hw && pixelMaxX > bx - hw){let d = abs(bx - centerX);if(d < bestDist){bestX = bx;bestY = dataY[prev];bestHW = hw;bestDist = d;}hit = true;}}if(!hit){barData[outputIdx] = BarData(0.0,0.0,0.0,0.0);return;}let seriesCount = max(1u,u.seriesCount);let barOffset =(f32(seriesIdx.index)- f32(seriesCount - 1u)* 0.5)*(bestHW * 2.0);let offsetX = bestX + barOffset;let normX =(offsetX - u.viewMinX)/ viewRangeX;let fullWidth = bestHW * 2.0 / viewRangeX;let gapSize = max(onePixel,fullWidth * 0.05);let bw = max(fullWidth - gapSize,onePixel);barData[outputIdx] = BarData(normX,bestY,bestY,bw);return;}var dataMinY = dataY[startIdx];var dataMaxY = dataY[startIdx];let rangeCount = endIdx - startIdx;let maxSamples = bu.maxSamplesPerPixel;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){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 hw = barHalfWidth(startIdx,count);let fullWidth = hw * 2.0 / viewRangeX;let gapSize = max(onePixel,fullWidth * 0.05);let bw = max(fullWidth - gapSize,onePixel);let seriesCount = max(1u,u.seriesCount);let barOffset =(f32(seriesIdx.index)- f32(seriesCount - 1u)* 0.5)*(hw * 2.0);let dataX_centered = dataX[startIdx] + barOffset;let normX =(dataX_centered - u.viewMinX)/ viewRangeX;barData[outputIdx] = BarData(normX,dataMinY,dataMaxY,bw);}`;
|
|
10
|
+
var BOX_RENDER_SHADER = `${UNIFORM_STRUCT}struct BarData{screenX: f32,minY: f32,maxY: f32,barWidth: f32,};@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> barData: array<BarData>;@group(0)@binding(2)var<storage,read> allSeries: array<SeriesInfo>;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)normY: 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 colIdx = vi / 6u;let vertexType = vi % 6u;if(colIdx >= maxCols){out.pos = vec4f(0.0,0.0,0.0,0.0);out.normY = 0.0;return out;}let bd = barData[colIdx];if(bd.barWidth <= 0.0){out.pos = vec4f(0.0,0.0,0.0,0.0);out.normY = 0.0;return out;}let viewRangeY = u.viewMaxY - u.viewMinY;let safeRangeY = select(viewRangeY,1.0,viewRangeY < 0.0001);let normMinY =(min(bd.minY,0.0)- u.viewMinY)/ safeRangeY;let normMaxY =(max(bd.maxY,0.0)- u.viewMinY)/ safeRangeY;let top = 1.0 - normMaxY;let bottom = 1.0 - normMinY;let halfW = bd.barWidth * 0.5;let left = bd.screenX - halfW;let right = bd.screenX + halfW;var positions = array<vec2f,6>(vec2f(left,bottom),vec2f(right,bottom),vec2f(left,top),vec2f(left,top),vec2f(right,bottom),vec2f(right,top));let screenPos = positions[vertexType];let clipX = screenPos.x * 2.0 - 1.0;let clipY = 1.0 - screenPos.y * 2.0;out.pos = vec4f(clipX,clipY,0.0,1.0);out.normY = normMaxY;return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{let series = allSeries[in.seriesIdx];return vec4f(series.color.rgb,0.85);}`;
|
|
11
|
+
|
|
12
|
+
// src/charts/bar.ts
|
|
13
|
+
var BarChart = {
|
|
14
|
+
name: "bar",
|
|
15
|
+
shaders: {
|
|
16
|
+
compute: BOX_COMPUTE_SHADER,
|
|
17
|
+
render: BOX_RENDER_SHADER
|
|
18
|
+
},
|
|
19
|
+
uniforms: [
|
|
20
|
+
{ name: "maxSamplesPerPixel", type: "u32", default: 1e4 }
|
|
21
|
+
],
|
|
22
|
+
buffers: [
|
|
23
|
+
{
|
|
24
|
+
name: "barBuffer",
|
|
25
|
+
bytes: ({ width }) => Math.max(16, width * 4 * 4),
|
|
26
|
+
usages: ["STORAGE"]
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
passes: [
|
|
30
|
+
{
|
|
31
|
+
type: "compute",
|
|
32
|
+
shader: "compute",
|
|
33
|
+
perSeries: true,
|
|
34
|
+
dispatch: ({ width }) => ({ x: Math.ceil(Math.max(1, width) / COMPUTE_WG) }),
|
|
35
|
+
bindings: [
|
|
36
|
+
{ binding: 0, source: "uniforms" },
|
|
37
|
+
{ binding: 1, source: "x-data" },
|
|
38
|
+
{ binding: 2, source: "y-data" },
|
|
39
|
+
{ binding: 3, source: "barBuffer", write: true },
|
|
40
|
+
{ binding: 4, source: "series-info" },
|
|
41
|
+
{ binding: 5, source: "series-index" },
|
|
42
|
+
{ binding: 6, source: "custom-uniforms" }
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "render",
|
|
47
|
+
shader: "render",
|
|
48
|
+
topology: "triangle-list",
|
|
49
|
+
loadOp: "load",
|
|
50
|
+
blend: {
|
|
51
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha" },
|
|
52
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }
|
|
53
|
+
},
|
|
54
|
+
draw: ({ width }) => width * 6,
|
|
55
|
+
bindings: [
|
|
56
|
+
{ binding: 0, source: "uniforms" },
|
|
57
|
+
{ binding: 1, source: "barBuffer" },
|
|
58
|
+
{ binding: 2, source: "series-info" }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
};
|
|
63
|
+
export {
|
|
64
|
+
BarChart
|
|
65
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{f as e,g as a,h as i}from"../chunk-64q9a7nw.js";import"../chunk-bbyt23tw.js";var r=`${a}struct BarUniforms{maxSamplesPerPixel: u32,_p1: u32,_p2: u32,_p3: u32};struct BarData{screenX: f32,minY: f32,maxY: f32,barWidth: 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> barData: array<BarData>;@group(0)@binding(4)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(5)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(6)var<uniform> bu: BarUniforms;${i}fn barHalfWidth(idx: u32,count: u32)-> f32{if(count <= 1u){return(u.viewMaxX - u.viewMinX)* 0.4;}var spacing: f32;if(idx == 0u){spacing = dataX[1u] - dataX[0u];}else if(idx >= count - 1u){spacing = dataX[count - 1u] - dataX[count - 2u];}else{spacing = min(dataX[idx + 1u] - dataX[idx],dataX[idx] - dataX[idx - 1u]);}let seriesCount = max(1u,u.seriesCount);return(spacing * 0.4)/ f32(seriesCount);}@compute @workgroup_size(${e})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){barData[outputIdx] = BarData(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){barData[outputIdx] = BarData(0.0,0.0,0.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;let startIdx = lowerBound(pixelMinX,count);var endIdx = lowerBound(pixelMaxX,count);endIdx = min(endIdx,count);let centerX =(pixelMinX + pixelMaxX)* 0.5;let onePixel = 1.0 / u.width;if(startIdx >= endIdx){var hit = false;var bestX: f32 = 0.0;var bestY: f32 = 0.0;var bestHW: f32 = 0.0;var bestDist: f32 = 1e10;if(startIdx < count){let bx = dataX[startIdx];let hw = barHalfWidth(startIdx,count);if(pixelMinX < bx + hw && pixelMaxX > bx - hw){let d = abs(bx - centerX);bestX = bx;bestY = dataY[startIdx];bestHW = hw;bestDist = d;hit = true;}}if(startIdx > 0u){let prev = startIdx - 1u;let bx = dataX[prev];let hw = barHalfWidth(prev,count);if(pixelMinX < bx + hw && pixelMaxX > bx - hw){let d = abs(bx - centerX);if(d < bestDist){bestX = bx;bestY = dataY[prev];bestHW = hw;bestDist = d;}hit = true;}}if(!hit){barData[outputIdx] = BarData(0.0,0.0,0.0,0.0);return;}let seriesCount = max(1u,u.seriesCount);let barOffset =(f32(seriesIdx.index)- f32(seriesCount - 1u)* 0.5)*(bestHW * 2.0);let offsetX = bestX + barOffset;let normX =(offsetX - u.viewMinX)/ viewRangeX;let fullWidth = bestHW * 2.0 / viewRangeX;let gapSize = max(onePixel,fullWidth * 0.05);let bw = max(fullWidth - gapSize,onePixel);barData[outputIdx] = BarData(normX,bestY,bestY,bw);return;}var dataMinY = dataY[startIdx];var dataMaxY = dataY[startIdx];let rangeCount = endIdx - startIdx;let maxSamples = bu.maxSamplesPerPixel;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){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 hw = barHalfWidth(startIdx,count);let fullWidth = hw * 2.0 / viewRangeX;let gapSize = max(onePixel,fullWidth * 0.05);let bw = max(fullWidth - gapSize,onePixel);let seriesCount = max(1u,u.seriesCount);let barOffset =(f32(seriesIdx.index)- f32(seriesCount - 1u)* 0.5)*(hw * 2.0);let dataX_centered = dataX[startIdx] + barOffset;let normX =(dataX_centered - u.viewMinX)/ viewRangeX;barData[outputIdx] = BarData(normX,dataMinY,dataMaxY,bw);}`,n=`${a}struct BarData{screenX: f32,minY: f32,maxY: f32,barWidth: f32,};@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> barData: array<BarData>;@group(0)@binding(2)var<storage,read> allSeries: array<SeriesInfo>;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)normY: 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 colIdx = vi / 6u;let vertexType = vi % 6u;if(colIdx >= maxCols){out.pos = vec4f(0.0,0.0,0.0,0.0);out.normY = 0.0;return out;}let bd = barData[colIdx];if(bd.barWidth <= 0.0){out.pos = vec4f(0.0,0.0,0.0,0.0);out.normY = 0.0;return out;}let viewRangeY = u.viewMaxY - u.viewMinY;let safeRangeY = select(viewRangeY,1.0,viewRangeY < 0.0001);let normMinY =(min(bd.minY,0.0)- u.viewMinY)/ safeRangeY;let normMaxY =(max(bd.maxY,0.0)- u.viewMinY)/ safeRangeY;let top = 1.0 - normMaxY;let bottom = 1.0 - normMinY;let halfW = bd.barWidth * 0.5;let left = bd.screenX - halfW;let right = bd.screenX + halfW;var positions = array<vec2f,6>(vec2f(left,bottom),vec2f(right,bottom),vec2f(left,top),vec2f(left,top),vec2f(right,bottom),vec2f(right,top));let screenPos = positions[vertexType];let clipX = screenPos.x * 2.0 - 1.0;let clipY = 1.0 - screenPos.y * 2.0;out.pos = vec4f(clipX,clipY,0.0,1.0);out.normY = normMaxY;return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{let series = allSeries[in.seriesIdx];return vec4f(series.color.rgb,0.85);}`;var l={name:"bar",shaders:{compute:r,render:n},uniforms:[{name:"maxSamplesPerPixel",type:"u32",default:1e4}],buffers:[{name:"barBuffer",bytes:({width:t})=>Math.max(16,t*4*4),usages:["STORAGE"]}],passes:[{type:"compute",shader:"compute",perSeries:!0,dispatch:({width:t})=>({x:Math.ceil(Math.max(1,t)/e)}),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"x-data"},{binding:2,source:"y-data"},{binding:3,source:"barBuffer",write:!0},{binding:4,source:"series-info"},{binding:5,source:"series-index"},{binding:6,source:"custom-uniforms"}]},{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:t})=>t*6,bindings:[{binding:0,source:"uniforms"},{binding:1,source:"barBuffer"},{binding:2,source:"series-info"}]}]};export{l as BarChart};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMPUTE_WG,
|
|
3
|
+
UNIFORM_STRUCT
|
|
4
|
+
} from "../chunk-0jepamv9.js";
|
|
5
|
+
import {
|
|
6
|
+
ChartManager
|
|
7
|
+
} from "../chunk-n8ew0z0e.js";
|
|
8
|
+
import"../chunk-93yrr7er.js";
|
|
9
|
+
import"../chunk-5gtx3pza.js";
|
|
10
|
+
|
|
11
|
+
// src/shaders/boids.ts
|
|
12
|
+
var BOID_STATE = `struct BoidState { pos: vec2f, vel: vec2f, species: u32, _pad: u32 }`;
|
|
13
|
+
var PERCEPTION = 0.2;
|
|
14
|
+
var SEP_R = PERCEPTION * 0.2;
|
|
15
|
+
var MAX_SPD = 0.003;
|
|
16
|
+
var TURN_RATE = 0.7;
|
|
17
|
+
var W_SEP = 0.15;
|
|
18
|
+
var W_ALIGN = 0.02;
|
|
19
|
+
var W_COH = 0.001;
|
|
20
|
+
var W_NOISE = 0.2;
|
|
21
|
+
var CONTAIN_STRENGTH = 0.003;
|
|
22
|
+
var CONTAIN_PAD = 0.1;
|
|
23
|
+
var CLOSE_CELLS = 1;
|
|
24
|
+
var GRID_W = 16;
|
|
25
|
+
var GRID_H = 16;
|
|
26
|
+
var MAX_PER_CELL = 16;
|
|
27
|
+
var GRID_HELPERS = `
|
|
28
|
+
const GRID_W = ${GRID_W}u;
|
|
29
|
+
const GRID_H = ${GRID_H}u;
|
|
30
|
+
const MAX_PER_CELL = ${MAX_PER_CELL}u;
|
|
31
|
+
// Returns (cellX, cellY, gridMinX, gridMinY) sized to cover the padded view.
|
|
32
|
+
fn gridParams(vMinX: f32, vMaxX: f32, vMinY: f32, vMaxY: f32) -> vec4f {
|
|
33
|
+
let cX = (vMaxX - vMinX) * ${1 + CONTAIN_PAD}f / f32(GRID_W);
|
|
34
|
+
let cY = (vMaxY - vMinY) * ${1 + CONTAIN_PAD}f / f32(GRID_H);
|
|
35
|
+
return vec4f(cX, cY,
|
|
36
|
+
(vMinX + vMaxX) * 0.5 - cX * f32(GRID_W) * 0.5,
|
|
37
|
+
(vMinY + vMaxY) * 0.5 - cY * f32(GRID_H) * 0.5);
|
|
38
|
+
}
|
|
39
|
+
fn boidToCell(pos: vec2f, gp: vec4f) -> vec2i {
|
|
40
|
+
return clamp(
|
|
41
|
+
vec2i(i32((pos.x - gp.z) / gp.x), i32((pos.y - gp.w) / gp.y)),
|
|
42
|
+
vec2i(0, 0), vec2i(i32(GRID_W) - 1, i32(GRID_H) - 1)
|
|
43
|
+
);
|
|
44
|
+
}`;
|
|
45
|
+
var BOIDS_INIT_SHADER = `${UNIFORM_STRUCT}${BOID_STATE}@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> boidsState: array<BoidState>;@group(0)@binding(4)var<uniform> seriesIdx: SeriesIndex;fn hash2(p: vec2f)-> vec2f{let q = vec2f(dot(p,vec2f(127.1,311.7)),dot(p,vec2f(269.5,183.3)));return fract(sin(q)* 43758.5453);}@compute @workgroup_size(${COMPUTE_WG})fn main(@builtin(global_invocation_id)id: vec3u){let i = id.x;if(i >= u.pointCount){return;}let b = boidsState[i];if(b.vel.x == 0.0 && b.vel.y == 0.0){let seed = f32(seriesIdx.index * u.pointCount + i);let rPos = hash2(vec2f(seed * 0.1,1.7));let rVel = hash2(vec2f(seed * 0.1,0.5));let a = rVel.x * 6.28318;let spd = 0.002 + rVel.y * 0.003;boidsState[i] = BoidState(vec2f(rPos.x,rPos.y),vec2f(cos(a)* spd,sin(a)* spd),seriesIdx.index,0u);}}`;
|
|
46
|
+
var BOIDS_CLEAR_SHADER = `${GRID_HELPERS}@group(0)@binding(0)var<storage,read_write> gridCount: array<atomic<u32>>;@compute @workgroup_size(${GRID_W * GRID_H})fn main(@builtin(global_invocation_id)id: vec3u){atomicStore(&gridCount[id.x],0u);}`;
|
|
47
|
+
var BOIDS_INSERT_SHADER = `${UNIFORM_STRUCT}${BOID_STATE}${GRID_HELPERS}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> boidsState: array<BoidState>;@group(0)@binding(2)var<storage,read_write> gridCount: array<atomic<u32>>;@group(0)@binding(3)var<storage,read_write> gridBoids: array<u32>;@compute @workgroup_size(${COMPUTE_WG})fn main(@builtin(global_invocation_id)id: vec3u){let i = id.x;if(i >= u.pointCount){return;}let gp = gridParams(u.viewMinX,u.viewMaxX,u.viewMinY,u.viewMaxY);let gc = boidToCell(boidsState[i].pos,gp);let cell = u32(gc.y * i32(GRID_W)+ gc.x);let slot = atomicAdd(&gridCount[cell],1u);if(slot < MAX_PER_CELL){gridBoids[cell * MAX_PER_CELL + slot] = i;}}`;
|
|
48
|
+
var BOIDS_SIM_SHADER = `${UNIFORM_STRUCT}${BOID_STATE}${GRID_HELPERS}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read_write> boidsState: array<BoidState>;@group(0)@binding(2)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(3)var<storage,read> gridCount: array<u32>;@group(0)@binding(4)var<storage,read> gridBoids: array<u32>;fn hash2(p: vec2f)-> vec2f{let q = vec2f(dot(p,vec2f(127.1,311.7)),dot(p,vec2f(269.5,183.3)));return fract(sin(q)* 43758.5453);}@compute @workgroup_size(${COMPUTE_WG})fn main(@builtin(global_invocation_id)id: vec3u){let i = id.x;if(i >= u.pointCount){return;}let me = boidsState[i];let viewRange =(u.viewMaxX - u.viewMinX + u.viewMaxY - u.viewMinY)* 0.5;let dynMaxSpd = ${MAX_SPD}* max(viewRange,1.0);let gp = gridParams(u.viewMinX,u.viewMaxX,u.viewMinY,u.viewMaxY);let cellSize = min(gp.x,gp.y);let dynPer = cellSize * 2.0;let dynSep = dynPer * ${SEP_R / PERCEPTION};let perSq = dynPer * dynPer;let sepSq = dynSep * dynSep;var sep = vec2f(0.0);var align = vec2f(0.0);var coh = vec2f(0.0);var sameCnt = 0u;let lookahead = me.pos + me.vel;let gc = boidToCell(me.pos,gp);for(var dy = -${CLOSE_CELLS};dy <= ${CLOSE_CELLS};dy++){for(var dx = -${CLOSE_CELLS};dx <= ${CLOSE_CELLS};dx++){let nx = gc.x + dx;let ny = gc.y + dy;if(nx < 0 || nx >= i32(GRID_W)|| ny < 0 || ny >= i32(GRID_H)){continue;}let cell = u32(ny * i32(GRID_W)+ nx);let cnt = min(gridCount[cell],MAX_PER_CELL);let base = cell * MAX_PER_CELL;for(var s = 0u;s < cnt;s++){let j = gridBoids[base + s];if(j == i){continue;}let o = boidsState[j];let d = o.pos - lookahead;let dSq = dot(d,d);if(dSq < perSq && dSq > 1e-10){sameCnt += 1u;if(dSq < sepSq){sep -= d / dSq;}align += o.vel;coh += o.pos;}}}}var accel = vec2f(0.0);if(sameCnt > 0u){let fc = f32(sameCnt);let sepMag = length(sep);if(sepMag > 1e-9){accel +=(sep / sepMag)* dynMaxSpd * ${W_SEP};}let avgVel = align / fc;let avgSpd = length(avgVel);if(avgSpd > 1e-9){accel +=(avgVel / avgSpd * dynMaxSpd - me.vel)* ${W_ALIGN};}let toCenter = coh / fc - me.pos;let toCenterLen = length(toCenter);if(toCenterLen > 1e-9){accel +=(toCenter / toCenterLen * dynMaxSpd - me.vel)* ${W_COH};}}let n = hash2(me.pos * 150.0 + vec2f(f32(i)* 0.013,0.0));accel +=(n - 0.5)*(dynMaxSpd * ${W_NOISE});let cx =(u.viewMinX + u.viewMaxX)* 0.5;let cy =(u.viewMinY + u.viewMaxY)* 0.5;let ax =(u.viewMaxX - u.viewMinX)* 0.5 *(1.0 + ${CONTAIN_PAD});let ay =(u.viewMaxY - u.viewMinY)* 0.5 *(1.0 + ${CONTAIN_PAD});let ex =(me.pos.x - cx)/ ax;let ey =(me.pos.y - cy)/ ay;let er = pow(ex*ex*ex*ex + ey*ey*ey*ey,0.25);let edge = max(1.0 - er,1e-4);let bW = dynMaxSpd * ${CONTAIN_STRENGTH};let maxB = dynMaxSpd * 1.5;let fMag = clamp(bW /(edge * edge),0.0,maxB);let gx = ex * ex * ex / ax;let gy = ey * ey * ey / ay;let gLen = max(sqrt(gx*gx + gy*gy),1e-8);accel -= vec2f(gx,gy)/ gLen * fMag;let curLen = length(me.vel);let curDir = select(vec2f(1.0,0.0),me.vel / curLen,curLen > 1e-12);let desired = me.vel + accel;let desLen = length(desired);let desDir = select(curDir,desired / desLen,desLen > 1e-12);let vel = normalize(mix(curDir,desDir,${TURN_RATE}))* dynMaxSpd;boidsState[i] = BoidState(me.pos + vel,vel,me.species,0u);}`;
|
|
49
|
+
var BOIDS_RENDER_SHADER = `${UNIFORM_STRUCT}${BOID_STATE}struct BoidUniforms{radius: f32,_p0: u32,_p1: u32,_p2: u32}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> boidsState: array<BoidState>;@group(0)@binding(2)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(3)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(4)var<uniform> bu: BoidUniforms;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)uv: vec2f,@location(1)color: vec4f}@vertex fn vs(@builtin(vertex_index)vi: u32)-> VertexOutput{var out: VertexOutput;out.uv = vec2f(0.0);out.color = vec4f(0.0);out.pos = vec4f(0.0,0.0,2.0,1.0);let boidIdx = vi / 6u;if(boidIdx >= u.pointCount){return out;}let vtxInQuad = vi % 6u;let b = boidsState[boidIdx];let series = allSeries[seriesIdx.index];let rx = u.viewMaxX - u.viewMinX;let ry = u.viewMaxY - u.viewMinY;if(rx < 1e-5 || ry < 1e-5){return out;}let normX =(b.pos.x - u.viewMinX)/ rx;let normY =(b.pos.y - u.viewMinY)/ ry;let clipX = normX * 2.0 - 1.0;let clipY = normY * 2.0 - 1.0;let zoomScale = clamp(pow(1.0 / min(max(rx,1e-5),max(ry,1e-5)),0.5),0.25,12.0);let r = max(3.0,bu.radius * zoomScale);var corners = array<vec2f,6>(vec2f(-r,r),vec2f(r,r),vec2f(-r,-r),vec2f(-r,-r),vec2f(r,r),vec2f(r,-r));let p = corners[vtxInQuad];out.pos = vec4f(clipX + p.x * 2.0 / u.width,clipY + p.y * 2.0 / u.height,0.0,1.0);out.uv = p;out.color = series.color;return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{let rx = u.viewMaxX - u.viewMinX;let ry = u.viewMaxY - u.viewMinY;let zoomScale = clamp(pow(1.0 / min(max(rx,1e-5),max(ry,1e-5)),0.5),0.25,12.0);let r = max(3.0,bu.radius * zoomScale);let d = length(in.uv);if(d > r){discard;}let alpha = 1.0 - smoothstep(r * 0.85,r,d);let ringT = smoothstep(r * 0.60,r * 0.88,d);let darkCol = in.color.rgb * 0.40;let col = mix(in.color.rgb,darkCol,ringT * 0.55);return vec4f(col,alpha);}`;
|
|
50
|
+
|
|
51
|
+
// src/charts/boids.ts
|
|
52
|
+
var BOID_BYTES = 24;
|
|
53
|
+
var boidsAnimMap = new WeakMap;
|
|
54
|
+
var BoidsChart = {
|
|
55
|
+
name: "boids",
|
|
56
|
+
shaders: {
|
|
57
|
+
init: BOIDS_INIT_SHADER,
|
|
58
|
+
clear: BOIDS_CLEAR_SHADER,
|
|
59
|
+
insert: BOIDS_INSERT_SHADER,
|
|
60
|
+
sim: BOIDS_SIM_SHADER,
|
|
61
|
+
render: BOIDS_RENDER_SHADER
|
|
62
|
+
},
|
|
63
|
+
uniforms: [{ name: "radius", type: "f32", default: 6 }],
|
|
64
|
+
buffers: [
|
|
65
|
+
{
|
|
66
|
+
name: "boidsState",
|
|
67
|
+
bytes: ({ samples }) => Math.max(16, samples * BOID_BYTES),
|
|
68
|
+
usages: ["STORAGE"]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "gridCount",
|
|
72
|
+
bytes: () => GRID_W * GRID_H * 4,
|
|
73
|
+
usages: ["STORAGE"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "gridBoids",
|
|
77
|
+
bytes: () => GRID_W * GRID_H * MAX_PER_CELL * 4,
|
|
78
|
+
usages: ["STORAGE"]
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
passes: [
|
|
82
|
+
{
|
|
83
|
+
type: "compute",
|
|
84
|
+
shader: "init",
|
|
85
|
+
perSeries: true,
|
|
86
|
+
dispatch: ({ samples }) => ({ x: Math.ceil(samples / COMPUTE_WG) }),
|
|
87
|
+
bindings: [
|
|
88
|
+
{ binding: 0, source: "uniforms" },
|
|
89
|
+
{ binding: 1, source: "x-data" },
|
|
90
|
+
{ binding: 2, source: "y-data" },
|
|
91
|
+
{ binding: 3, source: "boidsState", write: true },
|
|
92
|
+
{ binding: 4, source: "series-index" }
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
type: "compute",
|
|
97
|
+
shader: "clear",
|
|
98
|
+
perSeries: true,
|
|
99
|
+
dispatch: () => ({ x: 1 }),
|
|
100
|
+
bindings: [{ binding: 0, source: "gridCount", write: true }]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: "compute",
|
|
104
|
+
shader: "insert",
|
|
105
|
+
perSeries: true,
|
|
106
|
+
dispatch: ({ samples }) => ({ x: Math.ceil(samples / COMPUTE_WG) }),
|
|
107
|
+
bindings: [
|
|
108
|
+
{ binding: 0, source: "uniforms" },
|
|
109
|
+
{ binding: 1, source: "boidsState" },
|
|
110
|
+
{ binding: 2, source: "gridCount", write: true },
|
|
111
|
+
{ binding: 3, source: "gridBoids", write: true }
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: "compute",
|
|
116
|
+
shader: "sim",
|
|
117
|
+
perSeries: true,
|
|
118
|
+
dispatch: ({ samples }) => ({ x: Math.ceil(samples / COMPUTE_WG) }),
|
|
119
|
+
bindings: [
|
|
120
|
+
{ binding: 0, source: "uniforms" },
|
|
121
|
+
{ binding: 1, source: "boidsState", write: true },
|
|
122
|
+
{ binding: 2, source: "series-index" },
|
|
123
|
+
{ binding: 3, source: "gridCount" },
|
|
124
|
+
{ binding: 4, source: "gridBoids" }
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: "render",
|
|
129
|
+
shader: "render",
|
|
130
|
+
topology: "triangle-list",
|
|
131
|
+
loadOp: "load",
|
|
132
|
+
perSeries: true,
|
|
133
|
+
blend: {
|
|
134
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha" },
|
|
135
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }
|
|
136
|
+
},
|
|
137
|
+
draw: ({ samples }) => samples * 6,
|
|
138
|
+
bindings: [
|
|
139
|
+
{ binding: 0, source: "uniforms" },
|
|
140
|
+
{ binding: 1, source: "boidsState" },
|
|
141
|
+
{ binding: 2, source: "series-info" },
|
|
142
|
+
{ binding: 3, source: "series-index" },
|
|
143
|
+
{ binding: 4, source: "custom-uniforms" }
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
computeBounds() {
|
|
148
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
149
|
+
},
|
|
150
|
+
install(chart, _el) {
|
|
151
|
+
const tick = () => {
|
|
152
|
+
ChartManager.requestRender(chart.id);
|
|
153
|
+
boidsAnimMap.set(chart, requestAnimationFrame(tick));
|
|
154
|
+
};
|
|
155
|
+
boidsAnimMap.set(chart, requestAnimationFrame(tick));
|
|
156
|
+
},
|
|
157
|
+
uninstall(chart) {
|
|
158
|
+
const id = boidsAnimMap.get(chart);
|
|
159
|
+
if (id != null) {
|
|
160
|
+
cancelAnimationFrame(id);
|
|
161
|
+
boidsAnimMap.delete(chart);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
export {
|
|
166
|
+
BoidsChart
|
|
167
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{f as j,g as v}from"../chunk-64q9a7nw.js";import{q as F}from"../chunk-50bcv2hw.js";import"../chunk-wdfq2fpx.js";import"../chunk-bbyt23tw.js";var K="struct BoidState { pos: vec2f, vel: vec2f, species: u32, _pad: u32 }",q=0.2,o=q*0.2,b=0.003,n=0.7,B=0.15,l=0.02,H=0.001,W=0.2,c=0.003,J=0.1,z=1,w=16,x=16,Z=16,$=`
|
|
2
|
+
const GRID_W = ${w}u;
|
|
3
|
+
const GRID_H = ${x}u;
|
|
4
|
+
const MAX_PER_CELL = ${Z}u;
|
|
5
|
+
// Returns (cellX, cellY, gridMinX, gridMinY) sized to cover the padded view.
|
|
6
|
+
fn gridParams(vMinX: f32, vMaxX: f32, vMinY: f32, vMaxY: f32) -> vec4f {
|
|
7
|
+
let cX = (vMaxX - vMinX) * ${1+J}f / f32(GRID_W);
|
|
8
|
+
let cY = (vMaxY - vMinY) * ${1+J}f / f32(GRID_H);
|
|
9
|
+
return vec4f(cX, cY,
|
|
10
|
+
(vMinX + vMaxX) * 0.5 - cX * f32(GRID_W) * 0.5,
|
|
11
|
+
(vMinY + vMaxY) * 0.5 - cY * f32(GRID_H) * 0.5);
|
|
12
|
+
}
|
|
13
|
+
fn boidToCell(pos: vec2f, gp: vec4f) -> vec2i {
|
|
14
|
+
return clamp(
|
|
15
|
+
vec2i(i32((pos.x - gp.z) / gp.x), i32((pos.y - gp.w) / gp.y)),
|
|
16
|
+
vec2i(0, 0), vec2i(i32(GRID_W) - 1, i32(GRID_H) - 1)
|
|
17
|
+
);
|
|
18
|
+
}`,u=`${v}${K}@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> boidsState: array<BoidState>;@group(0)@binding(4)var<uniform> seriesIdx: SeriesIndex;fn hash2(p: vec2f)-> vec2f{let q = vec2f(dot(p,vec2f(127.1,311.7)),dot(p,vec2f(269.5,183.3)));return fract(sin(q)* 43758.5453);}@compute @workgroup_size(${j})fn main(@builtin(global_invocation_id)id: vec3u){let i = id.x;if(i >= u.pointCount){return;}let b = boidsState[i];if(b.vel.x == 0.0 && b.vel.y == 0.0){let seed = f32(seriesIdx.index * u.pointCount + i);let rPos = hash2(vec2f(seed * 0.1,1.7));let rVel = hash2(vec2f(seed * 0.1,0.5));let a = rVel.x * 6.28318;let spd = 0.002 + rVel.y * 0.003;boidsState[i] = BoidState(vec2f(rPos.x,rPos.y),vec2f(cos(a)* spd,sin(a)* spd),seriesIdx.index,0u);}}`,y=`${$}@group(0)@binding(0)var<storage,read_write> gridCount: array<atomic<u32>>;@compute @workgroup_size(${w*x})fn main(@builtin(global_invocation_id)id: vec3u){atomicStore(&gridCount[id.x],0u);}`,Y=`${v}${K}${$}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> boidsState: array<BoidState>;@group(0)@binding(2)var<storage,read_write> gridCount: array<atomic<u32>>;@group(0)@binding(3)var<storage,read_write> gridBoids: array<u32>;@compute @workgroup_size(${j})fn main(@builtin(global_invocation_id)id: vec3u){let i = id.x;if(i >= u.pointCount){return;}let gp = gridParams(u.viewMinX,u.viewMaxX,u.viewMinY,u.viewMaxY);let gc = boidToCell(boidsState[i].pos,gp);let cell = u32(gc.y * i32(GRID_W)+ gc.x);let slot = atomicAdd(&gridCount[cell],1u);if(slot < MAX_PER_CELL){gridBoids[cell * MAX_PER_CELL + slot] = i;}}`,k=`${v}${K}${$}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read_write> boidsState: array<BoidState>;@group(0)@binding(2)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(3)var<storage,read> gridCount: array<u32>;@group(0)@binding(4)var<storage,read> gridBoids: array<u32>;fn hash2(p: vec2f)-> vec2f{let q = vec2f(dot(p,vec2f(127.1,311.7)),dot(p,vec2f(269.5,183.3)));return fract(sin(q)* 43758.5453);}@compute @workgroup_size(${j})fn main(@builtin(global_invocation_id)id: vec3u){let i = id.x;if(i >= u.pointCount){return;}let me = boidsState[i];let viewRange =(u.viewMaxX - u.viewMinX + u.viewMaxY - u.viewMinY)* 0.5;let dynMaxSpd = ${b}* max(viewRange,1.0);let gp = gridParams(u.viewMinX,u.viewMaxX,u.viewMinY,u.viewMaxY);let cellSize = min(gp.x,gp.y);let dynPer = cellSize * 2.0;let dynSep = dynPer * ${o/q};let perSq = dynPer * dynPer;let sepSq = dynSep * dynSep;var sep = vec2f(0.0);var align = vec2f(0.0);var coh = vec2f(0.0);var sameCnt = 0u;let lookahead = me.pos + me.vel;let gc = boidToCell(me.pos,gp);for(var dy = -${z};dy <= ${z};dy++){for(var dx = -${z};dx <= ${z};dx++){let nx = gc.x + dx;let ny = gc.y + dy;if(nx < 0 || nx >= i32(GRID_W)|| ny < 0 || ny >= i32(GRID_H)){continue;}let cell = u32(ny * i32(GRID_W)+ nx);let cnt = min(gridCount[cell],MAX_PER_CELL);let base = cell * MAX_PER_CELL;for(var s = 0u;s < cnt;s++){let j = gridBoids[base + s];if(j == i){continue;}let o = boidsState[j];let d = o.pos - lookahead;let dSq = dot(d,d);if(dSq < perSq && dSq > 1e-10){sameCnt += 1u;if(dSq < sepSq){sep -= d / dSq;}align += o.vel;coh += o.pos;}}}}var accel = vec2f(0.0);if(sameCnt > 0u){let fc = f32(sameCnt);let sepMag = length(sep);if(sepMag > 1e-9){accel +=(sep / sepMag)* dynMaxSpd * ${B};}let avgVel = align / fc;let avgSpd = length(avgVel);if(avgSpd > 1e-9){accel +=(avgVel / avgSpd * dynMaxSpd - me.vel)* ${l};}let toCenter = coh / fc - me.pos;let toCenterLen = length(toCenter);if(toCenterLen > 1e-9){accel +=(toCenter / toCenterLen * dynMaxSpd - me.vel)* ${H};}}let n = hash2(me.pos * 150.0 + vec2f(f32(i)* 0.013,0.0));accel +=(n - 0.5)*(dynMaxSpd * ${W});let cx =(u.viewMinX + u.viewMaxX)* 0.5;let cy =(u.viewMinY + u.viewMaxY)* 0.5;let ax =(u.viewMaxX - u.viewMinX)* 0.5 *(1.0 + ${J});let ay =(u.viewMaxY - u.viewMinY)* 0.5 *(1.0 + ${J});let ex =(me.pos.x - cx)/ ax;let ey =(me.pos.y - cy)/ ay;let er = pow(ex*ex*ex*ex + ey*ey*ey*ey,0.25);let edge = max(1.0 - er,1e-4);let bW = dynMaxSpd * ${c};let maxB = dynMaxSpd * 1.5;let fMag = clamp(bW /(edge * edge),0.0,maxB);let gx = ex * ex * ex / ax;let gy = ey * ey * ey / ay;let gLen = max(sqrt(gx*gx + gy*gy),1e-8);accel -= vec2f(gx,gy)/ gLen * fMag;let curLen = length(me.vel);let curDir = select(vec2f(1.0,0.0),me.vel / curLen,curLen > 1e-12);let desired = me.vel + accel;let desLen = length(desired);let desDir = select(curDir,desired / desLen,desLen > 1e-12);let vel = normalize(mix(curDir,desDir,${n}))* dynMaxSpd;boidsState[i] = BoidState(me.pos + vel,vel,me.species,0u);}`,X=`${v}${K}struct BoidUniforms{radius: f32,_p0: u32,_p1: u32,_p2: u32}@group(0)@binding(0)var<uniform> u: Uniforms;@group(0)@binding(1)var<storage,read> boidsState: array<BoidState>;@group(0)@binding(2)var<storage,read> allSeries: array<SeriesInfo>;@group(0)@binding(3)var<uniform> seriesIdx: SeriesIndex;@group(0)@binding(4)var<uniform> bu: BoidUniforms;struct VertexOutput{@builtin(position)pos: vec4f,@location(0)uv: vec2f,@location(1)color: vec4f}@vertex fn vs(@builtin(vertex_index)vi: u32)-> VertexOutput{var out: VertexOutput;out.uv = vec2f(0.0);out.color = vec4f(0.0);out.pos = vec4f(0.0,0.0,2.0,1.0);let boidIdx = vi / 6u;if(boidIdx >= u.pointCount){return out;}let vtxInQuad = vi % 6u;let b = boidsState[boidIdx];let series = allSeries[seriesIdx.index];let rx = u.viewMaxX - u.viewMinX;let ry = u.viewMaxY - u.viewMinY;if(rx < 1e-5 || ry < 1e-5){return out;}let normX =(b.pos.x - u.viewMinX)/ rx;let normY =(b.pos.y - u.viewMinY)/ ry;let clipX = normX * 2.0 - 1.0;let clipY = normY * 2.0 - 1.0;let zoomScale = clamp(pow(1.0 / min(max(rx,1e-5),max(ry,1e-5)),0.5),0.25,12.0);let r = max(3.0,bu.radius * zoomScale);var corners = array<vec2f,6>(vec2f(-r,r),vec2f(r,r),vec2f(-r,-r),vec2f(-r,-r),vec2f(r,r),vec2f(r,-r));let p = corners[vtxInQuad];out.pos = vec4f(clipX + p.x * 2.0 / u.width,clipY + p.y * 2.0 / u.height,0.0,1.0);out.uv = p;out.color = series.color;return out;}@fragment fn fs(in: VertexOutput)-> @location(0)vec4f{let rx = u.viewMaxX - u.viewMinX;let ry = u.viewMaxY - u.viewMinY;let zoomScale = clamp(pow(1.0 / min(max(rx,1e-5),max(ry,1e-5)),0.5),0.25,12.0);let r = max(3.0,bu.radius * zoomScale);let d = length(in.uv);if(d > r){discard;}let alpha = 1.0 - smoothstep(r * 0.85,r,d);let ringT = smoothstep(r * 0.60,r * 0.88,d);let darkCol = in.color.rgb * 0.40;let col = mix(in.color.rgb,darkCol,ringT * 0.55);return vec4f(col,alpha);}`;var d=24,Q=new WeakMap,t={name:"boids",shaders:{init:u,clear:y,insert:Y,sim:k,render:X},uniforms:[{name:"radius",type:"f32",default:6}],buffers:[{name:"boidsState",bytes:({samples:f})=>Math.max(16,f*d),usages:["STORAGE"]},{name:"gridCount",bytes:()=>w*x*4,usages:["STORAGE"]},{name:"gridBoids",bytes:()=>w*x*Z*4,usages:["STORAGE"]}],passes:[{type:"compute",shader:"init",perSeries:!0,dispatch:({samples:f})=>({x:Math.ceil(f/j)}),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"x-data"},{binding:2,source:"y-data"},{binding:3,source:"boidsState",write:!0},{binding:4,source:"series-index"}]},{type:"compute",shader:"clear",perSeries:!0,dispatch:()=>({x:1}),bindings:[{binding:0,source:"gridCount",write:!0}]},{type:"compute",shader:"insert",perSeries:!0,dispatch:({samples:f})=>({x:Math.ceil(f/j)}),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"boidsState"},{binding:2,source:"gridCount",write:!0},{binding:3,source:"gridBoids",write:!0}]},{type:"compute",shader:"sim",perSeries:!0,dispatch:({samples:f})=>({x:Math.ceil(f/j)}),bindings:[{binding:0,source:"uniforms"},{binding:1,source:"boidsState",write:!0},{binding:2,source:"series-index"},{binding:3,source:"gridCount"},{binding:4,source:"gridBoids"}]},{type:"render",shader:"render",topology:"triangle-list",loadOp:"load",perSeries:!0,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha"}},draw:({samples:f})=>f*6,bindings:[{binding:0,source:"uniforms"},{binding:1,source:"boidsState"},{binding:2,source:"series-info"},{binding:3,source:"series-index"},{binding:4,source:"custom-uniforms"}]}],computeBounds(){return{minX:0,maxX:1,minY:0,maxY:1}},install(f,V){let g=()=>{F.requestRender(f.id),Q.set(f,requestAnimationFrame(g))};Q.set(f,requestAnimationFrame(g))},uninstall(f){let V=Q.get(f);if(V!=null)cancelAnimationFrame(V),Q.delete(f)}};export{t as BoidsChart};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RendererPlugin } from "../types.ts";
|
|
2
|
+
export interface CandlestickConfig {
|
|
3
|
+
upColor?: [number, number, number];
|
|
4
|
+
downColor?: [number, number, number];
|
|
5
|
+
maxSamples?: number;
|
|
6
|
+
/** Target candle width in screen pixels, used by auto-interval selection.
|
|
7
|
+
* The smallest standard timeframe that gives candles at least this wide is chosen.
|
|
8
|
+
* Defaults to 8. Ignored when `interval` is set explicitly. */
|
|
9
|
+
binSize?: number;
|
|
10
|
+
/** Fixed grouping interval in X-axis units (e.g. seconds for time series).
|
|
11
|
+
* Set to 0 (default) to auto-select from standard timeframes based on zoom. */
|
|
12
|
+
interval?: number;
|
|
13
|
+
}
|
|
14
|
+
declare module "../types.ts" {
|
|
15
|
+
interface ChartTypeRegistry {
|
|
16
|
+
candlestick: CandlestickConfig;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export declare const packRGB: (r: number, g: number, b: number) => number;
|
|
20
|
+
export declare const CandlestickChart: RendererPlugin;
|
|
21
|
+
//# sourceMappingURL=candlestick.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candlestick.d.ts","sourceRoot":"","sources":["../../src/charts/candlestick.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,EAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;oEAEgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;oFACgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,iBAAiB;QACzB,WAAW,EAAE,iBAAiB,CAAC;KAChC;CACF;AAED,eAAO,MAAM,OAAO,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAIpC,CAAC;AAKvB,eAAO,MAAM,gBAAgB,EAAE,cAyE9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as a,c as b}from"../chunk-g2qmt43n.js";import"../chunk-64q9a7nw.js";import"../chunk-bbyt23tw.js";export{a as packRGB,b as CandlestickChart};
|