chartai 0.0.11 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/chart-library.d.ts +33 -146
  2. package/dist/chart-library.d.ts.map +1 -1
  3. package/dist/chart-library.js +378 -321
  4. package/dist/chart-library.min.js +1 -1
  5. package/dist/charts/area.d.ts +6 -0
  6. package/dist/charts/area.d.ts.map +1 -0
  7. package/dist/charts/area.js +65 -0
  8. package/dist/charts/area.min.js +1 -0
  9. package/dist/charts/bar.d.ts +11 -0
  10. package/dist/charts/bar.d.ts.map +1 -0
  11. package/dist/charts/bar.js +65 -0
  12. package/dist/charts/bar.min.js +1 -0
  13. package/dist/charts/boids.js +167 -0
  14. package/dist/charts/boids.min.js +18 -0
  15. package/dist/charts/candlestick.d.ts +21 -0
  16. package/dist/charts/candlestick.d.ts.map +1 -0
  17. package/dist/charts/candlestick.js +132 -0
  18. package/dist/charts/candlestick.min.js +32 -0
  19. package/dist/charts/line.d.ts +12 -0
  20. package/dist/charts/line.d.ts.map +1 -0
  21. package/dist/charts/line.js +62 -0
  22. package/dist/charts/line.min.js +1 -0
  23. package/dist/charts/scatter.d.ts +11 -0
  24. package/dist/charts/scatter.d.ts.map +1 -0
  25. package/dist/charts/scatter.js +46 -0
  26. package/dist/charts/scatter.min.js +1 -0
  27. package/dist/chunk-0jepamv9.js +7 -0
  28. package/dist/chunk-1p45ex5n.min.js +2 -0
  29. package/dist/chunk-831dem4f.js +4 -0
  30. package/dist/chunk-93yrr7er.js +35 -0
  31. package/dist/chunk-94kc81rr.min.js +2 -0
  32. package/dist/chunk-a27be8p9.js +105 -0
  33. package/dist/chunk-bfyv7z27.min.js +2 -0
  34. package/dist/chunk-dmaxrg6s.min.js +2 -0
  35. package/dist/chunk-e7d3zgw5.min.js +2 -0
  36. package/dist/chunk-g6m56ptf.js +609 -0
  37. package/dist/chunk-m17t3vjq.js +9 -0
  38. package/dist/chunk-me3qaz3m.min.js +2 -0
  39. package/dist/chunk-qr6mweck.min.js +2 -0
  40. package/dist/chunk-yabjrff2.js +11 -0
  41. package/dist/gpu-worker.js +625 -686
  42. package/dist/gpu-worker.min.js +1 -1
  43. package/dist/msg.d.ts +33 -0
  44. package/dist/msg.d.ts.map +1 -0
  45. package/dist/plugins/coords.d.ts +18 -0
  46. package/dist/plugins/coords.d.ts.map +1 -0
  47. package/dist/plugins/hover.d.ts +15 -2
  48. package/dist/plugins/hover.d.ts.map +1 -1
  49. package/dist/plugins/hover.js +103 -16
  50. package/dist/plugins/hover.min.js +1 -1
  51. package/dist/plugins/labels-panel.d.ts +4 -0
  52. package/dist/plugins/labels-panel.d.ts.map +1 -0
  53. package/dist/plugins/labels-panel.js +122 -0
  54. package/dist/plugins/labels-panel.min.js +1 -0
  55. package/dist/plugins/labels.d.ts +17 -2
  56. package/dist/plugins/labels.d.ts.map +1 -1
  57. package/dist/plugins/labels.js +11 -99
  58. package/dist/plugins/labels.min.js +1 -1
  59. package/dist/plugins/legend.d.ts +16 -0
  60. package/dist/plugins/legend.d.ts.map +1 -0
  61. package/dist/plugins/legend.js +282 -0
  62. package/dist/plugins/legend.min.js +21 -0
  63. package/dist/plugins/shared.d.ts +7 -0
  64. package/dist/plugins/shared.d.ts.map +1 -0
  65. package/dist/plugins/zoom.d.ts +10 -2
  66. package/dist/plugins/zoom.d.ts.map +1 -1
  67. package/dist/plugins/zoom.js +227 -97
  68. package/dist/plugins/zoom.min.js +1 -1
  69. package/dist/types.d.ts +179 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +0 -0
  72. package/dist/types.min.js +0 -0
  73. package/dist/worker-inline.d.ts +1 -1
  74. package/dist/worker-inline.d.ts.map +1 -1
  75. package/package.json +13 -12
  76. package/readme.md +51 -42
  77. package/dist/chunk-bgfkgcmg.js +0 -25
  78. package/dist/chunk-cj3zanvs.min.js +0 -2
@@ -1,2 +1,2 @@
1
- export declare const WORKER_CODE = "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";
1
+ export declare const WORKER_CODE = "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)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)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,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;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";
2
2
  //# sourceMappingURL=worker-inline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker-inline.d.ts","sourceRoot":"","sources":["../src/worker-inline.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,8n5BAA8n5B,CAAC"}
1
+ {"version":3,"file":"worker-inline.d.ts","sourceRoot":"","sources":["../src/worker-inline.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,8ueAA8ue,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chartai",
3
- "version": "0.0.11",
3
+ "version": "1.0.0",
4
4
  "description": "tiny gpu powered charts",
5
5
  "type": "module",
6
6
  "main": "./dist/chart-library.js",
@@ -11,21 +11,21 @@
11
11
  "types": "./dist/chart-library.d.ts",
12
12
  "default": "./dist/chart-library.js"
13
13
  },
14
+ "./types": {
15
+ "types": "./dist/types.d.ts",
16
+ "default": "./dist/types.js"
17
+ },
14
18
  "./worker": {
15
19
  "types": "./dist/gpu-worker.d.ts",
16
20
  "default": "./dist/gpu-worker.js"
17
21
  },
18
- "./plugins/hover": {
19
- "types": "./dist/plugins/hover.d.ts",
20
- "default": "./dist/plugins/hover.js"
21
- },
22
- "./plugins/labels": {
23
- "types": "./dist/plugins/labels.d.ts",
24
- "default": "./dist/plugins/labels.js"
22
+ "./plugins/*": {
23
+ "types": "./dist/plugins/*.d.ts",
24
+ "default": "./dist/plugins/*.js"
25
25
  },
26
- "./plugins/zoom": {
27
- "types": "./dist/plugins/zoom.d.ts",
28
- "default": "./dist/plugins/zoom.js"
26
+ "./charts/*": {
27
+ "types": "./dist/charts/*.d.ts",
28
+ "default": "./dist/charts/*.js"
29
29
  }
30
30
  },
31
31
  "files": [
@@ -74,5 +74,6 @@
74
74
  },
75
75
  "engines": {
76
76
  "node": ">=18.0.0"
77
- }
77
+ },
78
+ "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
78
79
  }
package/readme.md CHANGED
@@ -1,41 +1,45 @@
1
- # ChartAI
1
+ # chartai
2
2
 
3
- Are you looking for a simple tiny little chart library which can draw as many lines and points across as many charts as you have vram? Look no further.
3
+ Are you looking for a simple tiny little chart library which can draw as many lines and points as you have vram? Look no further.
4
4
 
5
- ChartAI is an ai powered chart library which can draw millions and millions of lines across hundreds at 60fps. But like good engineers we only draw when we need to saving battery life.
5
+ chartai is a library that can draw millions and millions of lines across thousands of series wickedly fast. It uses a passive rendering system that only update charts when needed. It lives in a web worker keeping the main thread free. It is fully pluggable so you only take way you need or add what's missing.
6
6
 
7
7
  * **[Examples](https://dgerrells.github.io/chartai/)**
8
8
  * **[Playground](https://dgerrells.github.io/chartai/demo/)**
9
- * **[Real data canvas demo](https://dgerrells.github.io/chartai/canvas/)**
9
+ * **[Silly overly complicated demo](https://dgerrells.github.io/chartai/canvas/)**
10
10
 
11
- Why ChartAI?
11
+ ## Why chartai?
12
12
 
13
- * Tiny, unlimited charts at ~11kb, plugins make it ~15kb
13
+ This library was inspired by uplot which is likely all you need. But if you do need the performance without the bundle bloat, this may do it.
14
+
15
+ * Tiny, unlimited line charts at ~11kb
14
16
  * Customizable with plugins
15
- * Lines, scatter, and bars
17
+ * Lines, scatter, bar, adn candlestick out of the box
16
18
  * Chart synchronization
17
19
  * Stupid faster compute shaders
18
20
  * Passively rendered, automatic virtualization
19
21
  * Doesn't miss the spikes in data, unless you want it to
20
- * Simple api
21
22
 
22
- ### Add a line chart.
23
+ Cool. How do I use it?
24
+
25
+ ### Add a line chart
23
26
 
24
27
  ```js
25
28
  import { ChartManager } from 'chartai';
29
+ import { LineChart } from 'chartai/charts/line';
26
30
 
27
- const manager = ChartManager.getInstance();
28
- await manager.init();
31
+ ChartManager.use(LineChart);
32
+ await ChartManager.init();
29
33
 
30
34
  const x = Array.from({ length: 100 }, (_, i) => i);
31
35
  const y = x.map(v => Math.sin(v * 0.1) * 50 + 50);
32
36
 
33
- const chartId = manager.create({
37
+ const chart = ChartManager.create({
34
38
  type: 'line',
35
39
  container: document.getElementById('chart'),
36
40
  series: [{
37
41
  label: 'My Data',
38
- color: { r: 0.4, g: 0.6, b: 1 },
42
+ color: 'oklab(0.65 0.15 -0.2)',
39
43
  x,
40
44
  y
41
45
  }],
@@ -45,52 +49,53 @@ const chartId = manager.create({
45
49
  ### Plugins
46
50
 
47
51
  ```js
48
- import { ChartManager, registerPlugin } from 'chartai';
49
- import { zoomPlugin } from 'chartai/plugins/zoom';
52
+ import { ChartManager } from 'chartai';
53
+ import { labelsPlugin } from 'chartai/plugins/labels';
50
54
  import { hoverPlugin } from 'chartai/plugins/hover';
51
55
 
52
- registerPlugin(zoomPlugin());
53
- registerPlugin(hoverPlugin);
56
+ ChartManager.use(zoomPlugin);
57
+ ChartManager.use(hoverPlugin);
54
58
  ```
55
59
 
56
- ### React weirdos
60
+ ### Agnostic
61
+
62
+ It is pure js. Add it to your favorite framework.
57
63
 
58
64
  ```js
59
65
  import { useEffect, useRef } from 'react';
60
- import { ChartManager, registerPlugin } from 'chartai';
66
+ import { ChartManager } from 'chartai';
67
+ import { LineChart } from 'chartai/charts/line';
61
68
  import { zoomPlugin } from 'chartai/plugins/zoom';
62
69
  import { hoverPlugin } from 'chartai/plugins/hover';
63
70
  import { labelsPlugin } from 'chartai/plugins/labels';
64
71
 
65
72
  function Chart() {
66
73
  const ref = useRef(null);
67
- const chartIdRef = useRef(null);
74
+ const chartRef = useRef(null);
68
75
 
69
76
  useEffect(() => {
70
- registerPlugin(labelsPlugin);
71
- registerPlugin(zoomPlugin());
72
- registerPlugin(hoverPlugin);
77
+ ChartManager.use(LineChart);
78
+ ChartManager.use(labelsPlugin);
79
+ ChartManager.use(zoomPlugin());
80
+ ChartManager.use(hoverPlugin);
73
81
 
74
- const manager = ChartManager.getInstance();
75
- manager.init().then(() => {
82
+ ChartManager.init().then(() => {
76
83
  const x = Array.from({ length: 100 }, (_, i) => i);
77
84
  const y = x.map(v => Math.sin(v * 0.1) * 50 + 50);
78
85
 
79
- chartIdRef.current = manager.create({
86
+ chartRef.current = ChartManager.create({
80
87
  type: 'line',
81
88
  container: ref.current,
82
- series: [{ label: 'My Data', color: { r: 0.4, g: 0.6, b: 1 }, x, y }],
89
+ series: [{ label: 'My Data', color: '#ffffff', x, y }],
83
90
  zoomMode: 'both',
84
91
  showTooltip: true
85
92
  });
86
93
 
87
- manager.setZoomMode(chartIdRef.current, 'x-only');
94
+ chartRef.current.configure({ zoomMode: 'x-only' });
88
95
  });
89
96
 
90
97
  return () => {
91
- if (chartIdRef.current) {
92
- manager.destroy(chartIdRef.current);
93
- }
98
+ chartRef.current?.destroy();
94
99
  };
95
100
  }, []);
96
101
 
@@ -100,16 +105,20 @@ function Chart() {
100
105
 
101
106
  ## Design
102
107
 
103
- I need to draw lots of lines, points, boxes whatever on multiple (2o+) charts where the view port is synchronized. The solution is to have a web worker generating frames via compute shaders. This allows for almost unlimited charts. As many as you can fit on the screen. Data scale depends on hardware but an m1 can push it at 60fps until ram runs out.
108
+ A little layer communicates with a web worker that does all the web gpu rendering. The design is pretty simple. Everything is a plugin. Both charts and well, plugins. The best way to see how to write your own plugins and charts is to look at the ones that exist.
109
+
110
+ Yes, you can point an agent at the examples and it will understand it.
111
+
112
+ To demonstrate just how well it works there is a boids simulation chart where the chart data functions as starting locations for the boids. It is totally overkill and ridiculous and silly. It does show how powerful the framework is.
113
+
114
+ ## Gotchas
115
+
116
+ * WebGPU - this uses it so if it isn't there it will not work. No fallback is provided as the intent is for this library to be tiny and lean.
117
+ * Appending data - Updating data is plenty fast even with larger datasets but it could be smarter. It doesn't support having a larger buffer size and only sending updated data. It is a full update internally for now.
118
+ * Workers - The library will try and inline bundle the worker for maximum simplicity. If it fails, it will fallback to standard es worker loading.
119
+
120
+ ### Contribution
104
121
 
105
- ## Gotchas and missing features
122
+ I test using bun which handles most of the bundling out of the box.
106
123
 
107
- * appending or updating is stupid. Full reupload. There are ways you can fast copy on the gpu memory to smartly grow. At small sizes it is still butter.
108
- * Bar charts...i like these and will not change them. They may not fit your jib. Copypasta your own shader, this lib is tiny.
109
- * Webgpu is used. No compute shaders, no charts
110
- * missing line size option. I need to switch up to a post process option (works well and cheap) or use signed distance fields. Many benefits but complex.
111
- * triple layered canvas. The plugins allow for canvas drawing behind and in front of the chart via 2 extra canvases. I hate it. There is a way I think to use a single canvas but I am still trying to figure it out.
112
- * Decimation may not be to your liking.
113
- * Finding the closes data point is a little messy.
114
- * I fucking hate npm publishing so if you like this, best bet is to just copypasta whatever you want. Or point local AI at this repo cook.
115
- * AI help with human review. If you want your code free-range and hormone free, look elsewhere. This works for me.
124
+ You can start a server watching files by running `bun server.ts`.
@@ -1,25 +0,0 @@
1
- var __create = Object.create;
2
- var __getProtoOf = Object.getPrototypeOf;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __toESM = (mod, isNodeMode, target) => {
7
- target = mod != null ? __create(__getProtoOf(mod)) : {};
8
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
9
- for (let key of __getOwnPropNames(mod))
10
- if (!__hasOwnProp.call(to, key))
11
- __defProp(to, key, {
12
- get: () => mod[key],
13
- enumerable: true
14
- });
15
- return to;
16
- };
17
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
18
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
19
- }) : x)(function(x) {
20
- if (typeof require !== "undefined")
21
- return require.apply(this, arguments);
22
- throw Error('Dynamic require of "' + x + '" is not supported');
23
- });
24
-
25
- export { __toESM, __require };
@@ -1,2 +0,0 @@
1
- var g=Object.create;var{getPrototypeOf:h,defineProperty:f,getOwnPropertyNames:i}=Object;var j=Object.prototype.hasOwnProperty;var k=(a,c,b)=>{b=a!=null?g(h(a)):{};let d=c||!a||!a.__esModule?f(b,"default",{value:a,enumerable:!0}):b;for(let e of i(a))if(!j.call(d,e))f(d,e,{get:()=>a[e],enumerable:!0});return d};var l=((a)=>typeof require!=="undefined"?require:typeof Proxy!=="undefined"?new Proxy(a,{get:(c,b)=>(typeof require!=="undefined"?require:c)[b]}):a)(function(a){if(typeof require!=="undefined")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});
2
- export{k as b,l as c};