Create powerful interactive charts with Apache ECharts - balanced ease-of-use and customization
Apache ECharts Visualization Skill
Create stunning, interactive charts with Apache ECharts - the perfect balance of ease-of-use and extensive customization.
When to Use This Skill
Use ECharts when you need:
- Balance of ease and power - Easy to start, powerful when needed
- Broad chart variety - 20+ chart types including geo maps
- TypeScript support - Full type definitions
- Mobile responsiveness - Built-in responsive design
- Large datasets - Efficient rendering of 100k+ points
- Chinese/International - Excellent i18n support
Avoid when:
- Ultimate customization needed (use D3.js)
- Only need simple charts (use Chart.js)
- 3D scientific visualizations (use Plotly)
Core Capabilities
1. Basic Line Chart
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
</head>
<body>
<div id="main" style="width: 600px; height: 400px;"></div>
<script>
var myChart = echarts.init(document.getElementById('main'));
var option = {
title: {
text: 'Monthly Sales'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['Sales']
},
xAxis: {
type: 'category',
data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
},
yAxis: {
type: 'value'
},
series: [{
name: 'Sales',
type: 'line',
data: [120, 200, 150, 80, 70, 110],
smooth: true
}]
};
myChart.setOption(option);
</script>
</body>
</html>
2. Bar Chart with Multiple Series
var option = {
title: {
text: 'Quarterly Revenue Comparison'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['2023', '2024']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['Q1', 'Q2', 'Q3', 'Q4']
},
yAxis: {
type: 'value',
name: 'Revenue (k$)'
},
series: [
{
name: '2023',
type: 'bar',
data: [120, 200, 150, 80],
itemStyle: {
color: '#5470C6'
}
},
{
name: '2024',
type: 'bar',
data: [180, 250, 200, 120],
itemStyle: {
color: '#91CC75'
}
}
]
};
myChart.setOption(option);
3. Pie Chart with Rich Formatting
var option = {
title: {
text: 'Traffic Sources',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '50%',
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Affiliate' },
{ value: 300, name: 'Video Ads' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
myChart.setOption(option);
Complete Examples
Example 1: Loading Data from CSV
// Fetch CSV data
fetch('../data/sales.csv')
.then(response => response.text())
.then(csvText => {
// Parse CSV
const lines = csvText.trim().split('\n');
const headers = lines[0].split(',');
const categories = [];
const values = [];
for (let i = 1; i < lines.length; i++) {
const row = lines[i].split(',');
categories.push(row[0]);
values.push(parseFloat(row[1]));
}
// Create chart
var myChart = echarts.init(document.getElementById('main'));
var option = {
title: { text: 'Sales Data from CSV' },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: categories
},
yAxis: { type: 'value' },
series: [{
name: 'Sales',
type: 'line',
data: values,
smooth: true,
areaStyle: {}
}]
};
myChart.setOption(option);
});
Example 2: Multi-Axis Chart
var option = {
title: {
text: 'Temperature and Precipitation'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['Temperature', 'Precipitation']
},
xAxis: {
type: 'category',
data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
},
yAxis: [
{
type: 'value',
name: 'Temperature (°C)',
position: 'left',
axisLabel: {
formatter: '{value} °C'
}
},
{
type: 'value',
name: 'Precipitation (mm)',
position: 'right',
axisLabel: {
formatter: '{value} mm'
}
}
],
series: [
{
name: 'Temperature',
type: 'line',
yAxisIndex: 0,
data: [2, 5, 9, 15, 20, 25],
smooth: true
},
{
name: 'Precipitation',
type: 'bar',
yAxisIndex: 1,
data: [50, 45, 40, 35, 30, 25]
}
]
};
myChart.setOption(option);
Example 3: Heatmap Calendar
// Generate data for a year
function getVirtulData(year) {
const date = +echarts.time.parse(year + '-01-01');
const end = +echarts.time.parse(+year + 1 + '-01-01');
const dayTime = 3600 * 24 * 1000;
const data = [];
for (let time = date; time < end; time += dayTime) {
data.push([
echarts.time.format(time, '{yyyy}-{MM}-{dd}', false),
Math.floor(Math.random() * 10000)
]);
}
return data;
}
var option = {
title: {
text: 'Activity Heatmap Calendar'
},
tooltip: {
position: 'top',
formatter: function (p) {
return p.data[0] + ': ' + p.data[1];
}
},
visualMap: {
min: 0,
max: 10000,
calculable: true,
orient: 'horizontal',
left: 'center',
top: 'top'
},
calendar: {
range: '2024',
cellSize: ['auto', 13]
},
series: {
type: 'heatmap',
coordinateSystem: 'calendar',
data: getVirtulData('2024')
}
};
myChart.setOption(option);
Example 4: Gauge Chart
var option = {
title: {
text: 'Performance Score'
},
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
series: [
{
name: 'Score',
type: 'gauge',
progress: {
show: true
},
detail: {
valueAnimation: true,
formatter: '{value}%'
},
data: [
{
value: 85,
name: 'Overall Score'
}
]
}
]
};
myChart.setOption(option);
// Animate the value
setInterval(() => {
const newValue = Math.random() * 100;
option.series[0].data[0].value = newValue.toFixed(2);
myChart.setOption(option);
}, 2000);
Example 5: Geographic Map (China)
// Load map data
fetch('https://cdn.jsdelivr.net/npm/echarts/map/json/china.json')
.then(response => response.json())
.then(chinaJson => {
echarts.registerMap('china', chinaJson);
var option = {
title: {
text: 'Sales by Province',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c} (units)'
},
visualMap: {
min: 0,
max: 1000,
text: ['High', 'Low'],
calculable: true
},
series: [
{
name: 'Sales',
type: 'map',
map: 'china',
roam: true,
emphasis: {
label: {
show: true
}
},
data: [
{ name: 'Beijing', value: 500 },
{ name: 'Shanghai', value: 800 },
{ name: 'Guangdong', value: 900 },
{ name: 'Zhejiang', value: 700 }
]
}
]
};
myChart.setOption(option);
});
Example 6: Dynamic Real-Time Data
var data = [];
var now = new Date();
function randomData() {
now = new Date(+now + 1000);
return {
name: now.toString(),
value: [
[now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/') + ' ' +
[now.getHours(), now.getMinutes(), now.getSeconds()].join(':'),
Math.round(Math.random() * 100)
]
};
}
// Initialize with 100 points
for (var i = 0; i < 100; i++) {
data.push(randomData());
}
var option = {
title: {
text: 'Real-Time Data Stream'
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
params = params[0];
return params.value[0] + ' : ' + params.value[1];
},
axisPointer: {
animation: false
}
},
xAxis: {
type: 'time',
splitLine: {
show: false
}
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
splitLine: {
show: false
}
},
series: [
{
name: 'Value',
type: 'line',
showSymbol: false,
data: data,
smooth: true
}
]
};
myChart.setOption(option);
// Update every second
setInterval(() => {
data.shift();
data.push(randomData());
myChart.setOption({
series: [{
data: data
}]
});
}, 1000);
Best Practices
1. Use Responsive Design
// Make chart responsive
window.addEventListener('resize', function() {
myChart.resize();
});
// Or set explicit size
myChart.resize({
width: 800,
height: 600
});
2. Use Loading and Empty States
// Show loading
myChart.showLoading();
// Fetch data
fetch('../data/data.json')
.then(response => response.json())
.then(data => {
myChart.hideLoading();
myChart.setOption(option);
});
// Handle no data
if (data.length === 0) {
myChart.setOption({
title: {
text: 'No Data Available',
left: 'center',
top: 'center'
}
});
}
3. Use Themes
// Use built-in themes
var myChart = echarts.init(document.getElementById('main'), 'dark');
// Or custom theme
var customTheme = {
color: ['#c23531', '#2f4554', '#61a0a8'],
backgroundColor: '#f4f4f4'
};
var myChart = echarts.init(document.getElementById('main'), customTheme);
4. Optimize for Large Datasets
option = {
series: [{
type: 'line',
// Enable sampling for large datasets
sampling: 'lttb',
// Use progressive rendering
progressive: 1000,
progressiveThreshold: 3000,
data: largeDataArray
}]
};
Available Chart Types
Basic Charts
- Line, Bar, Pie, Scatter, Candlestick
Advanced Charts
- Radar, Heatmap, Tree, Treemap, Sunburst, Parallel, Sankey, Funnel, Gauge
Maps
- GeoMap, BMap (Baidu Maps), Google Maps
3D Charts (with GL extension)
- 3D Bar, 3D Line, 3D Scatter, 3D Surface, Globe
Graph Charts
- Graph, Force-directed Graph
TypeScript Support
import * as echarts from 'echarts';
type EChartsOption = echarts.EChartsOption;
const option: EChartsOption = {
title: {
text: 'TypeScript Example'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'line'
}
]
};
const chartDom = document.getElementById('main')!;
const myChart = echarts.init(chartDom);
myChart.setOption(option);
Installation
CDN
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
NPM
npm install echarts
import * as echarts from 'echarts';
// Or import specific modules
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import { GridComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([LineChart, GridComponent, CanvasRenderer]);
Advanced Features
Animation Configuration
option = {
animation: true,
animationDuration: 1000,
animationEasing: 'cubicOut',
animationDelay: function (idx) {
return idx * 50;
}
};
DataZoom (Zoom/Pan)
option = {
dataZoom: [
{
type: 'inside', // Mouse wheel zoom
start: 0,
end: 100
},
{
type: 'slider', // Slider zoom
start: 0,
end: 100
}
],
// ... rest of option
};
Brush Selection
option = {
brush: {
toolbox: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'],
xAxisIndex: 0
},
// ... rest of option
};
myChart.on('brushSelected', function (params) {
var brushComponent = params.batch[0];
var selected = brushComponent.selected[0].dataIndex;
console.log('Selected data indices:', selected);
});
Event Handling
// Click event
myChart.on('click', function (params) {
console.log('Clicked:', params);
alert('You clicked on ' + params.name);
});
// Hover event
myChart.on('mouseover', function (params) {
console.log('Hovered:', params);
});
// Custom events
myChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: 1
});
Integration Examples
With React
import { useEffect, useRef } from 'react';
import * as echarts from 'echarts';
function EChartsComponent({ option }) {
const chartRef = useRef(null);
const chartInstance = useRef(null);
useEffect(() => {
if (!chartInstance.current) {
chartInstance.current = echarts.init(chartRef.current);
}
chartInstance.current.setOption(option);
const handleResize = () => chartInstance.current.resize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
chartInstance.current?.dispose();
};
}, [option]);
return <div ref={chartRef} style={{ width: '100%', height: '400px' }} />;
}
With Vue
<template>
<div ref="chart" style="width: 600px; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
props: ['option'],
mounted() {
this.chart = echarts.init(this.$refs.chart);
this.chart.setOption(this.option);
window.addEventListener('resize', this.handleResize);
},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize);
this.chart.dispose();
},
methods: {
handleResize() {
this.chart.resize();
}
},
watch: {
option: {
deep: true,
handler(newOption) {
this.chart.setOption(newOption);
}
}
}
};
</script>
Resources
- Official Docs: https://echarts.apache.org/en/index.html
- Examples: https://echarts.apache.org/examples/en/index.html
- GitHub: https://github.com/apache/echarts
- Community: https://github.com/ecomfe/awesome-echarts
Performance Tips
- Use progressive rendering for >10k points
- Enable sampling for time series data
- Lazy load chart instances
- Dispose charts when unmounting
- Use Canvas renderer for large datasets
Use this skill for the best balance of ease-of-use and powerful customization!
You Might Also Like
Related Skills

verify
Use when you want to validate changes before committing, or when you need to check all React contribution requirements.
facebook
test
Use when you need to run tests for React core. Supports source, www, stable, and experimental channels.
facebook
feature-flags
Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React.
facebook
extract-errors
Use when adding new error messages to React, or seeing "unknown error code" warnings.
facebook