Skip to content

ECharts チートシート

Powerful charting and visualization library by Apache.

01

Getting Started

Setup & First Chart

ECharts is initialized on a DOM element with explicit width/height. setOption configures the entire chart. Apache ECharts (formerly Baidu ECharts) is one of the most powerful JS charting libraries.

echarts
<!-- include ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>

<div id="chart" style="width: 600px; height: 400px;"></div>

<script>
const chart = echarts.init(document.getElementById('chart'));
chart.setOption({
  title: { text: 'Sales' },
  xAxis: { data: ['Q1', 'Q2', 'Q3', 'Q4'] },
  yAxis: {},
  series: [{
    type: 'bar',
    data: [100, 200, 150, 300]
  }]
});
</script>

Init with Theme & Renderer

init takes (dom, theme, opts). The 'svg' renderer is sharper at any zoom and produces smaller DOM for simple charts, while 'canvas' is faster for large datasets. devicePixelRatio controls crispness on retina. Always call dispose() when removing a chart to free memory.

echarts
// register a theme (defined elsewhere or imported)
echarts.registerTheme('myTheme', {
  color: ['#5470c6', '#91cc75'],
  backgroundColor: '#f5f5f5'
});

// renderer: 'canvas' (default, faster) or 'svg' (sharper, lighter)
const chart = echarts.init(document.getElementById('chart'), 'myTheme', {
  renderer: 'svg',
  devicePixelRatio: 2,
  width: 800,
  height: 600,
  locale: 'EN'
});

// detached from DOM later
chart.dispose();

Responsive Resize

ECharts doesn't auto-resize when its container changes — you must call chart.resize(). ResizeObserver is the modern way to watch container size (better than window resize for layout-driven changes). Always dispose() on teardown to prevent leaks in SPAs.

echarts
const chart = echarts.init(document.getElementById('chart'));
chart.setOption({ /* ... */ });

// resize when window changes
window.addEventListener('resize', () => chart.resize());

// or observe the container
const ro = new ResizeObserver(() => chart.resize());
ro.observe(document.getElementById('chart'));

// resize with explicit size
chart.resize({ width: 500, height: 300, silent: false });

// cleanup
window.addEventListener('unload', () => chart.dispose());

setOption Merge Modes

By default setOption deep-merges new options into existing ones, so you can update individual pieces. notMerge: true replaces the whole option (useful when series count changes). replaceMerge targets specific component types (series, xAxis) for partial replacement. lazyUpdate batches multiple setOption calls into one render.

echarts
const chart = echarts.init(document.getElementById('chart'));

// merge (default): deep-merges with existing option
chart.setOption({ xAxis: { data: ['A', 'B'] } });

// notMerge: replace entire option (old config discarded)
chart.setOption({ xAxis: { data: ['X', 'Y'] } }, { notMerge: true });

// replaceMerge: replace specific component types only
chart.setOption(
  { series: [{ type: 'bar', data: [5, 6] }] },
  { replaceMerge: ['series'] }
);

// lazyUpdate: batch updates, apply on next frame
chart.setOption({ series: [{ data: [1, 2] }] }, { lazyUpdate: true });

Lifecycle: getInstanceByDom & dispose

Calling init on a DOM that already has a chart throws. Use getInstanceByDom to check. dispose() frees memory and removes the chart; the DOM element stays. The attribute _echarts_instance_ marks chart containers — query it to find and clean up stray charts. Always dispose in framework unmount hooks.

echarts
function mountChart(dom) {
  // avoid double-init on the same DOM node
  const existing = echarts.getInstanceByDom(dom);
  if (existing) return existing;

  const chart = echarts.init(dom);
  chart.setOption({ /* ... */ });
  return chart;
}

// in a framework cleanup (React useEffect / Vue onUnmounted):
function unmount(dom) {
  const chart = echarts.getInstanceByDom(dom);
  if (chart) chart.dispose();  // free memory + remove DOM
}

// dispose all charts on a page
echarts.disposeAll?.();  // not built-in; iterate manually
Array.from(document.querySelectorAll('[_echarts_instance_]'))
  .forEach(dom => echarts.dispose(dom));
02

Bar Charts

Basic Bar

A bar chart needs a category xAxis and a value yAxis. Each series.data value maps to one category. itemStyle controls bar appearance. For vertical bars, the category axis is x; for horizontal bars, swap x and y axis types.

echarts
chart.setOption({
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
  },
  yAxis: { type: 'value' },
  series: [{
    type: 'bar',
    data: [120, 200, 150, 80, 70],
    itemStyle: { color: '#5470c6' }
  }]
});

Grouped & Stacked Bar

Multiple bar series with the same xAxis are grouped by default. To stack them, give each series the same stack name. Stacking accumulates values per category. Use stack: 'total' on all series that should stack together — series without a stack name still group.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'] },
  yAxis: { type: 'value' },
  // GROUPED: multiple series render side by side
  series: [
    { type: 'bar', name: 'A', data: [10, 20, 30, 40] },
    { type: 'bar', name: 'B', data: [15, 25, 35, 45] }
  ]
});

// STACKED: add stack with same name to each series
chart.setOption({
  series: [
    { type: 'bar', name: 'A', stack: 'total', data: [10, 20, 30, 40] },
    { type: 'bar', name: 'B', stack: 'total', data: [15, 25, 35, 45] }
  ]
});

Horizontal Bar

A horizontal bar is just a bar chart with the category axis on yAxis and value axis on xAxis. Labels with position: 'right' sit at the bar end. Horizontal bars are better for long category names or when comparing many categories — they avoid rotated labels.

echarts
chart.setOption({
  // swap: category axis becomes yAxis
  yAxis: {
    type: 'category',
    data: ['Apple', 'Banana', 'Cherry', 'Date']
  },
  xAxis: { type: 'value' },
  series: [{
    type: 'bar',
    data: [120, 200, 150, 80],
    label: {
      show: true,
      position: 'right'  // label at end of bar
    }
  }]
});

Bar with Background & Rounded Corners

showBackground draws a track behind each bar (progress-bar style). itemStyle.borderRadius rounds bar corners — pass [topLeft, topRight, bottomRight, bottomLeft] for vertical bars; reverse order for horizontal. borderRadius can be a number (all corners) or array.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['A', 'B', 'C', 'D'] },
  yAxis: { type: 'value' },
  series: [{
    type: 'bar',
    data: [50, 80, 60, 90],
    showBackground: true,
    backgroundStyle: {
      color: 'rgba(180, 180, 180, 0.2)',
      borderRadius: [4, 4, 0, 0]
    },
    itemStyle: {
      borderRadius: [8, 8, 0, 0]  // round top corners
    }
  }]
});

Bar Race (Dynamic)

A bar race animates reordering. Sort the data array, then update both the yAxis categories and series data. animationDurationUpdate controls transition smoothness. yAxis.inverse: true puts the largest value at the top. This is popular for animated data stories.

echarts
const data = [
  { name: 'A', value: 10 },
  { name: 'B', value: 20 }
];

chart.setOption({
  xAxis: { type: 'value', max: 100 },
  yAxis: { type: 'category', inverse: true },
  series: [{
    type: 'bar',
    data: data.map(d => ({ value: d.value, name: d.name })),
    label: { show: true, position: 'right' },
    // sort bars by value on each update
    animationDuration: 500,
    animationDurationUpdate: 500
  }]
});

// update data on interval
setInterval(() => {
  data.forEach(d => d.value += Math.random() * 10);
  data.sort((a, b) => b.value - a.value);
  chart.setOption({
    yAxis: { data: data.map(d => d.name) },
    series: [{ data: data.map(d => d.value) }]
  });
}, 1000);

Bar Width & Gap

barWidth accepts pixels or percentage of category band. barGap is the gap between bars within a group (only matters with multiple series). barCategoryGap is the gap between groups. Percentages are relative to the category band, so they stay proportional on resize.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['A', 'B', 'C', 'D'] },
  yAxis: { type: 'value' },
  series: [{
    type: 'bar',
    data: [50, 80, 60, 90],
    barWidth: '40%',          // width of each bar
    barGap: '20%',            // gap between bars in same group
    barCategoryGap: '40%',    // gap between category groups
    // fixed pixel width also works:
    // barWidth: 30
  }]
});
03

Line Charts

Basic Line

A line chart uses type: 'line'. Points are shown by default with symbol markers; set symbol: 'none' to hide them. The line connects points in data order. For time series, use type: 'time' on xAxis with [timestamp, value] pairs.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] },
  yAxis: { type: 'value' },
  series: [{
    type: 'line',
    data: [120, 200, 150, 80, 70],
    symbol: 'circle',      // point marker
    symbolSize: 8
  }]
});

Smooth Line & Area

smooth: true curves the line (Catmull-Rom interpolation). areaStyle fills the area under the line; a gradient (linear color stops) gives a faded look. boundaryGap: false on the category axis starts the line at the y-axis edge instead of leaving a gap.

echarts
chart.setOption({
  xAxis: { type: 'category', boundaryGap: false, data: ['Mon','Tue','Wed','Thu','Fri'] },
  yAxis: { type: 'value' },
  series: [{
    type: 'line',
    data: [120, 200, 150, 80, 70],
    smooth: true,           // curved line
    areaStyle: {            // fill under line
      color: {
        type: 'linear',
        x: 0, y: 0, x2: 0, y2: 1,
        colorStops: [
          { offset: 0, color: 'rgba(84,112,198,0.5)' },
          { offset: 1, color: 'rgba(84,112,198,0.05)' }
        ]
      }
    }
  }]
});

Multi-Series Line

Multiple series render as separate lines, distinguished by color. The legend toggles visibility. lineStyle.type accepts 'solid', 'dashed', 'dotted'. Each series can have its own style. The name in legend must match series.name.

echarts
chart.setOption({
  legend: { data: ['Email', 'Search'] },
  xAxis: { type: 'category', data: ['Mon','Tue','Wed','Thu','Fri'] },
  yAxis: { type: 'value' },
  series: [
    {
      type: 'line',
      name: 'Email',
      data: [120, 132, 101, 134, 90],
      lineStyle: { width: 3, type: 'solid' }
    },
    {
      type: 'line',
      name: 'Search',
      data: [220, 182, 191, 234, 290],
      lineStyle: { width: 2, type: 'dashed' }
    }
  ]
});

Stacked Area

Stacked area charts use type: 'line' with the same stack name and an areaStyle. Each series stacks on top of the previous. emphasis.focus: 'series' highlights the whole series on hover. Useful for showing composition over time (e.g. traffic by source).

echarts
chart.setOption({
  xAxis: { type: 'category', boundaryGap: false, data: ['Mon','Tue','Wed','Thu','Fri'] },
  yAxis: { type: 'value' },
  series: [
    {
      type: 'line',
      name: 'A',
      stack: 'total',
      areaStyle: {},
      data: [120, 132, 101, 134, 90],
      emphasis: { focus: 'series' }
    },
    {
      type: 'line',
      name: 'B',
      stack: 'total',
      areaStyle: {},
      data: [220, 182, 191, 234, 290]
    }
  ]
});

Step Line

step turns a line into a staircase. 'start' steps before the point, 'middle' (symmetric) at the point, 'end' after. Step charts are great for values that change discretely (inventory levels, server status) rather than continuously.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['Mon','Tue','Wed','Thu','Fri'] },
  yAxis: { type: 'value' },
  series: [{
    type: 'line',
    data: [120, 200, 150, 80, 70],
    step: 'middle',          // 'start' | 'middle' | 'end'
    symbol: 'none',
    lineStyle: { width: 2 }
  }]
});

Line with Time Axis

With type: 'time', the axis auto-formats dates and handles irregular intervals. Data points are [timestamp, value] pairs. ECharts spaces points by their actual time, so gaps in data show correctly. This is the right choice for time series with varying intervals.

echarts
chart.setOption({
  xAxis: { type: 'time' },   // auto-parses timestamps
  yAxis: { type: 'value' },
  series: [{
    type: 'line',
    data: [
      [new Date('2024-01-01').getTime(), 100],
      [new Date('2024-01-02').getTime(), 200],
      [new Date('2024-01-05').getTime(), 150],
      [new Date('2024-01-10').getTime(), 300]
    ],
    smooth: true
  }]
});
04

Pie Charts

Basic Pie

Pie charts don't use axes — series.data is an array of {value, name}. radius controls pie size as a percentage of the container's smaller dimension. emphasis styles apply on hover. The legend auto-derives labels from data.name.

echarts
chart.setOption({
  series: [{
    type: 'pie',
    radius: '60%',          // radius of pie
    data: [
      { value: 1048, name: 'Search' },
      { value: 735, name: 'Direct' },
      { value: 580, name: 'Email' },
      { value: 484, name: 'Union' },
      { value: 300, name: 'Video' }
    ],
    emphasis: {
      itemStyle: {
        shadowBlur: 10,
        shadowOffsetX: 0,
        shadowColor: 'rgba(0,0,0,0.5)'
      }
    }
  }]
});

Doughnut (Ring) Pie

Setting radius to [inner, outer] creates a doughnut. A center label is a common pattern (show total or a KPI). avoidLabelOverlap: false keeps labels where they are. The inner radius controls ring thickness — [50%, 70%] is a thin ring; [0%, 70%] is a full pie.

echarts
chart.setOption({
  series: [{
    type: 'pie',
    radius: ['40%', '70%'],   // [inner, outer] = ring
    avoidLabelOverlap: false,
    label: {
      show: true,
      position: 'center',     // center label
      formatter: 'Total\n{c}'
    },
    data: [
      { value: 1048, name: 'A' },
      { value: 735, name: 'B' },
      { value: 580, name: 'C' }
    ]
  }]
});

Rose (Nightingale) Chart

roseType makes slice radius proportional to value (Nightingale rose). 'area' uses sqrt(value) for radius (area-proportional), 'radius' uses value directly. Each slice has the same angle but different radius. Good for comparing magnitudes where angle alone is hard to judge.

echarts
chart.setOption({
  series: [{
    type: 'pie',
    radius: ['10%', '70%'],
    roseType: 'area',         // or 'radius'
    data: [
      { value: 40, name: 'A' },
      { value: 38, name: 'B' },
      { value: 32, name: 'C' },
      { value: 30, name: 'D' },
      { value: 28, name: 'E' }
    ],
    label: { show: true }
  }]
});

Pie with Custom Labels

label.formatter supports template vars: {a} (series name), {b} (data name), {c} (value), {d} (percentage). labelLine controls the connector line. length is the segment near the slice, length2 the segment near the label. Custom labels make pie charts much more readable.

echarts
chart.setOption({
  series: [{
    type: 'pie',
    radius: '60%',
    label: {
      formatter: '{b}: {d}%',   // name: percentage
      color: '#333',
      fontSize: 14
    },
    labelLine: {
      show: true,
      length: 15,              // first segment
      length2: 20,             // second segment
      smooth: true
    },
    data: [
      { value: 1048, name: 'Search' },
      { value: 735, name: 'Direct' }
    ]
  }]
});

Semi-circle Pie

Combining startAngle and endAngle creates partial pies (half, quarter, gauge-like). center positions the pie — ['50%','70%'] pushes it down so a 180° pie sits at the bottom. Partial pies are often used as gauges or for stylized dashboards.

echarts
chart.setOption({
  series: [{
    type: 'pie',
    radius: ['40%', '70%'],
    center: ['50%', '70%'],    // move down
    startAngle: 180,           // start at left
    endAngle: 360,             // end at right -> semicircle
    data: [
      { value: 60, name: 'A' },
      { value: 30, name: 'B' },
      { value: 10, name: 'C' }
    ]
  }]
});
05

Scatter Charts

Basic Scatter

Scatter charts use two value axes; each data point is [x, y]. symbolSize controls point size (fixed or per-point via a function). Scatter reveals correlation between two variables. Both axes are type: 'value' (numeric), unlike category-based bar/line.

echarts
chart.setOption({
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  series: [{
    type: 'scatter',
    symbolSize: 12,
    data: [
      [10, 20], [15, 25], [20, 30], [25, 35],
      [30, 40], [35, 45], [40, 50], [45, 55]
    ],
    itemStyle: { color: '#5470c6' }
  }]
});

Bubble Chart (Size by Value)

A bubble chart is a scatter where point size encodes a third dimension. Pass [x, y, size] per point and set symbolSize to a function returning the size. The function runs per point, so each bubble scales independently. Useful for 3-variable data without a 3D chart.

echarts
chart.setOption({
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  series: [{
    type: 'scatter',
    // each point: [x, y, size]
    data: [
      [10, 20, 30],
      [15, 25, 60],
      [20, 30, 12],
      [25, 35, 45]
    ],
    symbolSize: function (data) {
      return data[2];           // use 3rd element as size
    }
  }]
});

Scatter with VisualMap (Color by Value)

visualMap maps a data dimension to color. dimension: 2 colors by the 3rd element (index 2) of each point. inRange.color defines the gradient. This adds a fourth dimension (color) to a scatter. The visualMap component shows the legend with a slider.

echarts
chart.setOption({
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  visualMap: {
    min: 0,
    max: 100,
    dimension: 2,             // map color to 3rd element
    inRange: { color: ['#50a3ba', '#eac736', '#d94e5d'] },
    right: 10,
    top: 'center'
  },
  series: [{
    type: 'scatter',
    data: [[10,20,30], [15,25,60], [20,30,12]],
    symbolSize: 15
  }]
});

Effect Scatter (Animated)

effectScatter adds a ripple animation around each point — great for highlighting key data points (alerts, top cities). showEffectOn controls when the ripple plays. brushType: 'stroke' is lighter; 'fill' is more prominent. Use sparingly — too many ripples distract.

echarts
chart.setOption({
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  series: [{
    type: 'effectScatter',    // animated ripple
    symbolSize: function (data) { return data[2]; },
    data: [[10, 20, 30], [15, 25, 60]],
    showEffectOn: 'render',   // 'render' or 'emphasis'
    rippleEffect: {
      brushType: 'stroke',    // 'stroke' or 'fill'
      period: 4,
      scale: 3
    }
  }]
});

Large-scale Scatter

For thousands of points, enable progressive rendering — ECharts splits data into chunks and renders them across frames to avoid freezing. large: true uses a single optimized draw call. Combine with small symbolSize and opacity to handle overplotting. This keeps 50k+ points smooth.

echarts
// for thousands of points, use progressive rendering
chart.setOption({
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  series: [{
    type: 'scatter',
    data: largeDataArray,    // 50k+ points
    symbolSize: 3,
    progressive: 2000,        // chunk size for progressive render
    progressiveThreshold: 5000,  // enable above this count
    large: true,              // optimize for many points
    largeThreshold: 2000,
    itemStyle: { opacity: 0.6 }
  }]
});
06

Radar Charts

Basic Radar

Radar charts need a radar.indicator array defining each axis (name and max). Series data is an array of values matching the indicators. Radar is great for comparing multiple attributes of a few items (player stats, product comparison). max sets the scale of each axis.

echarts
chart.setOption({
  radar: {
    indicator: [
      { name: 'Speed', max: 100 },
      { name: 'Power', max: 100 },
      { name: 'Range', max: 100 },
      { name: 'Comfort', max: 100 },
      { name: 'Price', max: 100 }
    ]
  },
  series: [{
    type: 'radar',
    data: [{ value: [85, 70, 90, 65, 80], name: 'Car A' }]
  }]
});

Multi-series Radar

Multiple data entries render overlapping polygons, ideal for comparison. Each entry needs a unique name matching the legend. Too many series (5+) makes radar charts unreadable — the polygons overlap into a blob. Stick to 2-4 items for clarity.

echarts
chart.setOption({
  legend: { data: ['Car A', 'Car B'] },
  radar: {
    indicator: [
      { name: 'Speed', max: 100 },
      { name: 'Power', max: 100 },
      { name: 'Range', max: 100 }
    ]
  },
  series: [{
    type: 'radar',
    data: [
      { value: [85, 70, 90], name: 'Car A' },
      { value: [60, 95, 75], name: 'Car B' }
    ]
  }]
});

Radar with Area

areaStyle fills the radar polygon with semi-transparent color, making the shape easier to read. lineStyle emphasizes the outline. Keep areaStyle opacity low (0.2-0.4) so overlapping series stay visible. Symbols mark each vertex.

echarts
chart.setOption({
  radar: {
    indicator: [
      { name: 'A', max: 100 },
      { name: 'B', max: 100 },
      { name: 'C', max: 100 }
    ]
  },
  series: [{
    type: 'radar',
    data: [{ value: [85, 70, 90], name: 'Score' }],
    areaStyle: { opacity: 0.3 },
    lineStyle: { width: 2 },
    symbol: 'circle',
    symbolSize: 6
  }]
});

Radar Shape & Axis

shape: 'polygon' (default) gives angular axes; 'circle' makes smooth rings. splitNumber controls grid density. splitArea alternates colors for a zebra effect. axisName styles the axis labels. These options control the chart's visual structure without touching data.

echarts
chart.setOption({
  radar: {
    shape: 'polygon',          // 'polygon' or 'circle'
    radius: '65%',
    splitNumber: 5,            // grid ring count
    axisName: {
      color: '#333',
      fontSize: 12
    },
    splitLine: { lineStyle: { color: '#ccc' } },
    splitArea: {
      areaStyle: { color: ['#fafafa', '#fff'] }
    },
    indicator: [
      { name: 'Speed', max: 100 },
      { name: 'Power', max: 100 }
    ]
  },
  series: [{ type: 'radar', data: [{ value: [80, 70] }] }]
});

Radar Polar Radius

radius: [inner, outer] creates a ring-shaped radar (like a doughnut). center positions the chart. min on an indicator sets where the axis starts — useful when all values are high (avoids a tiny polygon in the center). Adjust center to leave room for axis labels.

echarts
chart.setOption({
  radar: {
    indicator: [
      { name: 'A', max: 100, min: 0 },   // min sets the inner bound
      { name: 'B', max: 100 },
      { name: 'C', max: 100 }
    ],
    radius: ['20%', '70%'],   // [inner, outer] for ring radar
    center: ['50%', '55%']
  },
  series: [{
    type: 'radar',
    data: [{ value: [60, 70, 80] }]
  }]
});
07

Heatmaps

Cartesian Heatmap

A cartesian heatmap needs a visualMap to color cells. Data is [x, y, value]. label: { show: true } prints values in cells (only good for small grids). calculable: true adds a slider handle. Heatmaps reveal density patterns (e.g. hourly activity).

echarts
const hours = ['12a','1a','2a','3a','4a','5a','6a','7a','8a','9a','10a','11a'];
const days = ['Sat','Sun','Mon','Tue','Wed','Thu','Fri'];

// data: [x, y, value]
const data = [[0,0,5],[0,1,1],[1,0,8] /* ... */];

chart.setOption({
  tooltip: {},
  xAxis: { type: 'category', data: hours },
  yAxis: { type: 'category', data: days },
  visualMap: {
    min: 0, max: 10,
    calculable: true,
    orient: 'horizontal',
    left: 'center', bottom: '5%'
  },
  series: [{
    type: 'heatmap',
    data: data,
    label: { show: true }
  }]
});

Calendar Heatmap

Calendar heatmaps show daily values over a year (GitHub-style contribution graph). calendar.range sets the year or date range. Data points are [dateString, value]. The visualMap gradient defines color stops. cellSize controls square size — 'auto' fits the container.

echarts
const data = [];
// generate one year of data
for (let i = 0; i < 365; i++) {
  const date = new Date(2024, 0, 1);
  date.setDate(date.getDate() + i);
  data.push([date.toISOString().slice(0,10), Math.floor(Math.random() * 100)]);
}

chart.setOption({
  tooltip: {},
  visualMap: {
    min: 0, max: 100,
    inRange: { color: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'] }
  },
  calendar: {
    range: '2024',
    cellSize: ['auto', 13],
    yearLabel: { show: true }
  },
  series: [{ type: 'heatmap', data: data }]
});

Heatmap Item Style

itemStyle.borderColor and borderWidth create a grid separator effect (white borders make cells distinct). borderRadius rounds cell corners. emphasis styles apply on hover. A hidden visualMap (show: false) still drives colors without showing the legend.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['A','B','C','D'] },
  yAxis: { type: 'category', data: ['X','Y','Z'] },
  visualMap: { min: 0, max: 100, show: false },
  series: [{
    type: 'heatmap',
    data: [[0,0,80],[0,1,30],[1,0,50]],
    itemStyle: {
      borderColor: '#fff',       // white grid lines
      borderWidth: 2,
      borderRadius: 4
    },
    emphasis: {
      itemStyle: { shadowBlur: 10 }
    }
  }]
});

Punch Card Heatmap

A punch card is a 7x24 heatmap showing activity by day-of-week and hour. Each cell is a time slot. The rounded itemStyle makes it look like dots. Punch cards reveal weekly patterns (e.g. when a server is busiest). The data is a complete 168-cell grid.

echarts
const data = [];
for (let day = 0; day < 7; day++) {
  for (let hour = 0; hour < 24; hour++) {
    data.push([hour, day, Math.floor(Math.random() * 50) + 1]);
  }
}

chart.setOption({
  xAxis: { type: 'category', data: Array.from({length:24}, (_,i) => i + 'h') },
  yAxis: { type: 'category', data: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] },
  visualMap: { max: 50, inRange: { color: ['#fff', '#5470c6'] } },
  series: [{
    type: 'heatmap',
    data: data,
    itemStyle: { borderRadius: 10, borderWidth: 2, borderColor: '#fff' }
  }]
});

Heatmap on Geo Map

Combining geo with a map series colors regions by value. visualMap drives the color scale. You must register a map first via echarts.registerMap('china', geoJson). roam: true enables pan/zoom. This is how choropleth (color-by-region) maps are built.

echarts
// requires a registered geo map (e.g. echarts.registerMap)
chart.setOption({
  geo: { map: 'china', roam: true },
  visualMap: {
    min: 0, max: 1000,
    inRange: { color: ['#e0ecf4', '#005824'] }
  },
  series: [{
    type: 'map',
    map: 'china',
    data: [
      { name: 'Beijing', value: 800 },
      { name: 'Shanghai', value: 950 }
    ]
  }]
});
08

Tree Charts

Basic Tree (Vertical)

Tree charts render hierarchical data. layout: 'orthogonal' with orient: 'LR' makes a left-to-right tree. expandAndCollapse lets users click to fold/unfold subtrees. leaves configures leaf node styling. Tree is perfect for org charts, file trees, and taxonomies.

echarts
const data = {
  name: 'Root',
  children: [
    {
      name: 'Child A',
      children: [{ name: 'A1' }, { name: 'A2' }]
    },
    {
      name: 'Child B',
      children: [{ name: 'B1' }]
    }
  ]
};

chart.setOption({
  series: [{
    type: 'tree',
    data: [data],
    top: '5%', left: '10%', bottom: '5%', right: '20%',
    layout: 'orthogonal',       // 'orthogonal' or 'radial'
    orient: 'LR',               // 'LR','RL','TB','BT'
    symbolSize: 10,
    label: { position: 'left' },
    leaves: { label: { position: 'right' } },
    expandAndCollapse: true,
    animationDuration: 550
  }]
});

Horizontal Tree

orient: 'LR' produces a horizontal tree (root on left, leaves on right). Internal node labels sit to the LEFT of the node; leaf labels to the RIGHT — this prevents overlap with branches. curveness on lineStyle creates curved connectors for a softer look.

echarts
chart.setOption({
  series: [{
    type: 'tree',
    data: [treeData],
    layout: 'orthogonal',
    orient: 'LR',              // left to right
    symbol: 'emptyCircle',
    symbolSize: 7,
    label: { position: 'left', verticalAlign: 'middle', align: 'right' },
    leaves: { label: { position: 'right', align: 'left' } },
    lineStyle: { color: '#999', width: 1, curveness: 0.5 }
  }]
});

Radial Tree

layout: 'radial' places the root at the center and radiates children outward in a circle. This works well for large trees where a horizontal layout would be too wide. emphasis.focus: 'descendant' highlights all descendants on hover, helping users trace branches.

echarts
chart.setOption({
  series: [{
    type: 'tree',
    data: [treeData],
    layout: 'radial',          // circular layout
    symbol: 'circle',
    symbolSize: 8,
    label: {
      position: 'inside',
      rotate: 0
    },
    leaves: { label: { position: 'right' } },
    emphasis: { focus: 'descendant' },
    lineStyle: { curveness: 0.5 }
  }]
});

Tree with Custom Symbols

symbol and symbolSize accept functions for per-node customization. Here internal nodes (with children) are larger rectangles while leaves are small circles. This visually distinguishes hierarchy levels. Combine with orient: 'TB' for a classic top-down org chart.

echarts
const treeData = {
  name: 'CEO',
  value: 'Boss',
  children: [
    { name: 'VP Engineering', children: [{ name: 'Eng Lead' }] },
    { name: 'VP Sales', children: [{ name: 'Sales Lead' }] }
  ]
};

chart.setOption({
  series: [{
    type: 'tree',
    data: [treeData],
    symbol: function (params) {
      // custom symbol per node
      return params.data.children ? 'rect' : 'circle';
    },
    symbolSize: function (params) {
      return params.data.children ? 15 : 8;
    },
    orient: 'TB',
    label: { position: 'top', distance: 8 }
  }]
});

Tree Expand/Collapse Control

initialTreeDepth controls how many levels are open initially (null = all, 0 = root only). Clicking a node with children toggles its subtree. The click event lets you react to node selection — useful for drill-down UIs. animationDurationUpdate smooths expand/collapse.

echarts
chart.setOption({
  series: [{
    type: 'tree',
    data: [treeData],
    expandAndCollapse: true,
    initialTreeDepth: 2,        // expand first 2 levels
    collapse: 'collapseBtn',
    symbol: 'circle',
    animationDurationUpdate: 750
  }]
});

// programmatic control via API
chart.on('click', function (params) {
  if (params.componentType === 'series') {
    console.log('Node clicked:', params.data.name);
    console.log('Collapsed:', params.data.collapsed);
  }
});
09

Sunburst Charts

Basic Sunburst

Sunburst is a radial tree where each ring represents a hierarchy level. Inner = parent, outer = children. Each node's value drives its angular size. radius: [0, '90%'] makes a full disc; [inner, outer] creates a ring sunburst. Great for hierarchical proportion visualization.

echarts
const data = [{
  name: 'Root',
  children: [
    {
      name: 'A',
      value: 15,
      children: [{ name: 'A1', value: 5 }, { name: 'A2', value: 10 }]
    },
    {
      name: 'B',
      value: 20,
      children: [{ name: 'B1', value: 20 }]
    }
  ]
}];

chart.setOption({
  series: [{
    type: 'sunburst',
    data: data,
    radius: [0, '90%'],
    label: { rotate: 'radial' }
  }]
});

Sunburst with Levels

levels configures each ring separately — the first entry is the root, subsequent entries map to deeper levels. r0/r set inner/outer radius for that level. Different label rotations (radial, tangential, 0) keep text readable at each depth. This gives fine-grained styling control.

echarts
chart.setOption({
  series: [{
    type: 'sunburst',
    data: sunburstData,
    radius: ['15%', '90%'],
    levels: [
      {},  // root level (default)
      {
        r0: '15%',
        r: '45%',
        label: { rotate: 0, fontSize: 14 },
        itemStyle: { borderWidth: 2 }
      },
      {
        r0: '45%',
        r: '70%',
        label: { rotate: 'tangential', fontSize: 12 }
      },
      {
        r0: '70%',
        r: '90%',
        label: { rotate: 'radial', fontSize: 10 }
      }
    ]
  }]
});

Sunburst Item Style & Highlight

emphasis.focus: 'ancestor' highlights the path from hovered node back to root — users see where a slice fits in the hierarchy. borderWidth separates slices visually. Sunburst is interactive: clicking usually drills down. Use ancestor highlighting to maintain context in deep trees.

echarts
chart.setOption({
  series: [{
    type: 'sunburst',
    data: data,
    itemStyle: {
      borderColor: '#fff',
      borderWidth: 1
    },
    emphasis: {
      focus: 'ancestor'    // highlight ancestors on hover
    },
    highlight: {
      itemStyle: { color: '#ffb' }
    }
  }]
});

Sunburst with Value & Sorting

sort controls slice ordering within a parent. nodeClick: 'zoomToNode' makes a click zoom into that subtree (great for exploration). minAngle hides labels on slices smaller than 5 degrees, avoiding clutter. The value of parent nodes is auto-summed from children if omitted.

echarts
chart.setOption({
  series: [{
    type: 'sunburst',
    data: [{
      name: 'Root',
      children: [
        { name: 'A', value: 30, children: [/* ... */] },
        { name: 'B', value: 70, children: [/* ... */] }
      ]
    }],
    nodeClick: 'zoomToNode',   // click to zoom into subtree
    sort: 'desc',              // or 'asc', null
    label: { minAngle: 5 }     // hide labels on tiny slices
  }]
});

Sunburst Drill-down

Custom click handlers let you build your own drill-down UX. Replace the data with the clicked node to zoom in. Keep a reference to the parent if you want a 'back' button. Sunburst drill-down is excellent for exploring deep hierarchies without overwhelming the screen.

echarts
const data = [/* full tree */];
let currentRoot = data[0];

chart.setOption({
  series: [{
    type: 'sunburst',
    data: data,
    nodeClick: false
  }]
});

chart.on('click', function (params) {
  if (params.componentType === 'series' && params.data.children) {
    // manually drill down
    currentRoot = params.data;
    chart.setOption({
      series: [{ data: [currentRoot] }]
    }, { notMerge: true });
  }
});
10

Sankey Diagrams

Basic Sankey

Sankey shows flow between nodes. data is nodes (with names); links is the flow (source, target, value). The width of each link is proportional to value. emphasis.focus: 'adjacency' highlights connected nodes on hover. Great for energy, money, or user flow visualization.

echarts
chart.setOption({
  series: [{
    type: 'sankey',
    data: [
      { name: 'Source A' },
      { name: 'Source B' },
      { name: 'Mid C' },
      { name: 'Sink D' }
    ],
    links: [
      { source: 'Source A', target: 'Mid C', value: 5 },
      { source: 'Source B', target: 'Mid C', value: 3 },
      { source: 'Mid C', target: 'Sink D', value: 8 }
    ],
    emphasis: { focus: 'adjacency' },
    lineStyle: { color: 'gradient', curveness: 0.5 }
  }]
});

Sankey Node Levels

levels styles nodes by depth (column). lineStyle.color: 'source' colors links to match the source node; 'target' matches the target; 'gradient' blends. nodeAlign positions nodes vertically within a column. Setting depth explicitly forces column placement, overriding auto-layout.

echarts
chart.setOption({
  series: [{
    type: 'sankey',
    data: [
      { name: 'A', depth: 0 },
      { name: 'B', depth: 1 },
      { name: 'C', depth: 2 }
    ],
    links: [
      { source: 'A', target: 'B', value: 10 },
      { source: 'B', target: 'C', value: 10 }
    ],
    levels: [
      { depth: 0, itemStyle: { color: '#fbb' }, lineStyle: { color: 'source' } },
      { depth: 1, itemStyle: { color: '#bfb' }, lineStyle: { color: 'target' } },
      { depth: 2, itemStyle: { color: '#bbf' } }
    ],
    nodeAlign: 'justify'      // 'left','right','justify'
  }]
});

Sankey Node Style & Gap

nodeWidth sets how thick each node rectangle is. nodeGap controls vertical spacing. Smaller gaps show more nodes but can overlap. lineStyle.opacity makes flows subtle so nodes stand out. label.position: 'right' puts labels next to nodes — common for left-to-right flows.

echarts
chart.setOption({
  series: [{
    type: 'sankey',
    data: nodes,
    links: links,
    nodeWidth: 20,            // width of each node rectangle
    nodeGap: 10,              // vertical gap between nodes
    nodeAlign: 'justify',
    label: {
      fontSize: 12,
      color: '#333',
      position: 'right'
    },
    lineStyle: { opacity: 0.4 },
    itemStyle: { borderWidth: 0 }
  }]
});

Sankey with Cycle (Drain)

True cycles cause ECharts Sankey to fail. The workaround is to split a recirculating node into separate 'in' and 'out' nodes (e.g. 'Recycle') so the flow is acyclic. This visually represents feedback loops. Always verify flow conservation: a node's input total should equal output total.

echarts
// Sankey normally forbids cycles, but you can show feedback loops
// by splitting a node into two (in & out) with the same name suffix
chart.setOption({
  series: [{
    type: 'sankey',
    data: [
      { name: 'Input' },
      { name: 'Process' },
      { name: 'Output' },
      { name: 'Recycle' }
    ],
    links: [
      { source: 'Input', target: 'Process', value: 100 },
      { source: 'Process', target: 'Output', value: 80 },
      { source: 'Process', target: 'Recycle', value: 20 },
      { source: 'Recycle', target: 'Process', value: 20 }
    ],
    emphasis: { focus: 'adjacency' }
  }]
});

Sankey Interaction

Sankey click events distinguish nodes from edges via dataType. Use this to build detail panels showing flow specifics. label.formatter: '{b}: {c}' shows name and value. The adjacency focus highlights the full path through a hovered node, revealing cause-and-effect chains.

echarts
chart.setOption({
  series: [{
    type: 'sankey',
    data: nodes,
    links: links,
    emphasis: {
      focus: 'adjacency',
      lineStyle: { opacity: 0.8 }
    },
    label: { formatter: '{b}: {c}' },
    tooltip: { trigger: 'item' }
  }]
});

chart.on('click', function (params) {
  if (params.dataType === 'edge') {
    console.log('Flow from', params.data.source, 'to', params.data.target);
    console.log('Value:', params.data.value);
  } else if (params.dataType === 'node') {
    console.log('Node:', params.data.name);
  }
});
11

Funnel Charts

Basic Funnel

A funnel shows stages of a process where each stage has fewer items. sort: 'descending' (default) puts the largest stage at top. Data should be ordered by the process flow. Funnels are perfect for sales pipelines, conversion analysis, and onboarding steps.

echarts
chart.setOption({
  series: [{
    type: 'funnel',
    data: [
      { value: 100, name: 'Visit' },
      { value: 75, name: 'Sign Up' },
      { value: 50, name: 'Trial' },
      { value: 25, name: 'Purchase' }
    ],
    sort: 'descending'      // 'descending','ascending','none'
  }]
});

Funnel with Sort & Gap

sort: 'ascending' inverts the funnel (smallest at top, like a growth chart). gap separates slices for readability. funnelAlign positions slices horizontally. minSize/maxSize bound the slice widths as percentages, ensuring tiny stages stay visible.

echarts
chart.setOption({
  series: [{
    type: 'funnel',
    data: data,
    sort: 'ascending',          // smallest at top
    gap: 4,                     // pixel gap between slices
    funnelAlign: 'center',      // 'left','center','right'
    width: '60%',
    minSize: '20%',
    maxSize: '100%'
  }]
});

Funnel Labels

position: 'inside' overlays labels on slices; 'left'/'right' places them outside with connector lines (labelLine). formatter: '{b}: {c}' shows name and value. Use outside labels when slices are too thin for inside text. Emphasis enlarges the label on hover.

echarts
chart.setOption({
  series: [{
    type: 'funnel',
    data: data,
    label: {
      show: true,
      position: 'inside',      // 'inside','left','right'
      formatter: '{b}: {c}'
    },
    labelLine: {
      show: true,
      length: 20,
      lineStyle: { width: 1, type: 'solid' }
    },
    emphasis: {
      label: { fontSize: 16 }
    }
  }]
});

Funnel Item Style

Per-slice itemStyle overrides the default color cycle. borderColor separates slices visually. You can also set color on individual data items. For a polished look, use a sequential color palette (lighter for early stages, darker for converted) to reinforce the funnel metaphor.

echarts
chart.setOption({
  series: [{
    type: 'funnel',
    data: [
      { value: 100, name: 'A', itemStyle: { color: '#5470c6' } },
      { value: 75, name: 'B', itemStyle: { color: '#91cc75' } },
      { value: 50, name: 'C', itemStyle: { color: '#fac858' } }
    ],
    itemStyle: {
      borderColor: '#fff',
      borderWidth: 2,
      borderRadius: 0
    }
  }]
});

Comparison Funnel

Multiple funnel series can sit side-by-side for period comparison. Give each series its own left/width to position them. This is great for A/B test visualization or year-over-year conversion comparison. Use contrasting colors per series to distinguish them.

echarts
chart.setOption({
  series: [
    {
      type: 'funnel',
      name: '2023',
      data: [{ value: 100, name: 'A' }, { value: 40, name: 'B' }],
      sort: 'descending',
      left: '5%', width: '40%',
      label: { position: 'inside' }
    },
    {
      type: 'funnel',
      name: '2024',
      data: [{ value: 120, name: 'A' }, { value: 60, name: 'B' }],
      sort: 'descending',
      left: '55%', width: '40%',
      label: { position: 'inside' }
    }
  ]
});
12

Gauge Charts

Basic Gauge

A gauge shows a single value on an arc. min/max set the scale. progress shows a colored arc up to the value (with axisLine as the track). detail renders the value text in the center. valueAnimation smoothly transitions the number. Great for KPIs and single-metric dashboards.

echarts
chart.setOption({
  series: [{
    type: 'gauge',
    min: 0,
    max: 100,
    progress: { show: true, width: 18 },
    axisLine: { lineStyle: { width: 18 } },
    detail: {
      valueAnimation: true,
      formatter: '{value}%'
    },
    data: [{ value: 70, name: 'Score' }]
  }]
});

Gauge with Pointer

The pointer style is the classic gauge look. anchor is the center pin. Negative distance values push ticks/labels inward (toward center). radius scales the whole gauge. Combine pointer with splitLine to mimic a physical instrument. Useful when you want an analog feel.

echarts
chart.setOption({
  series: [{
    type: 'gauge',
    radius: '60%',
    min: 0, max: 100,
    pointer: { show: true, length: '60%', width: 5 },
    anchor: { show: true, size: 12, itemStyle: { color: '#333' } },
    axisTick: { distance: -15, length: 5 },
    splitLine: { distance: -20, length: 10 },
    axisLabel: { distance: -25 },
    data: [{ value: 42 }]
  }]
});

Gauge with Color Bands

axisLine.lineStyle.color accepts an array of [threshold, color] pairs to create colored zones (e.g. red/yellow/green for risk levels). Thresholds are fractions (0-1). This is the standard way to show 'safe/warning/danger' ranges on a gauge. The pointer or progress arc indicates the current value within these zones.

echarts
chart.setOption({
  series: [{
    type: 'gauge',
    min: 0, max: 100,
    axisLine: {
      lineStyle: {
        width: 20,
        color: [
          [0.3, '#fd666d'],    // 0-30% red
          [0.7, '#37a2da'],    // 30-70% blue
          [1, '#91cc75']       // 70-100% green
        ]
      }
    },
    data: [{ value: 85 }]
  }]
});

Multi-pointer Gauge

Multiple data entries create multiple pointers on the same gauge. Useful for comparing related metrics (CPU vs Memory vs Disk). Each value animates independently. Keep the count low (3-5 max) or the gauge becomes cluttered. Names appear as labels near each pointer.

echarts
chart.setOption({
  series: [{
    type: 'gauge',
    min: 0, max: 100,
    data: [
      { value: 60, name: 'CPU' },
      { value: 40, name: 'Memory' },
      { value: 80, name: 'Disk' }
    ],
    detail: { formatter: '{value}%' },
    title: { fontSize: 14 }
  }]
});

Custom Gauge (Round Progress)

Setting startAngle/endAngle to span 360° creates a circular progress ring (like an Apple Watch ring). Hiding pointer/ticks/labels gives a clean minimalist look. roundCap rounds the progress ends. This style is popular for modern dashboards — it's a gauge disguised as a ring.

echarts
chart.setOption({
  series: [{
    type: 'gauge',
    startAngle: 90,
    endAngle: -270,            // full circle
    pointer: { show: false },
    progress: {
      show: true,
      overlap: false,
      roundCap: true,
      clip: false
    },
    axisLine: { lineStyle: { width: 20, color: [[1, 'rgba(0,0,0,0.1)']] } },
    splitLine: { show: false },
    axisTick: { show: false },
    axisLabel: { show: false },
    detail: {
      valueAnimation: true,
      offsetCenter: ['0%', '0%'],
      fontSize: 30,
      formatter: '{value}%'
    },
    data: [{ value: 65 }]
  }]
});
13

Coordinate Systems

Multiple X Axes

xAxis is an array — each entry is a separate axis. Series bind to an axis via xAxisIndex (0-based). This lets one chart show two metrics with different scales or units. Use position to place axes on top/bottom. Common for stock charts (price + volume) or weather (temp + humidity).

echarts
chart.setOption({
  xAxis: [
    { type: 'category', data: ['A','B','C'], position: 'bottom' },
    { type: 'category', data: ['A','B','C'], position: 'top', axisLine: { onZero: false } }
  ],
  yAxis: { type: 'value' },
  series: [
    { type: 'line', data: [10, 20, 30], xAxisIndex: 0 },
    { type: 'line', data: [50, 60, 70], xAxisIndex: 1 }
  ]
});

Dual Y Axes

Two y-axes (left and right) let you plot series with different units (e.g. revenue in $ vs units sold). Each series binds to an axis via yAxisIndex. Color-code the right axis line to match its series so users know which line reads against which axis. Avoid 3+ axes — they get confusing.

echarts
chart.setOption({
  xAxis: { type: 'category', data: ['Mon','Tue','Wed','Thu'] },
  yAxis: [
    { type: 'value', name: 'Sales', position: 'left' },
    { type: 'value', name: 'Orders', position: 'right', axisLine: { lineStyle: { color: '#ee6666' } } }
  ],
  series: [
    { type: 'bar', data: [200, 180, 250, 210], yAxisIndex: 0 },
    { type: 'line', data: [40, 35, 50, 42], yAxisIndex: 1, smooth: true }
  ]
});

Polar Coordinates

Polar coordinates use angleAxis (around the circle) and radiusAxis (out from center). Series set coordinateSystem: 'polar'. startAngle: 90 puts 0° at the top (north). Polar is great for directional data (wind rose), cyclical patterns, or rose/nightingale variants.

echarts
chart.setOption({
  polar: {},
  angleAxis: {
    type: 'category',
    data: ['N','NE','E','SE','S','SW','W','NW'],
    startAngle: 90
  },
  radiusAxis: { type: 'value' },
  series: [{
    type: 'bar',
    data: [1, 2, 3, 4, 5, 6, 7, 8],
    coordinateSystem: 'polar'
  }]
});

Calendar Coordinates

The calendar coordinate system maps dates to cells. Series with coordinateSystem: 'calendar' bind to it. cellSize can be pixels or 'auto'. orient: 'horizontal' is the standard week-row layout. dayLabel/monthLabel nameMap localizes the labels. Combine with heatmap for contribution graphs.

echarts
chart.setOption({
  calendar: {
    range: ['2024-01-01', '2024-12-31'],
    cellSize: ['auto', 15],
    left: 50, right: 30,
    orient: 'horizontal',
    dayLabel: { nameMap: 'en' },
    monthLabel: { nameMap: 'en' },
    yearLabel: { show: false }
  },
  series: [{
    type: 'heatmap',
    coordinateSystem: 'calendar',
    data: calendarData
  }]
});

Parallel Coordinates

Parallel coordinates plot multi-dimensional data with one axis per dimension. Each data row becomes a polyline crossing all axes. This reveals correlations and clusters in high-dimensional data (e.g. comparing cars across price, mileage, year, safety). Useful for data exploration.

echarts
chart.setOption({
  parallelAxis: [
    { dim: 0, name: 'Price' },
    { dim: 1, name: 'Mileage' },
    { dim: 2, name: 'Year' },
    { dim: 3, name: 'Safety', type: 'category', data: ['Low','Med','High'] }
  ],
  parallel: {
    parallelAxisDefault: {
      axisLine: { lineStyle: { color: '#999' } },
      nameTextStyle: { color: '#333' }
    }
  },
  series: [{
    type: 'parallel',
    data: [[20000, 30, 2020, 'High'], [25000, 25, 2021, 'Med']]
  }]
});

Geo Map Setup

registerMap binds a GeoJSON to a name for use in geo and map series. roam enables mouse pan/zoom. itemStyle.areaColor fills regions; borderColor outlines them. emphasis styles apply on hover. Geo alone shows a map; pair with a map series to color regions by value (choropleth).

echarts
// load a map GeoJSON (must be registered before use)
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
  .then(r => r.json())
  .then(geoJson => {
    echarts.registerMap('china', geoJson);
    chart.setOption({
      geo: {
        map: 'china',
        roam: true,                  // pan & zoom
        zoom: 1.2,
        label: { show: false },
        itemStyle: {
          areaColor: '#eee',
          borderColor: '#fff'
        },
        emphasis: {
          label: { show: true },
          itemStyle: { areaColor: '#f5f5f5' }
        }
      }
    });
  });
14

Dataset

Basic Dataset

Dataset separates data from series config. The source is a 2D array (header row first). seriesLayoutBy: 'column' makes each series take a column. encode maps dataset columns to x/y. This decouples data from presentation — useful when data is shared across multiple charts.

echarts
chart.setOption({
  dataset: {
    source: [
      ['product', '2023', '2024'],
      ['Apple', 41, 56],
      ['Banana', 67, 28],
      ['Cherry', 89, 76]
    ]
  },
  xAxis: { type: 'category' },
  yAxis: {},
  series: [
    { type: 'bar', seriesLayoutBy: 'column', encode: { x: 'product', y: '2023' } },
    { type: 'bar', seriesLayoutBy: 'column', encode: { x: 'product', y: '2024' } }
  ]
});

Dataset with Object Rows

Dataset source can be an array of objects (key-value rows). dimensions optionally declares columns (useful when rows might be missing keys). encode uses dimension names instead of indices for readability. Object rows are easier to author by hand and more self-documenting.

echarts
chart.setOption({
  dataset: {
    dimensions: ['product', 'count', 'score'],
    source: [
      { product: 'Apple', count: 41, score: 90 },
      { product: 'Banana', count: 67, score: 75 },
      { product: 'Cherry', count: 89, score: 88 }
    ]
  },
  xAxis: { type: 'category' },
  yAxis: {},
  series: [
    { type: 'bar', encode: { x: 'product', y: 'count' } },
    { type: 'bar', encode: { x: 'product', y: 'score' } }
  ]
});

Dataset Transform (Filter/Sort)

Transforms chain datasets: filter removes rows, sort orders them. Each transform reads from fromDatasetId and exposes a new dataset. Series bind via datasetId. Transforms let you derive views from one source without copying data. Supported transforms: filter, sort, and custom via registerTransform.

echarts
chart.setOption({
  dataset: [
    {
      id: 'raw',
      source: [
        { product: 'A', sales: 100 },
        { product: 'B', sales: 50 },
        { product: 'C', sales: 200 }
      ]
    },
    {
      id: 'filtered',
      fromDatasetId: 'raw',
      transform: {
        type: 'filter',
        config: { and: [{ gte: { sales: 80 } }] }
      }
    },
    {
      id: 'sorted',
      fromDatasetId: 'filtered',
      transform: { type: 'sort', config: { order: 'desc', main: 'sales' } }
    }
  ],
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', datasetId: 'sorted', encode: { x: 'product', y: 'sales' } }]
});

Dataset Encode & Dimensions

encode maps dataset columns (by index or name) to chart dimensions. encode.tooltip lists columns to show in the tooltip. Here we use columns 0/1 for position, 2 for size, 3 for color (via itemStyle). Encoding makes the same dataset reusable across different chart types.

echarts
chart.setOption({
  dataset: {
    source: [
      [10, 20, 30, 'red'],
      [15, 25, 35, 'blue'],
      [20, 30, 40, 'green']
    ]
  },
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  series: [{
    type: 'scatter',
    encode: {
      x: 0,                  // first column -> x
      y: 1,                  // second column -> y
      tooltip: [0, 1, 2]     // show these in tooltip
    },
    symbolSize: function (d) { return d[2]; }
  }]
});

Dataset with Pie

Pie charts need itemName and value mappings via encode. The same dataset could feed a bar chart (encode x:name, y:value) and a pie chart with different encodings. This is the strength of dataset: one source, multiple views. Switching chart types only changes the series type and encode.

echarts
chart.setOption({
  dataset: {
    source: [
      { name: 'Search', value: 1048 },
      { name: 'Direct', value: 735 },
      { name: 'Email', value: 580 }
    ]
  },
  series: [{
    type: 'pie',
    radius: '60%',
    encode: { itemName: 'name', value: 'value' }
  }]
});
15

VisualMap

Continuous VisualMap

Continuous visualMap maps a numeric range to color (and optionally size). inRange.color is the gradient (interpolated). calculable: true adds draggable handles for filtering. orient and left/top position it. The visualMap drives series colors — you don't set itemStyle.color manually.

echarts
chart.setOption({
  visualMap: {
    type: 'continuous',
    min: 0,
    max: 100,
    inRange: {
      color: ['#50a3ba', '#eac736', '#d94e5d'],
      symbolSize: [10, 50]
    },
    calculable: true,           // show slider handles
    orient: 'vertical',
    left: 'left', top: 'bottom'
  },
  series: [{
    type: 'scatter',
    data: [[10,20,30], [50,60,80], [80,90,95]]
  }]
});

Piecewise VisualMap

Piecewise visualMap bins values into discrete ranges, each with its own color. pieces defines the bins (min/max/label/color). This is clearer than a gradient when you want categorical buckets (e.g. low/medium/high risk). Useful for choropleth maps and categorized scatter plots.

echarts
chart.setOption({
  visualMap: {
    type: 'piecewise',
    pieces: [
      { min: 0, max: 30, label: 'Low', color: '#91cc75' },
      { min: 30, max: 70, label: 'Mid', color: '#fac858' },
      { min: 70, max: 100, label: 'High', color: '#ee6666' }
    ],
    orient: 'horizontal',
    left: 'center', bottom: 10
  },
  series: [{
    type: 'scatter',
    data: data
  }]
});

Category VisualMap

Category visualMap maps string categories to colors. categories lists the values; inRange.color lists the matching colors in order. dimension selects which data column drives the mapping (default 0). Great when your data has a categorical attribute (e.g. priority, status) you want to color-code.

echarts
chart.setOption({
  visualMap: {
    type: 'piecewise',
    categories: ['Low', 'Medium', 'High'],
    inRange: { color: ['#91cc75', '#fac858', '#ee6666'] },
    dimension: 2                  // which data column to map
  },
  series: [{
    type: 'scatter',
    data: [
      [10, 20, 'Low'],
      [50, 60, 'Medium'],
      [80, 90, 'High']
    ]
  }]
});

VisualMap Inline & Out of Range

outOfRange styles data points outside the visualMap's selected range (e.g. greyed out when filtered). controller styles the slider itself. When a user drags the slider to filter, out-of-range points fade to outOfRange.color. This makes visualMap an interactive filter, not just a legend.

echarts
chart.setOption({
  visualMap: {
    min: 0, max: 100,
    inRange: { color: ['#5470c6', '#91cc75'] },
    outOfRange: { color: '#ccc', symbolSize: 5 },  // filtered out style
    controller: {
      inRange: { color: ['#5470c6', '#91cc75'] }
    },
    right: 10, top: 'center'
  },
  series: [{
    type: 'scatter',
    data: data
  }]
});

VisualMap on Multiple Series

By default visualMap affects all series. Use seriesIndex (number or array) to target specific series. This lets you color-code one series while leaving others unchanged — useful when comparing a highlighted dataset against a reference. A single chart can even have multiple visualMaps for different series.

echarts
chart.setOption({
  visualMap: {
    min: 0, max: 100,
    inRange: { color: ['#5470c6', '#91cc75', '#fac858'] }
  },
  series: [
    { type: 'scatter', name: 'A', data: dataA },
    { type: 'scatter', name: 'B', data: dataB }
  ]
});

// bind visualMap to specific series only
chart.setOption({
  visualMap: { seriesIndex: 1 }   // only affects second series
});
16

Legend

Basic Legend

Legend lists series names for toggling visibility. data must match series.name (or be auto-derived). icon styles the marker. Clicking a legend item toggles its series. The legend auto-updates when series are added/removed via setOption.

echarts
chart.setOption({
  legend: {
    data: ['Email', 'Search', 'Direct'],
    show: true,
    icon: 'roundRect',        // 'circle','rect','roundRect','triangle','diamond','pin','arrow'
    itemWidth: 20,
    itemHeight: 14,
    textStyle: { color: '#333', fontSize: 12 }
  },
  series: [
    { type: 'line', name: 'Email', data: [120, 200, 150] },
    { type: 'line', name: 'Search', data: [220, 180, 90] }
  ]
});

Legend Position & Layout

orient and top/left position the legend. Common layouts: top-center (default), bottom-center, right-vertical. itemGap controls spacing between legend items. A subtle background/border visually separates the legend from the chart. Position matters — bottom legends free up vertical space.

echarts
chart.setOption({
  legend: {
    orient: 'horizontal',          // 'horizontal' or 'vertical'
    top: 'top',                    // 'top','bottom','middle' or px
    left: 'center',                // 'left','center','right' or px
    itemGap: 20,                   // gap between items
    padding: 5,
    backgroundColor: '#f5f5f5',
    borderColor: '#ddd',
    borderWidth: 1,
    borderRadius: 4
  },
  series: [/* ... */]
});

Legend Selection & Default

selected controls initial visibility. selectedMode: 'single' makes the legend act like radio buttons (only one series visible). The legendselectchanged event fires on user toggles — useful for persisting preferences or syncing multiple charts. Default mode is 'multiple'.

echarts
chart.setOption({
  legend: {
    selected: {
      'Email': true,        // visible by default
      'Search': false,      // hidden by default
      'Direct': true
    },
    selectedMode: 'multiple'   // 'single' or 'multiple'
  },
  series: [
    { type: 'line', name: 'Email', data: [120, 200, 150] },
    { type: 'line', name: 'Search', data: [220, 180, 90] },
    { type: 'line', name: 'Direct', data: [100, 90, 80] }
  ]
});

chart.on('legendselectchanged', function (params) {
  console.log('Selected:', params.selected);
});

Scrollable Legend

type: 'scroll' paginates the legend when there are too many items — page buttons appear. This is essential for charts with 10+ series that would otherwise overflow. Page icon/text styles customize the navigation. Vertical scroll legends fit well in the right margin.

echarts
chart.setOption({
  legend: {
    type: 'scroll',           // 'plain' (default) or 'scroll'
    orient: 'vertical',
    right: 10, top: 20, bottom: 20,
    pageButtonItemStyle: { color: '#333' },
    pageIconColor: '#5470c6',
    pageIconInactiveColor: '#ccc',
    pageTextStyle: { color: '#333' },
    data: Array.from({length: 30}, (_, i) => 'Series ' + i)
  },
  series: [/* many series */]
});

Legend Formatter & Rich Text

formatter customizes legend labels (e.g. uppercase, add counts). rich text lets you style parts of the label differently — define styles in textStyle.rich and reference them in the formatter with {style|text} syntax. This enables legends like 'A {count|42}' with mixed styling.

echarts
chart.setOption({
  legend: {
    data: ['A', 'B'],
    formatter: function (name) {
      return name.toUpperCase();
    },
    textStyle: {
      rich: {
        a: { color: '#5470c6', fontSize: 14, fontWeight: 'bold' },
        b: { color: '#91cc75', fontSize: 12 }
      }
    }
  },
  series: [/* ... */]
});

// legend can also show values via legendselectchanged + setOption
chart.on('legendselectchanged', () => {
  // dynamic label updates
});
17

Tooltip

Basic Tooltip

trigger: 'item' shows tooltip per data point (scatter, pie). 'axis' shows it for the whole category (bar, line). axisPointer draws a guide line — 'shadow' is a translucent band (good for bars), 'line' is a thin line (good for line charts), 'cross' shows both x and y lines.

echarts
chart.setOption({
  tooltip: {
    trigger: 'axis',           // 'item','axis','none'
    show: true,
    backgroundColor: 'rgba(50,50,50,0.9)',
    borderColor: '#333',
    borderWidth: 1,
    padding: 10,
    textStyle: { color: '#fff', fontSize: 13 },
    axisPointer: { type: 'shadow' }   // 'line','shadow','cross'
  },
  xAxis: { type: 'category', data: ['A','B','C'] },
  yAxis: { type: 'value' },
  series: [{ type: 'bar', data: [10, 20, 30] }]
});

Tooltip Formatter

formatter customizes tooltip content. A function receives params (with name, value, seriesName, color, etc.) and returns HTML. String templates use {a} (series name), {b} (category/x), {c} (value), {d} (pie percentage). For multi-series axis tooltips, params is an array — iterate it.

echarts
chart.setOption({
  tooltip: {
    trigger: 'item',
    formatter: function (params) {
      // params has: name, value, seriesName, color, dataIndex, ...
      return '<b>' + params.name + '</b><br/>' +
             'Value: ' + params.value + '<br/>' +
             'Series: ' + params.seriesName;
    }
  },
  series: [{ type: 'pie', data: [/* ... */] }]
});

// string template form (for axis trigger)
chart.setOption({
  tooltip: {
    trigger: 'axis',
    formatter: '{a}: {b} = {c}'   // a=series, b=category, c=value
  }
});

Tooltip Crosshairs & Axis Pointer

Top-level axisPointer.link syncs pointers across multiple charts (multi-chart dashboards) — pass xAxisIndex: 'all'. type: 'cross' shows a full crosshair with both x and y values in labels. crossStyle/lineStyle customize the guide lines. Synced pointers are essential for comparing data across stacked charts.

echarts
chart.setOption({
  tooltip: { trigger: 'axis' },
  xAxis: { type: 'category', data: ['Mon','Tue','Wed','Thu'] },
  yAxis: { type: 'value' },
  axisPointer: {
    link: [{ xAxisIndex: 'all' }],   // sync pointers across charts
    label: { backgroundColor: '#333' }
  },
  series: [{ type: 'line', data: [10, 20, 30, 40] }]
});

// per-axis pointer type
chart.setOption({
  tooltip: {
    axisPointer: {
      type: 'cross',
      crossStyle: { color: '#999' },
      lineStyle: { color: '#999', type: 'dashed' }
    }
  }
});

Tooltip Trigger Item

trigger: 'item' shows the tooltip when hovering a single data point (pie slice, scatter point). This is the default for pie, scatter, radar. extraCssText adds arbitrary CSS (shadows, rounded corners) for custom styling. percent is available for pie charts. Item tooltips are precise per-point.

echarts
chart.setOption({
  tooltip: {
    trigger: 'item',               // per-point, not per-axis
    formatter: function (p) {
      return p.name + ': ' + p.value + ' (' + p.percent + '%)';
    },
    backgroundColor: 'rgba(255,255,255,0.95)',
    borderColor: '#eee',
    textStyle: { color: '#333' },
    extraCssText: 'box-shadow: 0 2px 10px rgba(0,0,0,0.1);'
  },
  series: [{
    type: 'pie',
    data: [{ value: 60, name: 'A' }, { value: 40, name: 'B' }]
  }]
});

Tooltip with Rich Content

For axis tooltips with multiple series, params is an array. Iterate it to build a rich HTML table with color markers, values, and formatting. This is how you build professional tooltips with alignment, totals, or units. Returning HTML gives full styling control via inline CSS.

echarts
chart.setOption({
  tooltip: {
    trigger: 'axis',
    axisPointer: { type: 'shadow' },
    formatter: function (params) {
      let html = '<div style="font-weight:bold;margin-bottom:4px;">'
        + params[0].name + '</div>';
      params.forEach(p => {
        html += '<div style="display:flex;align-items:center;">'
          + '<span style="display:inline-block;width:10px;height:10px;background:'
          + p.color + ';margin-right:6px;"></span>'
          + p.seriesName + ': ' + p.value
          + '</div>';
      });
      return html;
    }
  },
  series: [
    { type: 'bar', name: 'A', data: [10, 20, 30] },
    { type: 'bar', name: 'B', data: [15, 25, 35] }
  ]
});
18

Toolbox

Toolbox Features

Toolbox adds action icons (top-right by default). dataZoom lets users drag-select to zoom. dataView shows raw data (editable if readOnly: false). magicType switches chart type (line/bar). restore resets. saveAsImage exports PNG/SVG. Each feature has its own config.

echarts
chart.setOption({
  toolbox: {
    show: true,
    right: 10, top: 10,
    feature: {
      dataZoom: { yAxisIndex: 'none' },
      dataView: { readOnly: false, title: 'Data', lang: ['Data','Close','Refresh'] },
      magicType: { type: ['line','bar','stack','tiled'] },
      restore: {},
      saveAsImage: { pixelRatio: 2, name: 'chart', type: 'png' }
    }
  },
  series: [{ type: 'bar', data: [10, 20, 30] }]
});

Data Zoom via Toolbox

Toolbox dataZoom adds 'zoom in/out' buttons for drag-select. Combine with dataZoom components: 'inside' (mouse/touch gestures) and 'slider' (a draggable bar). yAxisIndex: 'none' restricts zoom to x. For time series with thousands of points, dataZoom is essential for navigation.

echarts
chart.setOption({
  toolbox: {
    feature: {
      dataZoom: {
        yAxisIndex: 'none',    // only zoom x axis
        title: { zoom: 'Zoom In', back: 'Zoom Out' }
      }
    }
  },
  dataZoom: [
    { type: 'inside', xAxisIndex: 0 },   // mouse wheel
    { type: 'slider', xAxisIndex: 0 }    // slider below chart
  ],
  xAxis: { type: 'category', data: longData },
  series: [{ type: 'line', data: longData }]
});

Data View (Edit Raw Data)

dataView shows the chart's underlying data. readOnly: false lets users edit and re-render. optionToContent/contentToOption let you fully customize the view (e.g. an HTML table instead of JSON). Useful for debugging or letting advanced users tweak data. Edits trigger a re-render.

echarts
chart.setOption({
  toolbox: {
    feature: {
      dataView: {
        readOnly: false,                  // editable
        title: 'View Data',
        lang: ['Data View', 'Close', 'Refresh'],
        optionToContent: function (opt) {
          // custom HTML rendering instead of JSON
          return '<div>Custom view</div>';
        },
        contentToOption: function (div) {
          // parse edited content back to option
          return opt;
        }
      }
    }
  }
});

Magic Type & Restore

magicType lets users switch between line/bar and stacked/tiled layouts at runtime — ECharts handles the conversion. restore reverts all toolbox changes to the original option. The magicTypeChanged event lets you react to type switches (e.g. update labels). Great for exploration without extra code.

echarts
chart.setOption({
  toolbox: {
    feature: {
      magicType: {
        type: ['line', 'bar', 'stack', 'tiled'],
        title: { line: 'Line', bar: 'Bar', stack: 'Stack', tiled: 'Tile' }
      },
      restore: { title: 'Restore' }
    }
  },
  series: [
    { type: 'bar', name: 'A', data: [10, 20, 30] },
    { type: 'bar', name: 'B', data: [15, 25, 35] }
  ]
});

chart.on('magicTypeChanged', function (params) {
  console.log('Switched to', params.currentType);
});

Save as Image

saveAsImage exports the chart as PNG/JPG. pixelRatio: 2 doubles resolution for retina. excludeComponents removes elements (like toolbox) from the export. getDataURL returns a base64 string for programmatic download or upload. SVG renderer exports cleaner vector images when type is 'svg'.

echarts
chart.setOption({
  toolbox: {
    feature: {
      saveAsImage: {
        type: 'png',                  // 'png' or 'jpg'
        name: 'my-chart',
        pixelRatio: 2,                // higher = sharper
        backgroundColor: '#fff',
        excludeComponents: ['toolbox'],
        title: 'Download'
      }
    }
  }
});

// programmatic export
chart.getDataURL({
  type: 'png',
  pixelRatio: 2,
  backgroundColor: '#fff'
});
19

Marks (MarkPoint / MarkLine / MarkArea)

MarkPoint (Highlight Points)

markPoint draws attention to specific points. Built-in types: 'max', 'min', 'average'. You can also specify coord: [x, y] for custom points. symbolSize scales the marker. MarkPoints float above the series — they don't affect axis scaling. Useful for calling out extremes or events.

echarts
chart.setOption({
  series: [{
    type: 'line',
    data: [10, 50, 30, 80, 20, 90],
    markPoint: {
      symbolSize: 50,
      data: [
        { type: 'max', name: 'Peak' },
        { type: 'min', name: 'Low' },
        { type: 'average', name: 'Avg' }
      ],
      label: { fontSize: 12 }
    }
  }]
});

MarkLine (Reference Lines)

markLine draws reference lines. type: 'average' draws a horizontal line at the mean. { yAxis: 60 } draws a custom horizontal line (thresholds, targets). { xAxis: 'Wed' } draws a vertical line (event markers). symbol: 'none' removes end arrows for a cleaner look.

echarts
chart.setOption({
  series: [{
    type: 'bar',
    data: [10, 50, 30, 80, 20],
    markLine: {
      symbol: 'none',              // no end arrows
      lineStyle: { type: 'dashed', color: '#ee6666' },
      data: [
        { type: 'average', name: 'Avg' },
        { yAxis: 60, name: 'Threshold' },          // horizontal line at y=60
        { xAxis: 'Wed', name: 'Event' }            // vertical line at category
      ],
      label: { formatter: '{b}: {c}' }
    }
  }]
});

MarkArea (Highlight Regions)

markArea shades a region of the chart. data is an array of [start, end] pairs — each pair defines a rectangle by coord (xAxis/yAxis values). Useful for highlighting business hours, weekends, recessions, or any span of interest. silent: false makes it respond to hover events.

echarts
chart.setOption({
  series: [{
    type: 'line',
    data: [10, 20, 30, 40, 50, 60, 70],
    markArea: {
      silent: false,
      itemStyle: { color: 'rgba(255, 200, 0, 0.2)' },
      data: [
        [
          { xAxis: 'Tue' },          // start
          { xAxis: 'Thu' }           // end
        ],
        [
          { xAxis: 'Fri' },
          { xAxis: 'Sat' }
        ]
      ],
      label: { show: true, position: 'top' }
    }
  }]
});

Marks Combined

Combine markPoint, markLine, and markArea on one series. A typical analysis chart highlights the peak (markPoint), shows the average and target (markLine), and shades a notable period (markArea). Each mark has independent styling. Don't overdo it — too many marks clutter the chart.

echarts
chart.setOption({
  series: [{
    type: 'line',
    data: [20, 50, 30, 80, 60, 90, 40],
    markPoint: {
      data: [{ type: 'max', name: 'Max' }]
    },
    markLine: {
      data: [
        { type: 'average', name: 'Average' },
        { yAxis: 70, name: 'Target', lineStyle: { color: '#91cc75' } }
      ]
    },
    markArea: {
      data: [[
        { xAxis: 'Wed' },
        { xAxis: 'Fri', itemStyle: { color: 'rgba(145,204,117,0.1)' } }
      ]]
    }
  }]
});

Mark with Custom Coordinates

For custom positions, use coord: [x, y] instead of built-in types. markLine with custom coords takes an array of two coord objects (start and end) — you can draw arbitrary lines (diagonals, trend lines from regression). symbol: 'pin' changes the markPoint shape. This enables annotations on specific data points.

echarts
chart.setOption({
  series: [{
    type: 'scatter',
    data: [[10,20], [50,60], [80,90]],
    markPoint: {
      data: [
        { coord: [50, 60], name: 'Center', value: 'Origin' }
      ],
      symbol: 'pin',
      symbolSize: 40,
      itemStyle: { color: '#ee6666' }
    },
    markLine: {
      data: [
        [{ coord: [0, 0] }, { coord: [100, 100] }]  // diagonal line
      ]
    }
  }]
});
20

Animation & Interaction

Animation Options

Globally control animation. animationDuration is the entrance animation length. Easing names include 'linear','cubicOut','elasticOut','bounceOut'. animationDelay as a function staggers items (idx * 100 makes each bar appear 100ms after the previous). For large datasets, animationThreshold auto-disables animation to stay performant.

echarts
chart.setOption({
  animation: true,
  animationThreshold: 2000,        // disable above this data count
  animationDuration: 2000,         // entrance duration (ms)
  animationEasing: 'cubicOut',     // easing function
  animationDelay: function (idx) { // stagger by index
    return idx * 100;
  },
  animationDurationUpdate: 500,    // update transition
  animationEasingUpdate: 'cubicInOut',
  animationDelayUpdate: 0,
  series: [{ type: 'bar', data: [10, 20, 30, 40] }]
});

Easing Functions

ECharts supports 30+ easing functions. 'cubicOut' (default) is a natural deceleration. 'elasticOut' and 'bounceOut' add playful overshoot. 'sinusoidalInOut' is smooth and neutral. For data viz, prefer subtle easings (cubic, sinusoidal) — bouncy animations distract from the data. Match easing to your brand personality.

echarts
chart.setOption({
  animationEasing: 'elasticOut',
  // available easings:
  // linear, quadraticIn, quadraticOut, quadraticInOut,
  // cubicIn, cubicOut, cubicInOut,
  // quarticIn, quarticOut, quarticInOut,
  // quinticIn, quinticOut, quinticInOut,
  // sinusoidalIn, sinusoidalOut, sinusoidalInOut,
  // exponentialIn, exponentialOut, exponentialInOut,
  // circularIn, circularOut, circularInOut,
  // elasticIn, elasticOut, elasticInOut,
  // backIn, backOut, backInOut,
  // bounceIn, bounceOut, bounceInOut
  series: [{ type: 'bar', data: [10, 20, 30] }]
});

Loading Animation

showLoading displays a spinner overlay while fetching data. Call hideLoading once data is ready. This is the standard async-data pattern — show loading, fetch, hide loading, setOption. Customize the spinner color and message to match your app. The mask prevents user interaction during load.

echarts
// show loading mask
chart.showLoading({
  text: 'Loading data...',
  color: '#5470c6',
  textColor: '#333',
  maskColor: 'rgba(255, 255, 255, 0.8)',
  zlevel: 0,
  fontSize: 14,
  showSpinner: true,
  spinnerRadius: 10,
  lineWidth: 2
});

// hide after data loads
fetch('/api/data').then(r => r.json()).then(data => {
  chart.hideLoading();
  chart.setOption({ series: [{ type: 'bar', data: data }] });
});

Events API

chart.on binds event handlers. Common events: click, dblclick, mouseover, legendselectchanged, datazoom, pieselectchanged. params carries component info. dispatchAction triggers actions (highlight, showTip, dataZoom) — useful for syncing external UI with the chart or programmatically showing tooltips.

echarts
chart.on('click', function (params) {
  console.log('Clicked:', params.componentType, params.seriesType);
  console.log('Series:', params.seriesName, 'Data:', params.name, params.value);
  console.log(' dataIndex:', params.dataIndex);
});

chart.on('legendselectchanged', function (params) {
  console.log('Legend toggled:', params.selected);
});

chart.on('datazoom', function (params) {
  console.log('Zoom:', params.batch?.[0]?.start, params.batch?.[0]?.end);
});

// dispatch an action programmatically
chart.dispatchAction({
  type: 'highlight',
  seriesIndex: 0,
  dataIndex: 2
});

chart.dispatchAction({ type: 'showTip', x: 100, y: 100 });

Graphic Elements (Custom Shapes)

graphic lets you overlay custom shapes (text, circles, rects, images) on the chart — useful for watermarks, empty-state messages, or annotations. Elements support positioning (left/top/right/bottom as px or %), styling, and events. They render above or below the chart based on z. This is the escape hatch when standard options aren't enough.

echarts
chart.setOption({
  graphic: {
    elements: [
      {
        type: 'text',
        left: 'center', top: 'middle',
        style: { text: 'No Data', fontSize: 24, fill: '#999' },
        invisible: false
      },
      {
        type: 'circle',
        shape: { cx: 50, cy: 50, r: 20 },
        style: { fill: '#5470c6' },
        onclick: function () { console.log('clicked'); }
      },
      {
        type: 'image',
        style: { image: 'logo.png', width: 100, height: 40 },
        left: 10, top: 10
      }
    ]
  }
});

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.