← Home

Stop Comparing Chart Libraries. Compare Rendering Modes.

The gap between ECharts, Highcharts and Chart.js is usually under 2x. The gap between SVG and canvas is a different shape entirely — one grows with your data, the other does not.

A stopwatch on a desk between two panels, one packed with thousands of tiny separate tiles and one a single smooth surface.

The question arrives in roughly this shape: we have a hundred thousand points, should we use ECharts, Highcharts, or Chart.js? It is a reasonable question, and it is aimed at the wrong variable.

The library gap is a constant. The mode gap is a slope.

Benchmark the popular libraries against each other on the same workload and they mostly land within about 2x. That is a real difference, but it is a constant — switching libraries costs you a day of migration to buy a fixed factor of two.

The mode choice is not a constant. It changes the shape of the curve. Here is what this page’s own tool measured while I was writing it, on one ordinary laptop:

Points SVG Canvas
500 28 ms 33 ms
2,000 32 ms 32 ms
5,000 33 ms 29 ms
10,000 49 ms 28 ms
20,000 80 ms 26 ms

Two things in that table are worth more than the headline number.

Below about 5,000 marks, there is no story. SVG is fine. Anyone telling you to reach for canvas at two thousand points is optimising something that is not costing them anything.

Canvas is flat and SVG is not. Canvas sits at roughly the same cost from 500 to 20,000 points, because you pay per pixel and the pixels did not change. SVG climbs, because every mark is another DOM node to create, lay out, style, and paint. That slope is the whole argument: it is not that canvas is faster today, it is that SVG gets slower as your data grows and canvas does not.

Measure it on your own machine

The table above is one laptop. Yours is a different one, and the crossover point moves with it. Start at 2,000 points and step up until the SVG number starts climbing — that is where your own threshold sits.

Render cost meter
Rendering mode

Results from your browser

Every run carries roughly one to two frames of overhead from the measurement itself, so small gaps at low point counts are noise. Watch the shape of the curve, not a single number.

Nothing measured yet.

The SVG mode here draws one DOM node per point, which is what scatter plots, bar charts, and line charts with markers actually do. A plain SVG line chart is a single <path> and stays cheap — the explosion is specifically about node count, not about SVG as a format.

One caveat about the numbers, because it matters: each run carries roughly one to two frames of fixed overhead from the measurement method itself, which is why the 500-point rows sit at 28 ms rather than near zero. Read the slope, not the floor.

Which mode does your library use?

Library Default mode How to switch
D3 SVG Draw to a canvas context manually
Chart.js Canvas —
ECharts Canvas (SVG available) renderer: 'svg'
Highcharts SVG boost module → WebGL
Plotly SVG (WebGL available) scattergl instead of scatter
Recharts SVG —
uPlot Canvas —

Read that table next to the measurements you just took. Most of the libraries people describe as “unable to handle large datasets” are SVG-by-default libraries being asked to do a canvas job — and several of them have a one-line switch.

What this means for the decision

  1. Decide the mode from the mark count, not the brand. Under a few thousand marks, SVG buys you real DOM nodes: hoverable, CSS-styleable, inspectable, reachable by a screen reader, and it costs you nothing measurable. Above that, the node count starts costing more than the interactivity is worth — and it keeps costing on every reflow, not just on first paint.
  2. Then reduce what you draw. Downsampling before rendering is the other half of this problem, and it compounds with the mode choice rather than competing with it.
  3. Only then pick the library, on API, ecosystem, and how it renders in your framework. By that point performance has stopped being the deciding factor, which is the correct end state.

Common follow-ups

Is SVG always the wrong choice?

No. Below a few thousand marks SVG is comfortable, and you get real DOM nodes — individually hoverable, styleable with CSS, inspectable, accessible to screen readers. That is worth a lot. The problem only starts when the node count grows faster than the insight does.

Where exactly does the cost come from?

Each SVG element is a real DOM node that must be created, laid out, styled, and painted, and it keeps costing on every subsequent reflow. A canvas is one node no matter how many marks you draw into it — you pay for pixels, not for structure.

What if I need tooltips on every point?

Draw to canvas and do hit-testing yourself against the underlying data, usually with a quadtree or by inverting the scale. That is the standard trade: you give up free DOM interactivity and get back a cost that stops growing with your row count.

When is WebGL worth it over canvas?

Around the point where canvas stops fitting in a frame — very roughly past 100,000 marks, or when you need to redraw continuously while panning and zooming. Below that, canvas is far simpler and fast enough.