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
- 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>
- 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);
- 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
- Use Responsive Design
// Make chart responsive window.addEventListener('resize', function() { myChart.resize(); });
// Or set explicit size myChart.resize({ width: 800, height: 600 });
- 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' } }); }
- 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);
- 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
-
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!