chart

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 (window points, duration ms). The value axis eases to its new range (fix it with yAxis.min / max).
  • Change: chart.update(data), or chart.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

OptionDefaultWhat 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)
pauseOnHovertrueHold the picture while the pointer is on the data (data keeps arriving)
fps30Draws per second at most; appends and updates within a frame are drawn together
tween300Milliseconds update() and setValue() take to glide; 0 jumps; reduced motion always jumps

API

Method or eventWhat 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.