不用画图板也能做出专业图表 Echarts教程文档大全 从配置项到高级功能全掌握
大家好,今天我们来聊聊一个超级实用的工具——ECharts。如果你曾经为了做一张漂亮的图表翻遍各种设计软件,或者对着Excel的图表功能抓狂,那这篇文章就是为你准备的。
一、什么是ECharts?它凭什么这么火?
ECharts是百度开源的一个纯JavaScript图表库,自从2013年发布以来,迅速成为中国数据可视化领域最受欢迎的工具之一。它的流行不是没有原因的:
开源免费,这点就不用多说了,企业项目用完全没有版权顾虑。
功能极其全面,支持柱状图、折线图、饼图、散点图、K线图、地图、热力图、关系图、仪表盘、漏斗图、矩形树图等二十几种图表类型,而且还在持续更新。
性能好得惊人。ECharts底层是基于ZRender这个轻量级Canvas矢量图形库,对于普通的数据量,渲染速度非常流畅,即便是几十万条数据点也能hold住。
文档堪称业界标杆。官方文档写得非常细致,配置项说明清晰,每个参数都有示例,对新手极其友好。
跨平台兼容。它可以在PC端和移动端流畅运行,还支持各种主流的浏览器,甚至连IE8+都没问题。
简单来说,ECharts就像是程序员的数据可视化瑞士军刀——小巧、灵活、什么都能切。
二、环境搭建:三步让ECharts跑起来
2.1 引入ECharts
这是最简单的入门方式,通过CDN直接引入:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ECharts示例</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<div id="main" style="width: 800px;height:500px;"></div>
<script>
// 在这里写你的图表配置
</script>
</body>
</html>
如果你想用最新版本,可以把版本号换成latest,或者去官网下载。
2.2 通过npm安装
对于有构建工具(比如Vite、Webpack)的项目,用npm安装更方便:
npm install echarts
然后在项目里引入:
// 完全引入
import * as echarts from 'echarts';
// 按需引入(推荐,能减小打包体积)
import * as echarts from 'echarts/core';
import { BarChart, LineChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent
} from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
BarChart,
LineChart,
CanvasRenderer
]);
按需引入的好处很明显——你只需要打包用到的图表和组件,体积能缩小很多。
2.3 在框架中使用
如果你用的是React、Vue或Angular,ECharts都有专门的封装库:
- Vue:
vue-echarts,用法和原生ECharts几乎一样 - React:
echarts-for-react,以组件方式使用 - Angular:
ngx-echarts
这些封装库让你可以在组件的生命周期里更方便地管理图表实例。
三、第一个图表:柱状图
现在我们来做一个最基础的柱状图。假设你要展示某公司过去六个月的销售额。
// 初始化echarts实例
// 注意:这里用的是我们之前引入的echarts
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
// 配置项
var option = {
// 标题
title: {
text: '公司近半年销售额统计',
subtext: '单位:万元',
left: 'center'
},
// 提示框组件
tooltip: {
trigger: 'axis',
// 自定义提示框内容
formatter: function(params) {
return params[0].name + '<br/>' +
params[0].seriesName + ':' + params[0].value + ' 万元';
}
},
// 图例
legend: {
data: ['销售额'],
top: '10%'
},
// X轴
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月'],
axisLabel: {
// 设置X轴标签样式
color: '#666',
fontSize: 14
}
},
// Y轴
yAxis: {
type: 'value',
name: '金额(万元)',
// 添加分割线让图表更清晰
splitLine: {
lineStyle: {
type: 'dashed'
}
}
},
// 系列列表
series: [{
name: '销售额',
type: 'bar',
data: [820, 932, 901, 934, 1290, 1330],
// 柱状图的样式
itemStyle: {
color: '#5470c6',
// 圆角
borderRadius: [4, 4, 0, 0]
},
// 在柱子上显示数值
label: {
show: true,
position: 'top'
}
}]
};
// 使用配置项显示图表
myChart.setOption(option);
这段代码执行后,你会看到一个美观的柱状图,鼠标悬停在柱子上会显示详细数据。
3.1 让图表自适应窗口大小
很多新手会遇到这个问题:图表在固定大小的容器里显示没问题,但浏览器窗口缩放后图表不会跟着变化。解决办法很简单:
// 监听窗口大小变化
window.addEventListener('resize', function() {
myChart.resize();
});
这样每次窗口大小改变时,图表都会自动调整尺寸。
四、折线图:展示趋势的好帮手
折线图适合展示数据随时间变化的趋势。我们来做一个多系列折线图,展示三个产品过去一年的销售对比。
var option = {
title: {
text: '三款产品年度销售趋势对比',
left: 'center'
},
tooltip: {
trigger: 'axis',
// 十字准星指示器
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['产品A', '产品B', '产品C'],
top: '10%'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月',
'7月', '8月', '9月', '10月', '11月', '12月']
},
yAxis: {
type: 'value',
name: '销量(件)'
},
series: [
{
name: '产品A',
type: 'line',
// 平滑曲线
smooth: true,
// 填充区域
areaStyle: {
opacity: 0.3
},
data: [120, 132, 101, 134, 90, 230, 210, 180, 150, 200, 220, 250],
itemStyle: {
color: '#5470c6'
}
},
{
name: '产品B',
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.3
},
data: [220, 182, 191, 234, 290, 330, 310, 280, 250, 300, 320, 350],
itemStyle: {
color: '#91cc75'
}
},
{
name: '产品C',
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.3
},
data: [150, 232, 201, 154, 190, 330, 410, 380, 350, 400, 420, 450],
itemStyle: {
color: '#fac858'
}
}
]
};
几个关键点:
smooth: true让折线变成平滑曲线,看起来更柔和areaStyle给折线下方填充颜色,能让趋势更直观boundaryGap: false让折线从X轴的刻度开始,而不是在刻度之间
五、饼图:占比一目了然
饼图适合展示各部分占总体的比例。我们来做一个公司产品线营收占比的饼图。
var option = {
title: {
text: '公司产品线营收占比',
subtext: '2024年度数据',
left: 'center'
},
tooltip: {
trigger: 'item',
// 自定义格式化,显示百分比
formatter: '{b}: {c}万元 ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
series: [
{
name: '营收占比',
type: 'pie',
// 饼图半径
radius: ['40%', '70%'],
// 做成环形图
center: ['50%', '50%'],
// 不显示圆角
roseType: 'area',
itemStyle: {
borderRadius: 8
},
data: [
{ value: 1048, name: '电子产品' },
{ value: 735, name: '服装鞋帽' },
{ value: 580, name: '食品饮料' },
{ value: 484, name: '家居用品' },
{ value: 300, name: '图书文具' }
],
// 标签配置
label: {
show: true,
formatter: '{b}\n{d}%'
},
// 高亮样式
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
这里的饼图做成了环形图的样式,中间留白可以放文字说明,视觉效果更好。
六、散点图:发现数据关联
散点图适合展示两个变量之间的关系,比如身高和体重的关系、广告投入和销售额的关系等。
var option = {
title: {
text: '广告投入与销售额关系分析',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return '广告投入:' + params.value[0] + '万元<br/>' +
'销售额:' + params.value[1] + '万元';
}
},
xAxis: {
type: 'value',
name: '广告投入(万元)',
min: 0,
max: 100
},
yAxis: {
type: 'value',
name: '销售额(万元)',
min: 0,
max: 500
},
series: [{
type: 'scatter',
symbolSize: function(data) {
// 根据利润大小调整气泡大小
return data[2] * 2;
},
data: [
[10, 80, 5],
[20, 150, 12],
[30, 220, 18],
[40, 300, 25],
[50, 380, 30],
[60, 420, 35],
[70, 450, 40],
[80, 480, 45],
[90, 490, 48],
[100, 500, 50],
[15, 100, 8],
[25, 180, 15],
[35, 250, 20],
[45, 320, 28],
[55, 400, 32],
[65, 440, 38],
[75, 470, 42],
[85, 495, 47],
[95, 500, 49]
],
// 气泡颜色根据利润映射
itemStyle: {
color: function(params) {
var colorList = [
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de'
];
return colorList[params.dataIndex % colorList.length];
}
}
}]
};
这个散点图里,气泡的大小代表了第三个维度的数据(利润),气泡颜色也做了区分。这种多维数据的可视化方式让信息量更丰富。
七、地图:地域数据的最佳展示方式
ECharts支持各种地图,包括中国地图、世界地图、省份地图等。
7.1 中国地图示例
// 注册地图数据(从GeoJSON获取)
// 实际使用时你需要引入china.js或者动态加载GeoJSON
// echarts.registerMap('china', chinaGeoJson);
var option = {
title: {
text: '2024年各省份GDP分布',
subtext: '单位:万亿元',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>GDP:{c} 万亿元'
},
// 视觉映射组件,根据数值大小显示不同颜色
visualMap: {
min: 0,
max: 12,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true,
inRange: {
color: ['#e0f3f8', '#abd9e9', '#74a9d6', '#2b8cbe', '#045a8d']
},
textStyle: {
color: '#333'
}
},
series: [
{
name: 'GDP',
type: 'map',
map: 'china',
roam: true, // 支持鼠标缩放和平移
zoom: 1.2, // 初始缩放级别
label: {
show: true,
color: '#333',
fontSize: 10
},
// 高亮状态
emphasis: {
label: {
color: '#fff',
fontSize: 12
},
itemStyle: {
areaColor: '#ff7f50',
shadowBlur: 10,
shadowColor: 'rgba(0,0,0,0.5)'
}
},
data: [
{ name: '广东', value: 12.9 },
{ name: '江苏', value: 11.6 },
{ name: '山东', value: 9.2 },
{ name: '浙江', value: 8.3 },
{ name: '河南', value: 6.5 },
{ name: '四川', value: 5.7 },
{ name: '湖北', value: 5.4 },
{ name: '福建', value: 5.3 },
{ name: '湖南', value: 4.9 },
{ name: '安徽', value: 4.7 },
{ name: '上海', value: 4.5 },
{ name: '北京', value: 4.2 },
{ name: '河北', value: 4.1 },
{ name: '陕西', value: 3.3 },
{ name: '江西', value: 3.0 }
]
}
]
};
7.2 动态加载地图数据
如果你不想在代码里硬编码地图数据,可以从外部GeoJSON文件动态加载:
// 动态获取并注册地图
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
.then(response => response.json())
.then(json => {
echarts.registerMap('china', json);
myChart.setOption(option);
});
八、高级功能:让图表更专业
8.1 数据堆积柱状图
var option = {
title: { text: '年度各季度营收构成' },
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { data: ['Q1', 'Q2', 'Q3', 'Q4'] },
xAxis: { type: 'category', data: ['2021', '2022', '2023'] },
yAxis: { type: 'value', name: '营收(亿元)' },
series: [
{
name: 'Q1',
type: 'bar',
stack: 'total', // 堆叠关键:设置相同的stack名称
data: [320, 332, 301],
itemStyle: { color: '#5470c6' }
},
{
name: 'Q2',
type: 'bar',
stack: 'total',
data: [360, 380, 350],
itemStyle: { color: '#91cc75' }
},
{
name: 'Q3',
type: 'bar',
stack: 'total',
data: [480, 500, 470],
itemStyle: { color: '#fac858' }
},
{
name: 'Q4',
type: 'bar',
stack: 'total',
data: [520, 550, 530],
itemStyle: { color: '#ee6666' }
}
]
};
stack: 'total' 是让柱状图堆叠的关键配置。
8.2 动态数据更新
在实际项目中,图表的数据往往是动态变化的。ECharts提供了很方便的数据更新方式:
// 模拟动态数据
var data = [
{ name: '苹果', value: 120 },
{ name: '香蕉', value: 150 },
{ name: '橙子', value: 80 },
{ name: '葡萄', value: 200 },
{ name: '西瓜', value: 170 }
];
var option = {
// ... 其他配置省略
series: [{
type: 'bar',
data: data
}]
};
// 每秒更新一次数据
setInterval(function() {
// 生成新数据
data = data.map(function(item) {
return {
name: item.name,
value: Math.floor(Math.random() * 300) + 50
};
});
// 直接更新数据,不需要重新setOption整个配置
myChart.setOption({
series: [{
data: data
}]
});
}, 1000);
8.3 图表联动
当多个图表需要展示同一组数据的不同维度时,联动效果能让用户体验更好:
// 创建两个图表实例
var chart1 = echarts.init(document.getElementById('chart1'));
var chart2 = echarts.init(document.getElementById('chart2'));
// 第一个图表的配置
var option1 = {
xAxis: { type: 'category', data: ['A', 'B', 'C', 'D', 'E'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [120, 200, 150, 80, 70] }]
};
// 第二个图表的配置
var option2 = {
xAxis: { type: 'category', data: ['A', 'B', 'C', 'D', 'E'] },
yAxis: { type: 'value' },
series: [{ type: 'line', data: [220, 182, 191, 234, 290] }]
};
chart1.setOption(option1);
chart2.setOption(option2);
// 绑定联动
chart1.on('highlight', function(params) {
chart2.dispatchAction({
type: 'downplay',
seriesIndex: 0
});
chart2.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: params.dataIndex
});
chart2.setOption({
tooltip: { show: true }
});
});
chart1.on('downplay', function() {
chart2.dispatchAction({
type: 'downplay',
seriesIndex: 0
});
});
这样当鼠标在第一个图表上移动时,第二个图表会同步高亮对应的数据点。
8.4 图表导出
ECharts支持将图表导出为图片,这对于生成报告非常有用:
// 导出为PNG图片
var url = myChart.getDataURL({
type: 'png',
pixelRatio: 2, // 高DPI屏幕需要更高的像素比
backgroundColor: '#fff'
});
// 创建下载链接
var a = document.createElement('a');
a.href = url;
a.download = 'chart.png';
a.click();
九、常见坑点和解决方案
9.1 图表不显示
这个问题新手最常遇到,常见原因有:
- 容器没有设置高度——图表需要一个有明确高度的容器
#main {
width: 800px;
height: 500px;
}
- 初始化时机不对——确保DOM已经渲染完成后再初始化
// 错误:DOM还没加载完成
var myChart = echarts.init(document.getElementById('main'));
// 正确:在DOM就绪后初始化
document.addEventListener('DOMContentLoaded', function() {
var myChart = echarts.init(document.getElementById('main'));
});
9.2 图表大小异常
// 解决方法:监听窗口大小变化
window.addEventListener('resize', function() {
myChart.resize();
});
9.3 数据更新后图表没有变化
这是因为你直接修改了数据数组,但没有通知ECharts重新渲染。应该用setOption来更新:
// 错误做法
myChartOption.series[0].data.push(newData);
// ECharts不会自动检测到这个变化
// 正确做法
myChart.setOption({
series: [{
data: [...option.series[0].data, newData]
}]
});
9.4 性能问题
当数据量很大时,ECharts可能会变卡。几个优化建议:
- 开启大数据量优化
series: [{
type: 'line',
large: true, // 开启大数据量优化
largeThreshold: 2000 // 数据量超过这个值时启用优化
}]
- 按需引入,避免打包所有组件
- 使用WebGL渲染替代Canvas(适用于海量数据)
var myChart = echarts.init(chartDom, null, {
renderer: 'webgl'
});
十、实战案例:完整的数据看板
最后我们来做一个稍微复杂一点的案例,模拟一个数据看板页面:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>数据看板</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #1a1a2e;
color: #fff;
font-family: 'Microsoft YaHei', sans-serif;
padding: 20px;
}
.header {
text-align: center;
padding: 20px;
border-bottom: 1px solid #333;
margin-bottom: 20px;
}
.header h1 { font-size: 28px; color: #00d4ff; }
.dashboard {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.card {
background: #16213e;
border-radius: 10px;
padding: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.card-title {
font-size: 16px;
color: #aaa;
margin-bottom: 10px;
}
.chart {
width: 100%;
height: 300px;
}
.stat-card {
display: flex;
justify-content: space-around;
margin-top: 10px;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 28px;
color: #00d4ff;
font-weight: bold;
}
.stat-label {
font-size: 12px;
color: #888;
}
</style>
</head>
<body>
<div class="header">
<h1>📊 企业运营数据看板</h1>
</div>
<div class="dashboard">
<!-- 卡片1:销售趋势 -->
<div class="card">
<div class="card-title">📈 月度销售趋势</div>
<div id="chart1" class="chart"></div>
</div>
<!-- 卡片2:产品占比 -->
<div class="card">
<div class="card-title">🥧 产品营收占比</div>
<div id="chart2" class="chart"></div>
</div>
<!-- 卡片3:关键指标 -->
<div class="card">
<div class="card-title">📊 关键运营指标</div>
<div class="stat-card">
<div class="stat-item">
<div class="stat-value">128.5万</div>
<div class="stat-label">月销售额</div>
</div>
<div class="stat-item">
<div class="stat-value">3,842</div>
<div class="stat-label">订单数</div>
</div>
<div class="stat-item">
<div class="stat-value">67.8%</div>
<div class="stat-label">复购率</div>
</div>
</div>
</div>
<!-- 卡片4:用户增长 -->
<div class="card">
<div class="card-title">👥 用户增长趋势</div>
<div id="chart3" class="chart"></div>
</div>
</div>
<script>
// 图表1:销售趋势折线图
var chart1 = echarts.init(document.getElementById('chart1'));
chart1.setOption({
tooltip: { trigger: 'axis' },
grid: { left: '10%', right: '5%', top: '15%', bottom: '15%' },
xAxis: {
type: 'category',
data: ['1月','2月','3月','4月','5月','6月'],
axisLine: { lineStyle: { color: '#555' } },
axisLabel: { color: '#aaa' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#555' } },
axisLabel: { color: '#aaa' },
splitLine: { lineStyle: { color: '#333' } }
},
series: [{
type: 'line',
data: [820, 932, 901, 934, 1290, 1330],
smooth: true,
areaStyle: { opacity: 0.3 },
itemStyle: { color: '#00d4ff' },
lineStyle: { width: 3 }
}]
});
// 图表2:产品占比环形图
var chart2 = echarts.init(document.getElementById('chart2'));
chart2.setOption({
tooltip: { trigger: 'item', formatter: '{b}: {d}%' },
legend: {
orient: 'vertical',
right: '5%',
top: 'center',
textStyle: { color: '#aaa' }
},
series: [{
type: 'pie',
radius: ['40%', '70%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#16213e',
borderWidth: 2
},
label: { show: false },
emphasis: {
label: { show: true, fontSize: 16, fontWeight: 'bold', color: '#fff' }
},
data: [
{ value: 35, name: '电子产品', itemStyle: { color: '#5470c6' } },
{ value: 25, name: '服装鞋帽', itemStyle: { color: '#91cc75' } },
{ value: 20, name: '食品饮料', itemStyle: { color: '#fac858' } },
{ value: 12, name: '家居用品', itemStyle: { color: '#ee6666' } },
{ value: 8, name: '其他', itemStyle: { color: '#73c0de' } }
]
}]
});
// 图表3:用户增长柱状图
var chart3 = echarts.init(document.getElementById('chart3'));
chart3.setOption({
tooltip: { trigger: 'axis' },
grid: { left: '10%', right: '5%', top: '15%', bottom: '15%' },
xAxis: {
type: 'category',
data: ['1月','2月','3月','4月','5月','6月'],
axisLine: { lineStyle: { color: '#555' } },
axisLabel: { color: '#aaa' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#555' } },
axisLabel: { color: '#aaa' },
splitLine: { lineStyle: { color: '#333' } }
},
series: [{
type: 'bar',
data: [1200, 1320, 1510, 1640, 1890, 2130],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
]),
borderRadius: [4, 4, 0, 0]
}
}]
});
// 响应式
window.addEventListener('resize', function() {
chart1.resize();
chart2.resize();
chart3.resize();
});
</script>
</body>
</html>
十一、进阶学习路线
如果你觉得上面的内容还不够,这里给你推荐一些进阶方向:
- 深入阅读官方文档 —— echarts.apache.org 上的文档非常详细,每个配置项都有示例
- 学习数据可视化设计原则 —— 好的图表不仅要能用,还要好看、易读
- 探索ECharts GL —— 如果需要3D图表,ECharts GL是不错的选择
- 结合数据接口实战 —— 学完基础后,尝试对接真实的后端API,做动态数据可视化
结语
ECharts的学习曲线非常平缓,从入门到精通大概只需要几天的时间。它的强大之处在于灵活——你想怎么 customize 都可以,从颜色、字体到交互行为,几乎每一处都可以调整。
最重要的是,ECharts有一个活跃的社区和非常完善的文档,遇到问题基本都能找到答案。
希望这篇文章能帮你快速上手ECharts。图表做好看,数据讲清楚,让数据为你的工作赋能!
