Docs › Interaction and export
Realtime (streaming) charts
Realtime charts: append() streams points through a sliding window, update() glides to new values. All fourteen types, with SSE and WebSocket examples.
A realtime chart redraws as data arrives to show the current state (users online, server load, trade prices, incoming requests). With one option, realtime, all fourteen 82chart types work live, in two ways:
- Append:
chart.append(points)for line, area, bar and scatter charts (time or category x), combos and calendar heatmaps. New points slide in from the right and old ones leave the window (windowpoints,durationms). The value axis eases to its new range (fix it withyAxis.min/max). - Change:
chart.update(data), orchart.setValue(series, index, y)for one value, on every type. Pie and donut angles, gauge values, radar polygons, bar, pyramid, funnel and waterfall lengths, heatmap, calendar and treemap colors and tile positions, totals and labels all glide from the old values to the new ones; new items grow from zero.
Live example
Code for this example
const chart = createChart('#chart', {
type: 'line',
title: 'Users online',
language: 'en',
xAxis: { type: 'time' },
zoom: true,
realtime: { duration: 60000 },
data: { series: [{ name: 'Online', data: [] }, { name: 'Signed in', data: [] }] },
});
let users = 1200, logins = 400;
setInterval(() => {
users = Math.max(0, users + Math.round((Math.random() - 0.48) * 80));
logins = Math.max(0, Math.round(users * (0.3 + Math.random() * 0.05)));
chart.append({ series: [[[Date.now(), users]], [[Date.now(), logins]]] });
}, 500);The chart above appends every half second and keeps the last minute (duration: 60000). With the pointer on the data the picture holds still so the tooltip stays on its point; leave and it catches up (pauseOnHover). Zoom in (+) and it stops following while you look, showing a "Live" button.
Change: every chart glides
Live example
Code for this example
const chart = createChart('#chart', {
type: 'donut',
title: 'Payments (live)',
language: 'en',
realtime: { tween: 400 },
data: { labels: ['Card', 'Wallet', 'Bank', 'Carrier'], series: [{ name: 'Payments', data: [520, 310, 120, 50] }] },
});
const counts = [520, 310, 120, 50];
setInterval(() => {
counts[Math.floor(Math.random() * 4)] += Math.round(Math.random() * 40);
chart.update({ labels: ['Card', 'Wallet', 'Bank', 'Carrier'], series: [{ name: 'Payments', data: [...counts] }] });
}, 800);Live example
Code for this example
const chart = createChart('#chart', {
type: 'gauge',
title: 'CPU usage',
unit: '%',
language: 'en',
realtime: { tween: 500 },
gauge: { max: 100, target: 80, targetLabel: 'Alert', bands: [{ to: 60, color: '#1baf7a' }, { to: 80, color: '#eda100' }, { to: 100, color: '#e34948' }] },
data: { series: [{ name: 'CPU', data: [42] }] },
});
let cpu = 42;
setInterval(() => {
cpu = Math.min(100, Math.max(3, cpu + (Math.random() - 0.5) * 18));
chart.setValue(0, 0, Math.round(cpu));
}, 1000);Live example
Code for this example
const chart = createChart('#chart', {
type: 'treemap',
title: 'Sector moves (live)',
colorBy: 'change',
language: 'en',
deltaColors: 'korea',
realtime: { tween: 600 },
data: { series: [
{ name: 'Chips', data: [{ x: 'Samsung', y: 420, change: 0.8 }, { x: 'SK hynix', y: 140, change: -1.2 }] },
{ name: 'Autos', data: [{ x: 'Hyundai', y: 52, change: 0.4 }, { x: 'Kia', y: 41, change: -0.3 }] },
{ name: 'Internet', data: [{ x: 'NAVER', y: 33, change: 1.5 }, { x: 'Kakao', y: 18, change: -2.1 }] },
] },
});
setInterval(() => {
const d = chart.getOptions().data;
chart.update({ series: d.series.map(s => ({ ...s, data: s.data.map(p => ({ ...p, change: +(p.change + (Math.random() - 0.5) * 0.6).toFixed(2) })) })) });
}, 1500);The realtime option
| Option | Default | What it does |
|---|---|---|
realtime | - | true or the object below. Without it update() redraws at once as before |
window | - | Most points kept per series (days for a calendar) |
duration | - | Time axes: keep only the last this many ms (60000 = a minute) |
pauseOnHover | true | Hold the picture while the pointer is on the data (data keeps arriving) |
fps | 30 | Draws per second at most; appends and updates within a frame are drawn together |
tween | 300 | Milliseconds update() and setValue() take to glide; 0 jumps; reduced motion always jumps |
API
| Method or event | What it does |
|---|---|
append(points, { series }) | One point { x, y }, a list for one series [[x, y], …], or several series { labels?, series: [[…], […]] }. Numeric x is epoch ms with xAxis: { type: 'time' } |
update(data) | With realtime: batched per frame and tweened |
setValue(series, index, y) | Change one value (a gauge, a slice, a cell) |
clear() | Remove every point (series names and options stay) |
isLive() / follow() | Following the newest data? / Undo the zoom and follow again (the Live button) |
announce() | Read the current summary to screen readers now |
on('append', ({ added, total }) => …) | On every append |
From the server: SSE and WebSocket
// Server-sent events (SSE): data: {"t": 1792800000000, "v": 1234}
const chart = createChart('#chart', { type: 'line', xAxis: { type: 'time' }, realtime: { duration: 5 * 60000 }, data: { series: [{ name: 'Requests', data: [] }] } });
const es = new EventSource('/api/stream');
es.onmessage = (e) => { const { t, v } = JSON.parse(e.data); chart.append([[t, v]]); };// WebSocket: several series per message
const ws = new WebSocket('wss://example.com/metrics');
ws.onmessage = (e) => {
const m = JSON.parse(e.data); // { t, cpu, mem }
chart.append({ series: [[[m.t, m.cpu]], [[m.t, m.mem]]] });
};
// when leaving the page
// ws.close(); chart.destroy();Accessibility and performance
- The screen-reader live region speaks at most every 10 seconds, not on every point; keyboard and pointer moves are read at once and
chart.announce()reads on demand. The chart summary (aria-label) is rewritten once a second. - The hidden data table and
toCSV()hold the current window (the table follows once a second). - Frames do not rebuild the SVG: when the structure is the same only attributes and text change, so the node count stays flat and tooltips and highlights keep working.
- Realtime charts skip progressive rendering and thin lines with more points than half the plot width with LTTB (CSV and the table keep everything).
- With reduced motion (
prefers-reduced-motion) changes jump instead of gliding. - Measured (laptop, Chrome, development build): 4 series × a 2,000-point window with 60 appends a second take about 7ms a draw (p95 11ms); a two-series 120-point line about 1.5ms; pies, gauges and treemaps updated 60 times a second around 1ms.