Skip to content

[charts-premium] Add WebGL renderer to ScatterChartPremium#22157

Open
JCQuintas wants to merge 22 commits intomui:masterfrom
JCQuintas:scatter-chart-webgl
Open

[charts-premium] Add WebGL renderer to ScatterChartPremium#22157
JCQuintas wants to merge 22 commits intomui:masterfrom
JCQuintas:scatter-chart-webgl

Conversation

@JCQuintas
Copy link
Copy Markdown
Member

@JCQuintas JCQuintas commented Apr 22, 2026

Summary

  • Adds a new ScatterChartPremium component with a renderer prop that accepts 'svg-single' | 'svg-batch' | 'webgl' (default 'svg-single').
  • When renderer="webgl", points are drawn into the shared premium WebGL canvas via a new ScatterWebGLPlot (instanced antialiased circles), keeping axes/grid/tooltip on the SVG layer.
  • Demo: docs/data/charts/scatter/ScatterWebGLRenderer.tsx — 200k points, two series.

WebGL plot internals

  • useScatterWebGLPlotData walks series once and writes directly into pre-allocated Float32Arrays (no intermediate objects). sizes/colors arrays are cached by seriesData identity so resize/axis changes don't trigger a GPU color re-upload.
  • ScatterWebGLProgram allocates buffers + VAO once, tracks (capacity, lastUploaded) per buffer, and uploads via bufferSubData + DYNAMIC_DRAW with a reference-equality short-circuit.
  • Clear/draw-dispatch is owned by the shared ChartsWebGLLayer; the program only issues the drawArraysInstanced call.

@code-infra-dashboard
Copy link
Copy Markdown

code-infra-dashboard Bot commented Apr 22, 2026

Bundle size

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)
@mui/x-charts-premium 🔺+7.36KB(+1.36%) 🔺+1.72KB(+1.07%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes

Deploy preview


Check out the code infra dashboard for more information about this PR.

@JCQuintas JCQuintas self-assigned this Apr 23, 2026
@JCQuintas JCQuintas added type: new feature Expand the scope of the product to solve a new problem. plan: Premium Impact at least one Premium user. scope: charts Changes related to the charts. labels Apr 23, 2026
@JCQuintas JCQuintas changed the title [charts] Add WebGL renderer to ScatterChartPremium [charts-premium] Add WebGL renderer to ScatterChartPremium Apr 23, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 23, 2026

Merging this PR will not alter performance

✅ 14 untouched benchmarks


Comparing JCQuintas:scatter-chart-webgl (53d388c) with master (328ea55)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (58314ba) during the generation of this report, so 328ea55 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@JCQuintas JCQuintas marked this pull request as ready for review April 23, 2026 14:00
@alexfauquette
Copy link
Copy Markdown
Member

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

@JCQuintas
Copy link
Copy Markdown
Member Author

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? 🤔

Copy link
Copy Markdown
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines +30 to +32
// 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You reuse the buffer if the number of data point increase. What if it decreases? Will we still see last removed points?

Comment on lines +51 to +55
const cx = getXPosition(scatterPoint.x);
const cy = getYPosition(scatterPoint.y);
const r = series.markerSize / 2;

return (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SHould we have a smaller test case then to make sure the WebGL renders correctly in argos?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plan: Premium Impact at least one Premium user. scope: charts Changes related to the charts. type: new feature Expand the scope of the product to solve a new problem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants