Interaction, resize and data updates

Event handling and dispatches, keeping the chart correct when the container changes size, and the merge rules behind setOption.

Events and actions

// listen: params carries the data point and the series that produced it
chart.on('click', (params) => {
  console.log(params.seriesName, params.name, params.value, params.dataIndex);
  openDetail(params.data.id);
});

chart.on('legendselectchanged', (params) => {
  saveVisibility(params.selected);      // { Free: false, Paid: true }
});

// dispatch: drive the chart programmatically
chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: 3 });
chart.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: 3 });
chart.dispatchAction({ type: 'dataZoom', start: 0, end: 50 });
chart.dispatchAction({ type: 'legendToggleSelect', name: 'Paid' });
EventFires when
click / dblclickA mark or an empty area is clicked; params.componentType says which
mouseover / mouseoutHover on a series item or axis
legendselectchangedA legend entry is toggled
datazoomThe user zooms or pans
finishedThe render loop settled — the moment to screenshot the chart
  • Always chart.off('click') before re-binding inside a render loop, or handlers accumulate.
  • params.value is the raw value; params.data is the original object you passed in, which is where custom fields live.
  • Actions are the supported way to script the chart — mutating internal state directly is not part of the public API.

Responsive resize

// simplest correct approach: observe the container, not the window
const ro = new ResizeObserver(() => chart.resize());
ro.observe(document.getElementById('main'));

// stop observing when the chart is torn down
// ro.disconnect(); chart.dispose();

// option-level responsiveness: overrides keyed on container width
chart.setOption({
  baseOption: {
    legend: { bottom: 0 },
    series: [{ type: 'line', symbol: 'circle' }]
  },
  media: [
    {
      query: { maxWidth: 480 },
      option: {
        legend: { show: false },
        yAxis: { splitNumber: 3 },
        series: [{ symbolSize: 4 }]
      }
    }
  ]
});
SituationWhat to do
Container width changedchart.resize() via a ResizeObserver
Container became visiblechart.resize() after the tab or accordion opens
Fewer labels fitaxisLabel.rotate, axisLabel.hideOverlap, or a smaller splitNumber
Data needs a different formmedia rules that swap series options wholesale
Device pixel ratio changedRe-init with devicePixelRatio, or resize — ECharts re-reads it on resize

Listening to window.resize misses every layout change that is not a viewport change: sidebars, split panes and CSS grid reflows. Observing the container is both simpler and more accurate.

Updating data

// merge (default): matched series are updated in place
chart.setOption({ series: [{ data: nextValues }] });

// explicitly replace one component type instead of merging
chart.setOption({ series: [{ data: nextValues }] }, { replaceMerge: ['series'] });

// full rebuild: nothing from the previous option survives
chart.setOption(freshOption, { notMerge: true });

// defer the render to the next frame when several updates arrive together
chart.setOption(patch, { lazyUpdate: true });

// streaming: append points instead of resending the whole array
chart.appendData({ seriesIndex: 0, data: [[t, v]] });
CallBehaviourCost
setOption(patch)Deep merge into the current optionCheapest — reuse it for value changes
setOption(o, { replaceMerge: ['series'] })Replaces the listed components, keeps the restModerate — the right call when series count changes
setOption(o, { notMerge: true })Discards everything and rebuildsMost expensive; resets zoom and animation state
appendData()Appends to the end of a line, bar or scatter seriesBest for live streams
clear()Empties the canvas, keeps the instanceUse before loading a different chart type
dispose()Destroys the instance and frees listenersMandatory in single-page apps
⚠️
A chart that is never disposed keeps its DOM listeners, timers and canvas alive. In a single-page app that swaps views, call chart.dispose() in the teardown path — otherwise memory grows with every visit to the dashboard.

FAQ

Why do my custom series settings vanish on the next update?
The component was replaced rather than merged, usually because the new option changed the series count or you passed notMerge. Keep the option shape stable and patch only the arrays that change.
How do I export a chart as an image?
Wait for the finished event, then call chart.getDataURL({ pixelRatio: 2, backgroundColor: '#fff' }). The toolbox saveAsImage feature does the same from the UI.

Option configuration Setup and configuration

Last refreshed 2026-09-18.