Getting started: install, init and lifecycle
Choose between the CDN build and tree-shaken ESM imports, pick canvas or SVG rendering, size the container correctly, and dispose charts so memory does not grow.
Install and import
npm install echarts
# the full build is about 1 MB minified; the tree-shaken path is far smaller// Option A: everything, one import. Convenient, largest bundle.
import * as echarts from 'echarts';
// Option B: compose the exact chart you need. This is the production path.
import * as echarts from 'echarts/core';
import { LineChart, BarChart } from 'echarts/charts';
import {
GridComponent, TooltipComponent, LegendComponent,
DataZoomComponent, TitleComponent, MarkLineComponent
} from 'echarts/components';
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
LineChart, BarChart,
GridComponent, TooltipComponent, LegendComponent,
DataZoomComponent, TitleComponent, MarkLineComponent,
LabelLayout, UniversalTransition,
CanvasRenderer
]);
// Option C: CDN for a static page
// <script src="https://cdn.jsdelivr.net/npm/echarts@6/dist/echarts.min.js"></script>
// exposes a global echarts object| Import style | Bundle cost | Fits |
|---|---|---|
import * as echarts from 'echarts' | Everything | Prototypes and internal tools where size is irrelevant |
echarts/core + echarts.use() | Only the listed pieces | Production bundles |
| CDN script tag | Zero in your bundle, one request | Static pages and demos |
| Both | Wasted bytes | Never — pick one |
💡
Components must be registered before the first chart is created, not before the first
setOption. If a feature renders nothing — a tooltip that never appears, a legend that is missing — an unregistered component is almost always the cause. The tree-shaken build fails silently rather than warning.init, container sizing and rendering mode
<div id="revenue" style="width: 100%; height: 360px;"></div>import { init } from 'echarts/core';
const el = document.getElementById('revenue');
// init needs a sized element. A container with height: 0 renders nothing.
const chart = init(el, null, {
renderer: 'canvas', // 'canvas' (default) or 'svg'
devicePixelRatio: window.devicePixelRatio, // set explicitly for crisp export
useDirtyRect: true, // repaint only changed regions: good for dense updates
width: 'auto',
height: 'auto'
});
chart.setOption({
animationDuration: 400,
grid: { left: 48, right: 24, top: 32, bottom: 40 },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: ['Jan', 'Feb', 'Mar', 'Apr'] },
yAxis: { type: 'value' },
series: [{ type: 'line', smooth: true, data: [820, 932, 901, 1290] }]
});
// If the container was hidden at init time, size it and warn the chart:
// const observer = new ResizeObserver(() => chart.resize());
// observer.observe(el);| Renderer | Strength | Weakness |
|---|---|---|
canvas | Fast with thousands of marks; the default | Rasterised output; text is not selectable |
svg | Crisp at any zoom; output is inspectable DOM | Slower past a few thousand elements; larger memory footprint |
canvas with useDirtyRect | Cheap partial repaints | Slightly more bookkeeping per frame |
canvas at a fixed devicePixelRatio | Predictable export resolution | Blurry if the ratio is wrong for the display |
- A chart initialised inside a hidden tab or a collapsed accordion has a zero-size container and renders at 0 by 0 until
resize()is called. - Do not call
inittwice on the same element. ECharts warns and returns a broken chart; usegetInstanceByDomto reuse an existing one. - SVG output goes into the DOM, so a page with many SVG charts accumulates thousands of nodes. Canvas keeps one node per chart.
- The
devicePixelRatiooption is what makes an exported PNG match a retina screen. Without it the export looks soft on high-DPI displays.
Dispose, reuse and re-init
import { init, getInstanceByDom, getInstanceByDom as getInstance, dispose } from 'echarts/core';
// Safe get-or-create: no duplicate instances on the same element.
function mount(el, option) {
const existing = getInstanceByDom(el);
if (existing) {
existing.setOption(option, { notMerge: false });
return existing;
}
const chart = init(el);
chart.setOption(option);
return chart;
}
// Dispose frees the canvas, listeners and internal stores. Without it, a
// single-page app leaks one renderer per navigation.
function unmount(el) {
const chart = getInstanceByDom(el);
if (chart) chart.dispose();
}
// Two other clear paths:
// chart.clear() removes the option and the drawing, keeps the instance usable
// chart.dispose() tears everything down; the instance must not be used again
// A framework-agnostic lifecycle helper
export function createChartController(el) {
const observer = new ResizeObserver(() => getInstanceByDom(el)?.resize());
observer.observe(el);
let chart = null;
return {
render(option) {
chart = mount(el, option);
return chart;
},
resize() { chart?.resize(); },
destroy() {
observer.disconnect();
chart?.dispose();
chart = null;
}
};
}// Listening for events: register after init and remove on dispose.
chart.on('click', (params) => {
console.log(params.seriesName, params.name, params.value);
});
// ECharts keeps the handler alive with the instance, so dispose is the cleanup.
// If you must detach without disposing:
const handler = (params) => console.log(params);
chart.on('click', handler);
chart.off('click', handler);
// The 'finished' event fires after a render or animation completes.
// It is the right moment to read the canvas or take a screenshot.
chart.on('finished', () => {
const url = chart.getDataURL({ pixelRatio: 2, backgroundColor: '#fff' });
console.log(url.slice(0, 32));
});| Situation | Call | Why |
|---|---|---|
| New data for the same chart | setOption | Merges; keeps the instance and its state |
| The chart shape changed completely | setOption(option, { notMerge: true }) | Drops stale series |
| Element removed from the DOM | dispose() | Frees the renderer and listeners |
| Container resized | resize() | Canvas does not reflow by itself |
| Reuse the same element | getInstanceByDom then setOption | Avoids a duplicate instance |
| Reset to a blank chart | clear() | Keeps the instance alive |
FAQ
Why is my chart blank?
Check three things in order: the container has a real width and height, the components used by the option were registered with
echarts.use(), and setOption was called after init on an element that exists. A zero-height container is the most common cause.Should I use SVG or canvas?
Canvas for anything interactive or dense, which is most dashboards. SVG when the output must be crisp at arbitrary zoom, when the chart is small and static, or when you need CSS to reach the chart's elements. You cannot switch renderer on an existing instance — it is an init-time decision.
Related
Option configuration ECharts in React, Vue and Angular
Last refreshed 2026-09-18.