Performance
pixi-charts is built for interactive and streaming visualization of large datasets. This page demonstrates that with live measurements you can verify on your own hardware. Static one-shot rendering — drawing a chart once and never touching it again — is not where this library shines; for that, a simpler Canvas or SVG library may be a better fit. What you should care about here is per-frame update cost, and that is what the demos below measure.
The streaming demo
Section titled “The streaming demo”New points stream in at a constant rate; the oldest fall off the left as the window slides. The
overlay shows two numbers: the wall time of each chart.update() call, and the throughput-derived
FPS (1000 ÷ mean update time, uncapped — on a 120 Hz or 144 Hz display you’ll see numbers above 60 when pixi-charts has headroom to spare). Both numbers
update twice a second so they stay readable. Toggle the stream off and on, switch window sizes,
or regenerate the buffer to see how your hardware handles it.
Compared to Chart.js
Section titled “Compared to Chart.js”Toggle between libraries and try the same window size on each — the readout under the chart
remembers the other library’s last measurement so you can compare without rendering them at
the same time. Running them simultaneously would be unfair to the faster one: JavaScript is
single-threaded, so a 900ms chart.update() call on the slower library blocks the main thread
for everyone, including the faster library’s rAF callbacks. Visually they’d appear to update
in lockstep even though each library’s own per-update time differs by orders of magnitude.
Both libraries receive the same window of points each frame and run with the same minimal
configuration: animations off, tooltips off, axes hidden, plasma color by x-position, small
point radius. The per-update milliseconds in the overlay are the throughput number; the FPS
is its inverse (1000 ÷ updateMs), uncapped so the readout shows each library’s true ceiling
rather than the display’s refresh rate. At small window sizes (around 1k) both libraries paint
well within a frame, but the per-update numbers — and therefore the FPS readouts — already
differ by an order of magnitude. pixi-charts batches all points into a single tinted draw call
while Chart.js styles and paints each point individually. Past a few thousand points the gap
crosses the display budget and Chart.js’s frame rate drops visibly while pixi-charts continues
to update faster than the screen can show. By 100k Chart.js takes most of a second per update
and feels frozen, while pixi-charts still updates around twenty times a second. The shape of
the comparison is consistent across hardware — exact crossover points vary with your GPU and
CPU.
Chart.js was chosen as the comparison because it’s the most-downloaded charting library on npm and, like pixi-charts, paints to a canvas/GPU surface — so the comparison isolates rendering architecture (batched WebGL sprites vs. per-point Canvas draws) rather than the SVG-vs-Canvas axis.
Cold start vs warm update
Section titled “Cold start vs warm update”Creating a WebGL chart has a one-time setup cost: initializing the GL context and compiling shaders takes a few hundred milliseconds on typical hardware. After that, each update lands in single-digit milliseconds. The warm-update number above should match the per-frame update time the streaming demo is showing at 10k points — if it doesn’t, the chart is doing something it shouldn’t, and that’s a bug to file.
Cold start is a real cost. It is paid once per chart instance, not once per frame. If your use case is “draw a small chart once and never touch it again”, the cold-start number dominates and a simpler library is probably the better fit. If your use case is anything interactive — drilling in, panning, streaming, hovering, recoloring — the warm-update number is what determines whether the chart feels good, and that is what this library is built for.
How this works
Section titled “How this works”Three architectural choices drive the streaming throughput:
- Batched draw calls via PixiJS. All scatter points share a single texture inside a
ParticleContainer, so 100k points cost roughly the same to render as 1k — one GPU draw call, not one per point. update()reuses the GL context. The cold-start cost — context creation, shader compilation, particle texture upload — is paid once when the chart is first rendered.chart.update(newData)keeps the existing context, the existing texture, the existing particle container, and rewrites the buffer contents. That’s why the streaming demo’s per-update time is a small fraction of the cold-start time.- Quadtree hit-testing. Hover and click lookups go through
d3-quadtree, giving O(log n) nearest-point queries no matter how large the cloud gets. Tooltips work on 100k points without falling back to brute force.
Try it
Section titled “Try it”The streaming demo’s API is the same render(spec, container) entry point as every other chart
on the site — see Getting Started and the gallery for line, area, bar,
heatmap, and pie. The same chart.update() path used by this page drives every chart type.