[charts-premium] Add WebGL renderer to ScatterChartPremium#22157
[charts-premium] Add WebGL renderer to ScatterChartPremium#22157JCQuintas wants to merge 22 commits intomui:masterfrom
Conversation
Bundle size
Deploy previewCheck out the code infra dashboard for more information about this PR. |
|
Impressive 🎉 While playing with it, I'm wondering if the highlight will be handled in a follow up. For not with no item highlight, it's tricky to know if the tooltip and the rendered item are correct |
Added a small highlight component. It renders in svg since it is a single element, and would allow customisation. Not sure which class to use on it though. Should we create a new one or reuse the focusedMark? 🤔 |
alexfauquette
left a comment
There was a problem hiding this comment.
Verry nice component. I left minor comments but nothing serious about the WebGL. Maybe because I don't have the knowledge to review it. Would be interesting to gt Bernardo point of view on this one
| // Colors and sizes depend only on series identity (series color + markerSize). | ||
| // When only the drawing area or axes change we reuse the cached Float32Array | ||
| // references so the WebGL program can skip the GPU upload for them. |
There was a problem hiding this comment.
Claudio let me notice that this is not exact because of the following lines
const sx = xScale(point.x);
const sy = yScale(point.y);
if (sx == null || sy == null || Number.isNaN(sx) || Number.isNaN(sy)) {
continue;
}If the xAxis scale got modified in a way that sx/sy are not numbers, the point coordinate and colors might be desynchronised between the newly computed and the cached version.
That's fairly unlikely. But worth mentioning at least in the comment
| } | null>(null); | ||
|
|
||
| // Centers change on every zoom/axis update, but the underlying ArrayBuffer | ||
| // can be reused to avoid allocating ~1.6 MB per zoom frame at 200k points. |
There was a problem hiding this comment.
Just to be sure I got correctly how you reached to those number.
A Float32Number takes 4 Bytes. You have x and y you the array size in Bytes is 8 times the number of data points.
So plus the colors that are also 4 Bytes per RGBA component (so 16 in total) and the size which is also adding 4 Bytes, the charts represent a Buffer of (16 + 8 + 4)* 200k = 5.6MB
I'm wondering if the colors and size could benefit from the usage of a Int8Array to save some bytes
|
|
||
| const centersLength = maxPoints * 2; | ||
| let pool = centersPoolRef.current; | ||
| if (pool === null || pool.length < centersLength) { |
There was a problem hiding this comment.
You reuse the buffer if the number of data point increase. What if it decreases? Will we still see last removed points?
| const cx = getXPosition(scatterPoint.x); | ||
| const cy = getYPosition(scatterPoint.y); | ||
| const r = series.markerSize / 2; | ||
|
|
||
| return ( |
There was a problem hiding this comment.
I think for the scatter plot, we check if the mark in inside the drawing area with some margins. That's usefull for keyboard navigation. It prevent from showing highlight outside of the drawing area without having to put this in a clip-path
| * so the highlight has to be drawn in SVG and positioned via the same axis scales the | ||
| * WebGL plot uses. | ||
| */ | ||
| export function HighlightedScatterMark(props: React.SVGAttributes<SVGCircleElement>) { |
There was a problem hiding this comment.
This should be in community since it's also usefull for the svg-batch rendering
| 'x-charts-pro/src/SankeyChart/SankeyNodePlot.tsx', | ||
| 'x-charts-pro/src/SankeyChart/SankeyLinkLabelPlot.tsx', | ||
| 'x-charts-pro/src/SankeyChart/SankeyNodeLabelPlot.tsx', | ||
| 'x-charts-premium/src/ScatterChartPremium/webgl/ScatterWebGLPlot.tsx', |
There was a problem hiding this comment.
It's not planned to use it with composition for now?
| '!docs/data/charts/sankey/CustomNodeLabelPlot', // sub-component for demo purpose | ||
| '!docs/data/charts/references/ReferenceArea', // sub-component for demo purpose | ||
| '!docs/data/charts/references/ReferencePoint', // sub-component for demo purpose | ||
| '!docs/data/charts/scatter/ScatterWebGLRenderer', // Timeout due to the large number of points. |
There was a problem hiding this comment.
SHould we have a smaller test case then to make sure the WebGL renders correctly in argos?
Summary
ScatterChartPremiumcomponent with arendererprop that accepts'svg-single' | 'svg-batch' | 'webgl'(default'svg-single').renderer="webgl", points are drawn into the shared premium WebGL canvas via a newScatterWebGLPlot(instanced antialiased circles), keeping axes/grid/tooltip on the SVG layer.docs/data/charts/scatter/ScatterWebGLRenderer.tsx— 200k points, two series.WebGL plot internals
useScatterWebGLPlotDatawalks series once and writes directly into pre-allocated Float32Arrays (no intermediate objects).sizes/colorsarrays are cached byseriesDataidentity so resize/axis changes don't trigger a GPU color re-upload.ScatterWebGLProgramallocates buffers + VAO once, tracks(capacity, lastUploaded)per buffer, and uploads viabufferSubData+DYNAMIC_DRAWwith a reference-equality short-circuit.ChartsWebGLLayer; the program only issues thedrawArraysInstancedcall.