Fast, Live Charts with Chart.js: Mastering .update() for Real‑Time Data
When dashboards push data every few seconds, destroying and recreating Chart.js instances hurts performance. This blog shows how to mutate data in place, call <code>.update()</code> with optional animation settings, and measure FPS for real‑time charts.
19 Feb 2026, 02:28 UTC

Problem: Re‑rendering Charts Too Often
When building dashboards that pull new data every few seconds, developers often destroy and recreate the entire Chart.js instance to show fresh values. This approach forces the browser to re‑allocate the canvas, rebuild scales, and re‑initialize plugins on every tick, which quickly degrades performance and can cause jank or frame drops.
What we really want is a way to mutate the data in place and let Chart.js redraw only the parts that changed.
Thesis: Use Chart.js’s Built‑In .update() Wisely
Chart.js exposes a .update() method that accepts an optional animationOptions object. By updating the internal chart.data structure and then calling .update(), you can:
- avoid destroying the canvas
- retain existing scales, tooltips, and legend state
- control animation timing or skip it entirely for high‑frequency streams
Section 1: Mutable Data Structures
Chart.js stores datasets in chart.data.datasets. To push a new point onto a line chart:
// Assume chart is an instance of Chart
const dataset = chart.data.datasets[0];
// Append a new label (e.g., timestamp)
chart.data.labels.push(new Date().toLocaleTimeString());
// Append the new value
dataset.data.push(Math.random() * 100);
// Keep the dataset size bounded (optional)
if (dataset.data.length > 50) {
dataset.data.shift();
chart.data.labels.shift();
}
After mutating the data, call chart.update(). The library will redraw only the affected elements.
Section 2: Animation Control
Animations add a pleasant visual effect but cost CPU cycles. The animationOptions object can be passed to .update():
chart.update({
duration: 0, // 0 ms disables animation
easing: 'linear' // optional, only used if duration > 0
});
Setting duration to 0 tells Chart.js to skip the transition, which is ideal for real‑time feeds that update >30 Hz. For less frequent updates (e.g., once per second), you can keep a small duration (e.g., 200 ms) to give users a smooth visual cue.
Section 3: Performance Measurement
Before and after enabling animation, you can compare frame rates using the browser’s PerformanceObserver:
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const fps = 1000 / entries.reduce((s, e) => s + e.duration, 0) * entries.length;
console.log('FPS:', fps.toFixed(2));
});
observer.observe({ entryTypes: ['measure'], buffered: true });
// Measure a 5‑second window
performance.mark('start');
setTimeout(() => performance.mark('end'), 5000);
performance.measure('frameRate', 'start', 'end');
Run this test with duration: 0 and then with duration: 200. You should see a noticeable FPS drop when animations are enabled during rapid updates.
Section 4: Common Pitfalls & Limitations
- Dataset Structure Changes: If you add or remove datasets, you must adjust
chart.data.datasetsaccordingly before calling.update(). Mismatched lengths can throw rendering errors. - Plugin Re‑initialization: Custom plugins that rely on initialization hooks (e.g.,
beforeInit) won’t run again on.update(). If your plugin needs to react to data changes, listen for thechart.updateevent. - High‑Frequency Updates: Even with
duration: 0, updating >30 times per second can overwhelm the main thread. Consider batching updates or usingrequestAnimationFrameto throttle. - Browser Compatibility: The animation API is stable in Chart.js v4+. Older v3 releases may behave differently.
Worked Example: Real‑Time Random Data
Below is a minimal HTML page that creates a line chart and updates it every 500 ms with a random value. The update is instantaneous (no animation) to keep the UI responsive.
Chart.js Live Update Demo
Key points:
- The
animation.durationis set to0in the chart options, ensuring all subsequent updates are instant. - Data is bounded to 50 points to prevent the chart from growing indefinitely.
- Because we mutate
chart.datadirectly, the canvas element remains untouched; only the visual representation changes.
Actionable Checklist for Live Charts
- Instantiate the chart once and keep a reference.
- Mutate
chart.data.labelsandchart.data.datasets[i].datafor new points. - Call
chart.update({ duration: 0 })for high‑frequency streams; use a small positive duration for occasional updates. - Keep dataset lengths bounded if memory is a concern.
- Measure FPS with
PerformanceObserverduring development to catch regressions. - Handle plugin updates by listening to
chart.updateevents if necessary.
Conclusion
Chart.js’s .update() method is a lightweight, built‑in solution for real‑time data. By mutating the chart’s data objects and disabling animations for rapid updates, you avoid the overhead of re‑creating the canvas and maintain smooth, responsive visuals. Remember to keep dataset structures consistent and monitor performance, especially in high‑frequency scenarios.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.