1. ECharts 简介
ECharts 是一个由百度开源的、功能强大的 JavaScript 可视化库,它能够帮助开发者轻松地创建交互式、美观的数据可视化图表。ECharts 支持多种图表类型,包括折线图、柱状图、饼图、散点图、地图等,并且具有高度的可定制性。
1.1 为什么选择 ECharts?
- 开源免费:完全免费,适合个人和商业项目。
- 丰富的图表类型:支持超过 20 种图表类型,满足各种数据展示需求。
- 强大的交互能力:支持数据缩放、拖拽、多图联动等交互功能。
- 良好的兼容性:兼容主流浏览器,包括 IE8+。
- 活跃的社区:拥有庞大的用户群体和丰富的文档资源。
2. 安装与引入
2.1 通过 CDN 引入(推荐初学者)
这是最简单的方式,适合快速上手和测试。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ECharts 示例</title>
<!-- 引入 ECharts 文件 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<!-- 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
2.2 通过 npm 安装(适合现代前端项目)
如果你使用 Vue、React 或 Angular 等现代前端框架,推荐使用 npm 安装。
# 安装 ECharts
npm install echarts --save
在 Vue 中使用 ECharts
<template>
<div ref="chart" style="width: 600px; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'EChartsDemo',
mounted() {
this.initChart();
},
methods: {
initChart() {
const chartDom = this.$refs.chart;
const myChart = echarts.init(chartDom);
const option = {
title: {
text: 'Vue 中使用 ECharts'
},
tooltip: {},
xAxis: {
data: ['A', 'B', 'C', 'D', 'E']
},
yAxis: {},
series: [{
name: '数据',
type: 'bar',
data: [10, 22, 15, 30, 18]
}]
};
myChart.setOption(option);
// 监听窗口大小变化,实现图表自适应
window.addEventListener('resize', () => {
myChart.resize();
});
}
}
};
</script>
在 React 中使用 ECharts
import React, { useEffect, useRef } from 'react';
import * as echarts from 'echarts';
const EChartsDemo = () => {
const chartRef = useRef(null);
const chartInstance = useRef(null);
useEffect(() =>
if (chartRef.current) {
chartInstance.current = echarts.init(chartRef.current);
const option = {
title: {
text: 'React 中使用 ECharts'
},
tooltip: {},
xAxis: {
data: ['A', 'B', 'C', 'D', 'E']
},
yAxis: {},
series: [{
name: '数据',
type: 'line',
data: [10, 22, 15, 30, 18]
}]
};
chartInstance.current.setOption(option);
// 监听窗口大小变化
const handleResize = () => {
chartInstance.current && chartInstance.current.resize();
};
window.addEventListener('resize', handleResize);
// 组件卸载时清理
return () => {
window.removeEventListener('resize', handleResize);
chartInstance.current && chartInstance.current.dispose();
};
}
}, []);
return (
<div ref={chartRef} style={{ width: '600px', height: '400px' }}></div>
);
};
export default EChartsDemo;
3. ECharts 核心概念
3.1 基本结构
ECharts 图表由以下几个核心部分组成:
- 容器(DOM):图表的挂载点,必须设置宽高。
- 实例(Instance):通过
echarts.init()创建的图表实例。 - 配置项(Option):定义图表的样式、数据和行为。
- 系列(Series):图表的数据系列,如柱状图、折线图等。
3.2 Option 配置详解
Option 是 ECharts 的核心,它是一个 JavaScript 对象,包含多个配置项:
const option = {
// 1. 标题配置
title: {
text: '主标题',
subtext: '副标题',
left: 'center', // 标题位置
textStyle: {
fontSize: 18,
color: '#333'
}
},
// 2. 提示框配置
tooltip: {
trigger: 'axis', // 触发类型:'item'(数据项触发)或 'axis'(坐标轴触发)
axisPointer: {
type: 'cross' // 指示器类型
}
},
// 3. 图例配置
legend: {
data: ['系列1', '系列2'],
top: 30,
textStyle: {
color: '#666'
}
},
// 4. 坐标轴配置
xAxis: {
type: 'category', // 类型:'value'(数值轴)、'category'(类目轴)、'time'(时间轴)、'log'(对数轴)
data: ['周一', '周二', '周三', '周四', '周五'],
axisLabel: {
interval: 0, // 强制显示所有标签
rotate: 30 // 标签旋转角度
}
},
yAxis: {
type: 'value',
name: '数值',
axisLine: {
show: true
}
},
// 5. 系列配置
series: [
{
name: '系列1',
type: 'bar', // 图表类型
data: [120, 132, 101, 134, 90],
itemStyle: {
color: '#5470c6'
},
label: {
show: true,
position: 'top'
}
},
{
name: '系列2',
type: 'line',
data: [220, 182, 191, 234, 290],
smooth: true, // 平滑曲线
lineStyle: {
width: 3
}
}
],
// 6. 工具栏配置
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {},
saveAsImage: {}
}
},
// 7. 数据区域缩放
dataZoom: [
{
type: 'slider', // 滑动条型
start: 0,
end: 100
},
{
type: 'inside' // 内置型
}
],
// 8. 网格配置
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
}
};
4. 实战图表示例
4.1 柱状图(Bar Chart)
柱状图适合展示分类数据的对比。
const barOption = {
title: {
text: '2023年各季度销售额',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['产品A', '产品B', '产品C'],
top: 30
},
xAxis: {
type: 'category',
data: ['Q1', 'Q2', 'Q3', 'Q4']
},
yAxis: {
type: 'value',
name: '销售额(万元)'
},
series: [
{
name: '产品A',
type: 'bar',
data: [120, 132, 101, 134],
itemStyle: {
color: '#5470c6'
}
},
{
name: '产品B',
type: 'bar',
data: [220, 182, 191, 234],
itemStyle: {
color: '#91cc75'
}
},
{
name: '产品C',
type: 'bar',
data: [150, 230, 224, 135],
itemStyle: {
color: '#fac858'
}
}
],
// 堆叠柱状图
// series 中的每个对象添加 stack: 'total' 属性
// series: [
// { name: '产品A', type: 'bar', stack: 'total', data: [...] },
// { name: '产品B', type: 'bar', stack: 'total', data: [...] }
// ]
};
4.2 折线图(Line Chart)
折线图适合展示数据随时间的变化趋势。
const lineOption = {
title: {
text: '2023年月度用户增长趋势',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['新增用户', '活跃用户'],
top: 30
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
},
yAxis: {
type: 'value',
name: '用户数'
},
series: [
{
name: '新增用户',
type: 'line',
data: [120, 132, 101, 134, 90, 230, 210, 200, 180, 150, 120, 100],
smooth: true,
lineStyle: {
width: 3,
color: '#5470c6'
},
areaStyle: {
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)' }
]
}
},
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
]
},
markLine: {
data: [
{ type: 'average', name: '平均值' }
]
}
},
{
name: '活跃用户',
type: 'line',
data: [80, 90, 70, 100, 120, 150, 180, 200, 220, 240, 260, 280],
smooth: true,
lineStyle: {
width: 3,
color: '#91cc75'
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(145, 204, 117, 0.5)' },
{ offset: 1, color: 'rgba(145, 204, 117, 0.05)' }
]
}
}
}
],
// 数据缩放
dataZoom: [
{
type: 'slider',
start: 0,
end: 100
}
]
};
4.3 饼图(Pie Chart)
饼图适合展示各部分占总体的比例。
const pieOption = {
title: {
text: '2023年产品市场份额',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: ['产品A', '产品B', '产品C', '产品D', '产品E']
},
series: [
{
name: '市场份额',
type: 'pie',
radius: ['40%', '70%'], // 内半径和外半径,形成环形图
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside',
formatter: '{b}: {c} ({d}%)'
},
emphasis: {
label: {
show: true,
fontSize: 16,
fontWeight: 'bold'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
labelLine: {
show: true,
length: 15,
length2: 10
},
data: [
{ value: 335, name: '产品A' },
{ value: 310, name: '产品B' },
{ value: 234, name: '产品C' },
{ value: 135, name: '产品D' },
{ value: 154, name: '产品E' }
]
}
]
};
4.4 散点图(Scatter Chart)
散点图适合展示两个变量之间的关系。
const scatterOption = {
title: {
text: '广告投入与销售额关系',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: function (params) {
return `广告投入: ${params.value[0]}万元<br/>销售额: ${params.value[1]}万元`;
}
},
xAxis: {
name: '广告投入(万元)',
nameLocation: 'middle',
nameGap: 30,
splitLine: {
show: false
}
},
yAxis: {
name: '销售额(万元)',
nameLocation: 'middle',
nameGap: 30,
splitLine: {
show: true,
lineStyle: {
type: 'dashed'
}
}
},
series: [
{
name: '数据点',
type: 'scatter',
symbolSize: function (data) {
return Math.sqrt(data[1]) * 2; // 根据销售额调整点的大小
},
itemStyle: {
color: '#5470c6',
shadowBlur: 10,
shadowColor: 'rgba(84, 112, 198, 0.5)'
},
data: [
[10, 20], [15, 30], [20, 45], [25, 50], [30, 60],
[35, 70], [40, 80], [45, 90], [50, 100], [55, 110],
[60, 120], [65, 130], [70, 140], [75, 150], [80, 160]
]
},
{
name: '趋势线',
type: 'line',
data: [
[10, 20], [80, 160]
],
lineStyle: {
type: 'dashed',
color: '#91cc75',
width: 2
},
symbol: 'none'
}
],
// 添加回归线(需要计算)
// 可以使用第三方库如 regression.js 计算线性回归
};
4.5 地图(Map)
地图需要引入相应的地图数据。
// 首先需要引入中国地图数据
// 可以通过 CDN 引入:https://cdn.jsdelivr.net/npm/echarts@5.4.3/map/js/china.js
// 或者通过 npm 安装:npm install echarts/map/js/china.js
const mapOption = {
title: {
text: '2023年各省份销售额分布',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>销售额: {c} 万元'
},
visualMap: {
min: 0,
max: 1000,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true,
inRange: {
color: ['#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
}
},
series: [
{
name: '销售额',
type: 'map',
map: 'china',
roam: true, // 开启鼠标缩放和平移
label: {
show: true,
fontSize: 10
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
},
itemStyle: {
areaColor: '#a50026'
}
},
data: [
{ name: '北京', value: 800 },
{ name: '天津', value: 300 },
{ name: '上海', value: 900 },
{ name: '重庆', value: 400 },
{ name: '河北', value: 500 },
{ name: '山西', value: 200 },
{ name: '辽宁', value: 350 },
{ name: '吉林', value: 150 },
{ name: '黑龙江', value: 100 },
{ name: '江苏', value: 700 },
{ name: '浙江', value: 650 },
{ name: '安徽', value: 450 },
{ name: '福建', value: 400 },
{ name: '江西', value: 300 },
{ name: '山东', value: 600 },
{ name: '河南', value: 550 },
{ name: '湖北', value: 500 },
{ name: '湖南', value: 450 },
{ name: '广东', value: 950 },
{ name: '海南', value: 80 },
{ name: '四川', value: 600 },
{ name: '贵州', value: 200 },
{ name: '云南', value: 250 },
{ name: '陕西', value: 400 },
{ name: '甘肃', value: 150 },
{ name: '青海', value: 50 },
{ name: '台湾', value: 300 },
{ name: '内蒙古', value: 200 },
{ name: '广西', value: 350 },
{ name: '西藏', value: 30 },
{ name: '宁夏', value: 80 },
{ name: '新疆', value: 180 },
{ name: '香港', value: 400 },
{ name: '澳门', value: 100 }
]
}
]
};
5. 常见问题解析
5.1 图表不显示或显示异常
问题描述:图表容器没有显示出来,或者显示为空白。
可能原因及解决方案:
- 容器没有设置宽高: “`html
2. **DOM 元素未加载完成**:
```javascript
// 错误:在 DOM 加载前初始化
// <script> 标签放在 <head> 中且没有等待 DOM 加载
// 正确:等待 DOM 加载完成
document.addEventListener('DOMContentLoaded', function() {
var myChart = echarts.init(document.getElementById('main'));
// ... 设置 option
});
- ECharts 文件未正确引入:
<!-- 检查路径是否正确 --> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
5.2 图表自适应问题
问题描述:窗口大小改变时,图表不能自动调整大小。
解决方案:
// 方法1:监听窗口 resize 事件
window.addEventListener('resize', function() {
myChart.resize();
});
// 方法2:使用防抖函数优化性能
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
const debouncedResize = debounce(() => myChart.resize(), 100);
window.addEventListener('resize', debouncedResize);
// 方法3:在 Vue/React 中使用生命周期钩子
// Vue 示例
mounted() {
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
},
methods: {
handleResize() {
if (this.myChart) {
this.myChart.resize();
}
}
}
5.3 数据更新问题
问题描述:数据更新后,图表没有重新渲染。
解决方案:
// 方法1:使用 setOption 更新数据
// 注意:ECharts 会自动合并配置,如果需要完全替换,可以使用第二个参数
myChart.setOption(newOption, true); // 第二个参数为 true 表示不合并,完全替换
// 方法2:先销毁再重新初始化(适用于复杂场景)
function updateChart(newData) {
// 1. 销毁旧实例
if (myChart) {
myChart.dispose();
}
// 2. 重新初始化
myChart = echarts.init(document.getElementById('main'));
// 3. 设置新配置
const newOption = {
// ... 新的配置
series: [{
data: newData
}]
};
myChart.setOption(newOption);
}
// 方法3:使用 watch 监听数据变化(Vue 示例)
watch: {
chartData: {
handler(newData) {
if (this.myChart) {
this.myChart.setOption({
series: [{
data: newData
}]
});
}
},
deep: true
}
}
5.4 内存泄漏问题
问题描述:在单页应用中,频繁创建和销毁 ECharts 实例可能导致内存泄漏。
解决方案:
// Vue 组件示例
export default {
data() {
return {
myChart: null
};
},
mounted() {
this.initChart();
},
beforeDestroy() {
// 销毁实例,释放内存
if (this.myChart) {
this.myChart.dispose();
this.myChart = null;
}
},
methods: {
initChart() {
// 检查容器是否存在
if (!this.$refs.chart) return;
// 销毁旧实例(如果有)
if (this.myChart) {
this.myChart.dispose();
}
// 创建新实例
this.myChart = echarts.init(this.$refs.chart);
// 设置配置
this.myChart.setOption(this.option);
// 监听窗口大小变化
window.addEventListener('resize', this.handleResize);
},
handleResize() {
if (this.myChart) {
this.myChart.resize();
}
}
}
};
5.5 性能优化问题
问题描述:大数据量时图表渲染缓慢或卡顿。
解决方案:
// 1. 使用渐进式渲染
const option = {
series: [{
type: 'scatter',
// 使用 large 模式优化大数据量散点图
large: true,
largeThreshold: 2000, // 超过 2000 个点时启用
progressive: 400, // 每次渲染 400 个点
progressiveThreshold: 5000 // 超过 5000 个点时启用
}]
};
// 2. 数据采样
function sampleData(data, sampleRate) {
if (data.length <= 1000) return data;
const sampled = [];
const step = Math.ceil(data.length / sampleRate);
for (let i = 0; i < data.length; i += step) {
sampled.push(data[i]);
}
return sampled;
}
// 3. 使用 WebGL 渲染(ECharts 5+ 支持)
const option = {
renderer: 'canvas', // 默认
// renderer: 'svg', // 或使用 SVG 渲染
// renderer: 'webgl', // 或使用 WebGL 渲染(需要引入 echarts-gl)
series: [{
type: 'scatter3D', // 3D 图表需要 echarts-gl
data: [...]
}]
};
// 4. 简化配置项
const simpleOption = {
// 移除不必要的动画和效果
animation: false,
// 简化 tooltip
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line'
}
},
// 简化图例
legend: {
show: false
}
};
5.6 自定义主题
问题描述:需要自定义图表颜色和样式以匹配品牌设计。
解决方案:
// 方法1:在 option 中直接配置
const customOption = {
color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de'],
textStyle: {
fontFamily: 'Arial, sans-serif',
fontSize: 12
},
// ... 其他配置
};
// 方法2:注册自定义主题
echarts.registerTheme('myTheme', {
color: ['#2c3e50', '#e74c3c', '#3498db', '#2ecc71', '#f39c12'],
backgroundColor: '#f8f9fa',
textStyle: {
fontFamily: 'Microsoft YaHei',
fontSize: 12
},
title: {
textStyle: {
color: '#2c3e50',
fontSize: 16
}
},
tooltip: {
backgroundColor: 'rgba(50, 50, 50, 0.9)',
textStyle: {
color: '#fff'
}
}
});
// 使用自定义主题
const myChart = echarts.init(document.getElementById('main'), 'myTheme');
5.7 与框架集成问题
问题描述:在 Vue、React 等框架中使用 ECharts 时遇到问题。
解决方案:
// Vue 3 Composition API 示例
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';
export default {
setup() {
const chartRef = ref(null);
const chartInstance = ref(null);
const chartData = ref([10, 20, 30, 40, 50]);
const initChart = () => {
if (!chartRef.value) return;
// 销毁旧实例
if (chartInstance.value) {
chartInstance.value.dispose();
}
// 创建新实例
chartInstance.value = echarts.init(chartRef.value);
// 设置配置
chartInstance.value.setOption({
xAxis: { type: 'category', data: ['A', 'B', 'C', 'D', 'E'] },
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: chartData.value
}]
});
// 监听窗口大小变化
window.addEventListener('resize', handleResize);
};
const handleResize = () => {
if (chartInstance.value) {
chartInstance.value.resize();
}
};
// 监听数据变化
watch(chartData, (newData) => {
if (chartInstance.value) {
chartInstance.value.setOption({
series: [{
data: newData
}]
});
}
}, { deep: true });
onMounted(() => {
// 确保 DOM 已渲染
setTimeout(initChart, 0);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
if (chartInstance.value) {
chartInstance.value.dispose();
}
});
return {
chartRef,
chartData
};
}
};
6. 进阶学习路径
6.1 官方文档学习
- 基础教程:https://echarts.apache.org/zh/tutorial.html
- API 文档:https://echarts.apache.org/zh/api.html
- 配置项手册:https://echarts.apache.org/zh/option.html
- 示例中心:https://echarts.apache.org/examples/zh/index.html
6.2 推荐学习资源
书籍:
- 《ECharts 数据可视化实战》
- 《ECharts 从入门到精通》
在线课程:
- 慕课网、极客时间等平台的 ECharts 课程
- B站上的 ECharts 教程视频
社区资源:
- ECharts GitHub Issues
- Stack Overflow 上的 ECharts 问题
- 知乎、掘金等技术社区
6.3 实战项目建议
- 个人数据仪表盘:整合多种图表展示个人数据
- 企业报表系统:开发一个完整的报表系统
- 数据大屏:制作一个数据可视化大屏
- 交互式图表:开发具有复杂交互功能的图表
7. 总结
ECharts 是一个功能强大且易于上手的数据可视化库。通过本文的学习,你应该已经掌握了:
- ECharts 的安装与引入方式
- 核心概念和配置项
- 多种图表类型的实现方法
- 常见问题的解决方案
- 性能优化和自定义主题的技巧
建议从简单的图表开始练习,逐步尝试更复杂的图表类型和交互功能。多查看官方示例和文档,积极参与社区讨论,不断提升自己的数据可视化能力。
记住,数据可视化的关键不仅在于技术实现,更在于如何通过图表清晰、准确地传达数据背后的故事。祝你学习愉快!
