Skip to content

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.

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.

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.

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.

Three architectural choices drive the streaming throughput:

  1. 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.
  2. 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.
  3. 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.

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.

Get started →