从零开始学ECharts零基础入门到实战完整路线从第一个图表到商业项目手把手教你用ECharts做数据可视化新手必看含实战项目与求职指南
说实话,我第一次看到ECharts的时候,心里也是直打鼓——这玩意儿会不会很难?学它会不会又要刷一堆数学公式?结果后来才发现,ECharts其实是个”看着高大上,用起来特友好”的家伙,只要你愿意一步步来,它就能帮你把枯燥的数据变成漂亮又专业的图表,甚至成为你简历上的一份硬核技能。
为什么要选ECharts
先别急着学,咱得先搞清楚:市面上图表库那么多,为什么偏偏是它?
我见过不少小伙伴在选工具上纠结半天,什么D3.js、Chart.js、Highcharts,每个都说自己好。但如果你是真的想快速上手、做项目、找工作,ECharts是最稳的选择,原因很简单:
- 国产之光:百度开源,文档全是中文,这对咱们中文用户来说简直是福音
- 社区活跃:GitHub上4万+ Stars,遇到问题基本上百度一搜就有答案
- 图表丰富:柱状图、折线图、饼图、散点图、地图、热力图……几十种图表类型全覆盖
- 企业认可度高:国内大厂用的多,面试经常被问到
- 性能稳定:数据量大的时候也能流畅渲染
我有个朋友叫小张,去年转行做数据分析师,前前后后花了三个月系统学ECharts,现在在一个中型互联网企业做数据可视化开发,入职薪资比之前涨了将近一倍。他的原话是:”说实话,ECharts入门真的不难,关键是要有一条清晰的学习路径,不然很容易学到一半就迷茫了。”
所以今天这篇内容,我就是想帮你把这条路捋清楚。
搭建你的第一个环境
学习任何东西,第一步都是”跑起来”。咱们先从最简单的开始,你不需要安装什么复杂的开发环境,一个浏览器就够。
我推荐两种方式,新手建议从第一种开始,熟悉之后再尝试第二种。
方式一:直接使用CDN引入(最快上手)
打开你的文本编辑器(VS Code、Sublime Text都行),新建一个HTML文件,写入下面这段代码:
<!DOCTYPE html>
<html lang="zh-CN">
<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>
<style>
/* 给图表容器设置尺寸,这是很多人忽略的关键一步 */
#main {
width: 800px;
height: 500px;
margin: 50px auto;
}
</style>
</head>
<body>
<!-- 图表容器 -->
<div id="main"></div>
<script>
// 基于准备好的DOM,初始化ECharts实例
var myChart = echarts.init(document.getElementById('main'));
// 配置项
var option = {
title: {
text: '我的第一个ECharts图表'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用配置项显示图表
myChart.setOption(option);
</script>
</body>
</html>
把这段代码保存为 index.html,然后用浏览器直接打开,你就能看到第一个柱状图了。
看到这一步你可能会说:”就这?也太简单了吧。”没错,就是这么简单。但别急着翻篇,这段代码里其实藏着几个新手常踩的坑,我一个一个给你说清楚。
第一个坑:容器必须设置宽高。很多新手把div的宽高设为0或者不设,结果图表渲染出来是一片空白,排查半天都找不到原因。记住,ECharts需要一个有实际尺寸的容器来渲染。
第二个坑:必须先初始化实例再设置配置。代码里 echarts.init() 这一步不能少,它是把图表和DOM元素绑定在一起的桥梁。
第三个坑:配置项写错了不报错,只是不显示。ECharts对配置项的容错性很强,但这也是双刃剑——你写错了某个属性名,它不会报错提示你,而是直接忽略。所以建议初学者写配置项的时候多对照文档,或者用VS Code安装ECharts的智能提示插件。
深入理解配置项结构
刚才那个例子只是一个最简单的柱状图,但ECharts真正强大的地方在于它的配置项体系。理解了这个体系,你就掌握了学ECharts的核心方法论。
ECharts的配置项是一个巨大的对象,但它不是杂乱无章的,而是有固定结构的。我给你拆解一下:
{
// 标题组件
title: {
text: '主标题',
subtext: '副标题',
left: 'center' // 位置
},
// 提示框组件,鼠标悬浮时显示
tooltip: {
trigger: 'axis',
formatter: '{b}: {c}'
},
// 图例组件
legend: {
data: ['销量']
},
// 直角坐标系X轴
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
// 直角坐标系Y轴
yAxis: {
type: 'value'
},
// 系列列表,每个系列通过type决定图表类型
series: [
{
name: '销售额',
type: 'bar',
data: [120, 200, 150, 80, 70, 110, 130],
// 系列内部的详细配置
itemStyle: {
color: '#5470c6'
},
label: {
show: true,
position: 'top'
}
}
],
// 网格配置,控制直角坐标系内绘图网格
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
}
}
你看,虽然配置项很多,但逻辑非常清晰。你可以把ECharts的配置想象成搭积木——每个组件都是一块积木,你需要什么功能就放哪块积木。
我带过的学员里,很多一开始被这些配置项吓到了,觉得”这么多属性我怎么可能记得住”。其实你根本不需要背,ECharts的学习方法不是死记硬背,而是”查文档+改配置+看效果”。你只需要理解每个组件的作用,具体属性值随时去文档查就行。
说到查文档,ECharts的官方文档做得非常好,我强烈建议你把它收藏起来,学习过程中遇到不懂的直接去里面找:https://echarts.apache.org/zh/index.html
常用图表类型实战
理解配置项之后,咱们就开始实战了。我按照从易到难的顺序,给你讲几种工作中最常用的图表类型。
柱状图
柱状图是最基础的图表之一,用来比较不同类别之间的数据大小。除了刚才那个简单例子,我带你做一个更专业的:
var option = {
title: {
text: '2024年上半年各部门销售情况',
left: 'center',
textStyle: {
fontSize: 18,
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
// 自定义提示框内容
return params[0].name + '<br/>' +
params[0].seriesName + ': ' + params[0].value + '万元';
}
},
legend: {
data: ['销售部', '市场部', '运营部'],
top: 40
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['一月', '二月', '三月', '四月', '五月', '六月'],
axisLabel: {
fontSize: 12
}
},
yAxis: {
type: 'value',
name: '销售额(万元)',
nameTextStyle: {
fontSize: 12
}
},
series: [
{
name: '销售部',
type: 'bar',
data: [82, 93, 90, 85, 110, 125],
itemStyle: { color: '#5470c6' },
barWidth: '20%'
},
{
name: '市场部',
type: 'bar',
data: [62, 78, 70, 82, 95, 108],
itemStyle: { color: '#91cc75' },
barWidth: '20%'
},
{
name: '运营部',
type: 'bar',
data: [45, 55, 60, 58, 72, 80],
itemStyle: { color: '#fac858' },
barWidth: '20%'
}
]
};
这里有个小技巧:barWidth 属性可以控制柱子的宽度。默认情况下多组柱状图并排时宽度可能不太协调,手动设置一下会好看很多。
折线图
折线图适合展示数据随时间变化的趋势,比如销售额走势、气温变化等。
var option = {
title: {
text: '近一年网站访问量趋势',
left: 'center'
},
tooltip: {
trigger: 'axis',
// 显示前后几项数据
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['访问量', '新增用户']
},
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: '人数',
min: 0,
max: 5000,
axisLabel: {
formatter: '{value}'
}
},
series: [
{
name: '访问量',
type: 'line',
smooth: true, // 平滑曲线,去掉这个就是折线
data: [1200, 1350, 1800, 2100, 2500, 2800, 3200, 3500, 3100, 2900, 3400, 3800],
itemStyle: { color: '#5470c6' },
areaStyle: {
// 面积图效果,让趋势更明显
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(84, 112, 198, 0.5)' },
{ offset: 1, color: 'rgba(84, 112, 198, 0.1)' }
])
}
},
{
name: '新增用户',
type: 'line',
smooth: true,
data: [300, 420, 550, 680, 800, 950, 1100, 1250, 1050, 980, 1200, 1400],
itemStyle: { color: '#91cc75' },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(145, 204, 117, 0.5)' },
{ offset: 1, color: 'rgba(145, 204, 117, 0.1)' }
])
}
}
]
};
这段代码里用到了渐变面积图,效果非常漂亮。你要注意 echarts.graphic.LinearGradient 这个API,它是ECharts提供的渐变色创建方法,很多高颜值的图表都靠它。
饼图
饼图适合展示各部分占整体的比例关系,比如市场份额、预算分配等。
var option = {
title: {
text: '公司年度预算分配',
subtext: '单位:万元',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}万元 ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
series: [
{
name: '预算分配',
type: 'pie',
radius: ['40%', '70%'], // 环形图,把40%改成0%就是普通饼图
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: '{b}\n{d}%',
fontSize: 12
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: [
{ value: 1048, name: '研发部' },
{ value: 735, name: '市场部' },
{ value: 580, name: '运营部' },
{ value: 484, name: '人事部' },
{ value: 300, name: '行政部' }
]
}
]
};
这个饼图做成了环形图的效果,比传统的实心饼图看起来更现代。radius 属性控制内外半径,你可以自己调调看效果。
散点图
散点图适合展示两个变量之间的关系,比如身高体重的关系、广告投入和销售额的关系等。
var option = {
title: {
text: '广告投入与销售额关系图',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return '广告投入: ' + params.data[0] + '万<br/>销售额: ' + params.data[1] + '万';
}
},
grid: {
left: '10%',
right: '10%',
bottom: '15%'
},
xAxis: {
type: 'value',
name: '广告投入(万元)',
nameLocation: 'middle',
nameGap: 30
},
yAxis: {
type: 'value',
name: '销售额(万元)',
nameLocation: 'middle',
nameGap: 50
},
series: [
{
type: 'scatter',
symbolSize: function(data) {
// 气泡大小映射第三个维度
return data[2] * 0.5;
},
data: [
[10, 55, 3], [20, 100, 5], [30, 150, 8],
[40, 180, 6], [50, 220, 10], [60, 280, 12],
[70, 310, 9], [80, 350, 15], [90, 400, 11],
[100, 450, 18]
],
itemStyle: {
color: function(params) {
// 根据数据动态设置颜色
var colors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de'];
return colors[params.dataIndex % colors.length];
},
opacity: 0.8
}
}
]
};
这个散点图用气泡大小来表示第三个维度(可以理解为公司大小),这就是所谓的气泡图。ECharts的散点图可以通过 symbolSize 函数来实现这种三维数据的展示。
进阶:动态数据与交互
学完基础图表之后,很多新手会问:”我的数据是后端动态返回的,怎么渲染?” 这是非常实际的问题,咱们来聊聊。
异步加载数据
在实际项目中,图表数据几乎都是从服务器获取的,很少写死。ECharts支持异步加载数据,核心思路是:先初始化空图表,然后通过Ajax获取数据,最后调用 setOption 更新图表。
// 初始化空图表
var myChart = echarts.init(document.getElementById('main'));
// 显示加载提示
myChart.showLoading();
// 模拟从服务器获取数据
$.ajax({
url: '/api/chart-data',
type: 'GET',
dataType: 'json',
success: function(result) {
// 隐藏加载提示
myChart.hideLoading();
// 更新图表数据
myChart.setOption({
xAxis: {
data: result.categories
},
series: [{
data: result.values
}]
}, true); // 第二个参数true表示不合并,完全替换
},
error: function() {
myChart.hideLoading();
alert('数据加载失败,请稍后重试');
}
});
这里有个细节要注意:setOption 的第二个参数。默认情况下,再次调用 setOption 时ECharts会合并配置项,但如果你希望完全替换而不是合并,可以传入 true。这个参数在实际项目中经常用到,尤其是数据需要整体更新的时候。
图表交互事件
ECharts支持丰富的交互事件,比如点击、鼠标悬浮、数据区域缩放等。这些交互可以让你的图表”活”起来。
// 监听点击事件
myChart.on('click', function(params) {
console.log('点击了:', params.name);
// 可以弹出详情,或者跳转到详情页
// window.location.href = '/detail?id=' + params.data.id;
});
// 监听鼠标悬浮事件
myChart.on('mouseover', function(params) {
console.log('悬浮在:', params.name);
});
// 数据区域缩放(刷选)
myChart.on('dataZoom', function(params) {
// 当用户缩放数据区域时触发
console.log('缩放范围:', params.batch[0].startValue, '~', params.batch[0].endValue);
});
// 图例开关
myChart.on('legendselectchanged', function(params) {
console.log('当前选中的图例:', params.selected);
});
我把这几个事件在实际项目中遇到过的好几个场景给你讲讲。第一个是点击图表跳转到详情页,比如在做一个销售数据看板时,用户点击某个柱状图,就跳转到该部门的详细数据页面。第二个是数据区域缩放,当数据量特别大的时候(比如一年的日数据),用户可以通过拖拽来放大某一段时间查看详细数据。第三个是图例开关,这个在很多多系列图表中很常用,用户点击图例可以显示/隐藏某个系列。
响应式适配
图表的响应式适配是很多人容易忽略的一个点。你的图表可能要在不同尺寸的屏幕上显示,手机、平板、桌面端都要能正常展示。
var myChart = echarts.init(document.getElementById('main'));
// 初始渲染
myChart.setOption(option);
// 监听窗口大小变化,自动resize
window.addEventListener('resize', function() {
myChart.resize();
});
// 或者用更优雅的方式
window.addEventListener('resize', myChart.resize.bind(myChart));
这行代码虽然只有两行,但在实际项目中特别重要。我曾经见过一个项目,图表在大屏幕上很好看,但同事用手机打开就全是变形了,就是因为没有加这个 resize 监听。
主题和配色
很多新手做出来的图表不好看,不是因为数据有问题,而是配色太丑了。ECharts默认的主题确实有点”朴素”,但好在它提供了很好的自定义能力。
使用内置主题
ECharts内置了几个不错的主题,你可以直接切换:
// 初始化时指定主题
var myChart = echarts.init(document.getElementById('main'), 'dark');
// 或者动态切换主题
myChart.setTheme('dark'); // 深色主题
myChart.setTheme('essos'); // 深色复古主题
myChart.setTheme('shine'); // 明亮主题
常用的内置主题有:dark(深色)、essos(深色复古)、shine(明亮)、roma(暖色调)、vintage(复古)。
自定义配色方案
如果你想做一套专属的配色方案,可以这样:
// 自定义主题颜色
var myChart = echarts.init(document.getElementById('main'), {
color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272']
});
这里给你的建议是:颜色不要超过6种,太多了图表会显得很乱。推荐几个好看的配色方案:
- 清新风格:
#5470c6,#91cc75,#fac858,#73c0de,#745af0 - 商务风格:
#1f77b4,#ff7f0e,#2ca02c,#d62728,#9467bd - 深色风格:
#3498db,#e74c3c,#2ecc71,#f39c12,#9b59b6
暗黑模式适配
现在很多系统都支持暗黑模式,如果你的图表应用也要适配,可以这样处理:
function getOption() {
// 根据系统主题返回不同的配置
var isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
return {
backgroundColor: isDark ? '#1a1a2e' : '#ffffff',
title: {
textStyle: {
color: isDark ? '#eee' : '#333'
}
},
textStyle: {
color: isDark ? '#ccc' : '#333'
},
// ... 其他配置
};
}
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(getOption());
// 监听主题变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function() {
myChart.setOption(getOption(), true);
});
这段代码用了 prefers-color-scheme 媒体查询来检测用户的系统主题设置,非常实用。
实战项目一:数据可视化仪表盘
理论学完了,咱们来做一个完整的项目——数据可视化仪表盘。这是一个非常典型的商业应用场景,很多公司的运营后台、数据大屏都需要这种布局。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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 {
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #fff;
min-height: 100vh;
padding: 20px;
}
.header {
text-align: center;
padding: 20px 0;
border-bottom: 1px solid rgba(255,255,255,0.1);
margin-bottom: 20px;
}
.header h1 {
font-size: 28px;
font-weight: 600;
letter-spacing: 2px;
}
.header .subtitle {
font-size: 14px;
color: rgba(255,255,255,0.6);
margin-top: 8px;
}
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 20px;
max-width: 1400px;
margin: 0 auto;
}
.card {
background: rgba(255,255,255,0.05);
border-radius: 12px;
padding: 20px;
border: 1px solid rgba(255,255,255,0.1);
backdrop-filter: blur(10px);
}
.card-title {
font-size: 14px;
color: rgba(255,255,255,0.7);
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 8px;
}
.card-title::before {
content: '';
width: 4px;
height: 14px;
background: #5470c6;
border-radius: 2px;
}
.card.large {
grid-column: span 2;
grid-row: span 2;
}
.card.medium {
grid-column: span 1;
grid-row: span 1;
}
.chart-container {
width: 100%;
height: 250px;
}
.card.large .chart-container {
height: 100%;
}
/* 关键指标卡片 */
.kpi-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
max-width: 1400px;
margin: 0 auto 20px;
}
.kpi-card {
background: rgba(255,255,255,0.05);
border-radius: 12px;
padding: 20px;
border: 1px solid rgba(255,255,255,0.1);
text-align: center;
}
.kpi-value {
font-size: 32px;
font-weight: 700;
color: #5470c6;
}
.kpi-label {
font-size: 13px;
color: rgba(255,255,255,0.6);
margin-top: 8px;
}
.kpi-change {
font-size: 12px;
margin-top: 5px;
}
.kpi-change.up {
color: #91cc75;
}
.kpi-change.down {
color: #ee6666;
}
</style>
</head>
<body>
<div class="header">
<h1>企业运营数据看板</h1>
<div class="subtitle">数据更新时间:2024年1月15日 14:30</div>
</div>
<!-- 关键指标 -->
<div class="kpi-cards">
<div class="kpi-card">
<div class="kpi-value">¥128.5万</div>
<div class="kpi-label">本月销售额</div>
<div class="kpi-change up">↑ 12.5% 较上月</div>
</div>
<div class="kpi-card">
<div class="kpi-value">3,562</div>
<div class="kpi-label">新增用户</div>
<div class="kpi-change up">↑ 8.3% 较上月</div>
</div>
<div class="kpi-card">
<div class="kpi-value">68.5%</div>
<div class="kpi-label">转化率</div>
<div class="kpi-change down">↓ 2.1% 较上月</div>
</div>
<div class="kpi-card">
<div class="kpi-value">12.8万</div>
<div class="kpi-label">活跃用户</div>
<div class="kpi-change up">↑ 5.6% 较上月</div>
</div>
</div>
<!-- 图表区域 -->
<div class="dashboard">
<div class="card large">
<div class="card-title">销售趋势分析</div>
<div class="chart-container" id="trendChart"></div>
</div>
<div class="card medium">
<div class="card-title">产品类别占比</div>
<div class="chart-container" id="pieChart"></div>
</div>
<div class="card medium">
<div class="card-title">各区域销售分布</div>
<div class="chart-container" id="barChart"></div>
</div>
</div>
<script>
// 销售趋势图
var trendChart = echarts.init(document.getElementById('trendChart'));
trendChart.setOption({
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(255,255,255,0.1)',
borderColor: 'rgba(255,255,255,0.2)',
textStyle: { color: '#fff' }
},
legend: {
data: ['销售额', '利润'],
textStyle: { color: 'rgba(255,255,255,0.7)' },
top: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisLine: { lineStyle: { color: 'rgba(255,255,255,0.2)' } },
axisLabel: { color: 'rgba(255,255,255,0.7)' }
},
yAxis: {
type: 'value',
axisLine: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', formatter: '{value}' },
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.1)' } }
},
series: [
{
name: '销售额',
type: 'line',
smooth: true,
data: [82, 93, 90, 85, 110, 125, 135, 142, 130, 155, 168, 180],
itemStyle: { color: '#5470c6' },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(84, 112, 198, 0.4)' },
{ offset: 1, color: 'rgba(84, 112, 198, 0.05)' }
])
}
},
{
name: '利润',
type: 'line',
smooth: true,
data: [25, 30, 28, 32, 40, 45, 50, 52, 48, 55, 60, 65],
itemStyle: { color: '#91cc75' },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(145, 204, 117, 0.4)' },
{ offset: 1, color: 'rgba(145, 204, 117, 0.05)' }
])
}
}
]
});
// 饼图
var pieChart = echarts.init(document.getElementById('pieChart'));
pieChart.setOption({
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255,255,255,0.1)',
borderColor: 'rgba(255,255,255,0.2)',
textStyle: { color: '#fff' },
formatter: '{b}: {c}万 ({d}%)'
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
textStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 11 }
},
series: [{
name: '产品类别',
type: 'pie',
radius: ['35%', '65%'],
center: ['40%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 6,
borderColor: 'rgba(26,26,46,0.8)',
borderWidth: 2
},
label: { show: false },
emphasis: {
label: {
show: true,
fontSize: 13,
fontWeight: 'bold',
color: '#fff'
}
},
data: [
{ value: 45.6, name: '电子产品' },
{ value: 32.8, name: '服装鞋帽' },
{ value: 28.5, name: '食品饮料' },
{ value: 18.2, name: '家居用品' },
{ value: 12.4, name: '其他' }
]
}]
});
// 柱状图
var barChart = echarts.init(document.getElementById('barChart'));
barChart.setOption({
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(255,255,255,0.1)',
borderColor: 'rgba(255,255,255,0.2)',
textStyle: { color: '#fff' },
axisPointer: { type: 'shadow' }
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '10%',
containLabel: true
},
xAxis: {
type: 'value',
axisLine: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)' },
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.1)' } }
},
yAxis: {
type: 'category',
data: ['华东', '华南', '华北', '西南', '华中', '西北', '东北'],
axisLine: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)' }
},
series: [{
type: 'bar',
data: [42, 38, 35, 28, 25, 15, 12],
itemStyle: {
color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
{ offset: 0, color: '#5470c6' },
{ offset: 1, color: '#91cc75' }
]),
borderRadius: [0, 4, 4, 0]
},
label: {
show: true,
position: 'right',
color: 'rgba(255,255,255,0.7)',
formatter: '{c}万'
}
}]
});
// 响应式适配
window.addEventListener('resize', function() {
trendChart.resize();
pieChart.resize();
barChart.resize();
});
</script>
</body>
</html>
这个项目虽然代码量不小,但拆开来看其实就三个部分:关键指标卡片、趋势折线图、饼图和柱状图。我特意用了深色主题,这种风格在商业大屏中非常常见,看起来很有科技感。
我把这个项目的几个关键设计点给你讲一下。第一个是CSS Grid布局,用三列两行的网格来排列卡片,第一个卡片设置了 grid-column: span 2 和 grid-row: span 2 让它占两列两行,形成一个大卡片,这样布局就有主次了,不会显得死板。
第二个是深色主题的一致性处理。所有文字颜色、分割线颜色、背景透明度都要统一,不能有的地方白色有的地方灰色,那样看起来很乱。我用的方法是统一用 rgba(255,255,255,0.7) 作为次要文字颜色,rgba(255,255,255,0.1) 作为分割线颜色。
第三个是渐变色条的圆角处理。注意看柱状图的 itemStyle,borderRadius: [0, 4, 4, 0] 只给右边两个角加了圆角,这样看起来更像是一个进度条,而不是传统的柱状图,视觉效果更好。
实战项目二:地图可视化
地图可视化是ECharts的杀手锏功能,很多商业项目都会用到。我用一个全国销售分布的项目来演示。
// 注册地图数据(以中国地图为例)
// 实际项目中需要从服务器获取GeoJSON数据
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
.then(response => response.json())
.then(geoJson => {
echarts.registerMap('china', geoJson);
var mapChart = echarts.init(document.getElementById('mapChart'));
mapChart.setOption({
tooltip: {
trigger: 'item',
formatter: '{b}<br/>销售额:{c}万元'
},
visualMap: {
min: 0,
max: 500,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true,
inRange: {
color: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']
},
textStyle: { color: '#fff' }
},
geo: {
map: 'china',
roam: true, // 允许缩放和平移
zoom: 1.2,
label: {
show: true,
color: 'rgba(255,255,255,0.7)',
fontSize: 10
},
itemStyle: {
areaColor: '#323c48',
borderColor: '#111'
},
emphasis: {
itemStyle: {
areaColor: '#2a333d'
},
label: {
color: '#fff'
}
}
},
series: [
{
name: '销售额',
type: 'map',
geoIndex: 0,
data: [
{ name: '广东省', value: 450 },
{ name: '江苏省', value: 380 },
{ name: '浙江省', value: 360 },
{ name: '山东省', value: 320 },
{ name: '河南省', value: 280 },
{ name: '四川省', value: 250 },
{ name: '湖北省', value: 220 },
{ name: '湖南省', value: 200 },
{ name: '安徽省', value: 180 },
{ name: '福建省', value: 170 },
{ name: '上海市', value: 420 },
{ name: '北京市', value: 390 },
{ name: '北京市', value: 390 },
{ name: '辽宁省', value: 150 },
{ name: '河北省', value: 140 }
]
},
{
// 散点图,标记重点城市
type: 'effectScatter',
coordinateSystem: 'geo',
data: [
{ name: '广州', value: [113.26, 23.13, 450] },
{ name: '深圳', value: [114.07, 22.62, 430] },
{ name: '上海', value: [121.47, 31.23, 420] },
{ name: '北京', value: [116.40, 39.90, 390] },
{ name: '杭州', value: [120.15, 30.28, 360] }
],
symbolSize: function(val) {
return val[2] / 20;
},
itemStyle: {
color: '#f4e925'
},
emphasis: {
itemStyle: {
borderColor: '#fff',
borderWidth: 2
}
}
}
]
});
});
这段代码里有几个重要的概念需要解释一下。第一个是echarts.registerMap,ECharts的地图功能需要预先注册地图数据,数据格式是GeoJSON。上面的代码从阿里云的数据源获取了中国地图数据,你也可以下载下来放到本地。
第二个是visualMap组件,它根据数据值自动给不同区域上色,数据越大颜色越深,非常直观。你可以调整 inRange.color 数组来改变配色方案。
第三个是effectScatter系列,它在地图上添加了动态的散点标记,那些扩散的圆圈效果让图表更加生动。symbolSize 函数根据数据的第三个值(销售额)来动态设置圆点大小。
实战项目三:实时数据看板
最后一个项目做一个稍微复杂一点的——实时数据更新看板。这种场景在实际工作中非常常见,比如交易大屏、监控大屏等。
var myChart = echarts.init(document.getElementById('main'));
// 模拟实时数据
var data = [];
var now = new Date();
for (var i = 0; i < 100; i++) {
data.push([
formatTime(new Date(now - (100 - i) * 1000)),
Math.round(Math.random() * 100 + 50)
]);
}
function formatTime(date) {
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
return h + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
}
var option = {
title: {
text: '实时温度监控',
left: 'center',
textStyle: { color: '#fff' }
},
tooltip: {
trigger: 'axis',
formatter: function(params) {
return params[0].axisValueLabel + '<br/>' +
'温度:' + params[0].value[1] + '°C';
},
backgroundColor: 'rgba(255,255,255,0.1)',
textStyle: { color: '#fff' }
},
grid: {
left: '10%',
right: '10%',
bottom: '15%',
top: '15%'
},
xAxis: {
type: 'category',
data: data.map(function(item) { return item[0]; }),
axisLine: { lineStyle: { color: 'rgba(255,255,255,0.3)' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
interval: 9, // 每10个显示一个标签
rotate: 30
}
},
yAxis: {
type: 'value',
name: '温度(°C)',
min: 0,
max: 150,
axisLine: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)' },
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.1)' } }
},
series: [{
name: '温度',
type: 'line',
data: data.map(function(item) { return item[1]; }),
smooth: true,
symbol: 'none',
lineStyle: {
color: '#5470c6',
width: 2
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(84, 112, 198, 0.5)' },
{ offset: 1, color: 'rgba(84, 112, 198, 0.05)' }
])
},
markLine: {
silent: true,
data: [
{ yAxis: 100, lineStyle: { color: '#ee6666', type: 'dashed' } },
{ yAxis: 50, lineStyle: { color: '#91cc75', type: 'dashed' } }
],
label: {
formatter: function(params) {
return params.value + '°C';
},
color: '#fff',
position: 'insideEndTop'
}
}
}]
};
myChart.setOption(option);
// 实时数据更新
setInterval(function() {
var now = new Date();
var newData = [
formatTime(now),
Math.round(Math.random() * 100 + 50)
];
// 移除最旧的数据
data.shift();
// 添加最新的数据
data.push(newData);
myChart.setOption({
xAxis: {
data: data.map(function(item) { return item[0]; })
},
series: [{
data: data.map(function(item) { return item[1]; })
}]
});
}, 1000);
这段代码模拟了一个每秒更新一次的实时温度监控看板。核心思路是:用 setInterval 每秒生成一个新数据点,然后把最早的一个数据点删掉,始终保持100个数据点在图表中显示。
我把这个例子给你讲得细一点,因为实时数据更新是很多面试项目都会问到的点。首先,setInterval 的回调函数里不能直接调用 myChart.clear(),那样会导致图表闪烁。正确的方法是只更新 xAxis.data 和 series.data,ECharts会自动做过渡动画。
其次,数据量很大的时候要注意性能。如果每秒更新的数据量超过1000个点,建议考虑降采样或者使用 ECharts 的 large: true 模式,它能对大量数据进行优化渲染。
最后,markLine 组件这个功能很多人不知道,它可以在图表上画一条参考线,比如这里的100°C和50°C阈值线,当数据超过阈值时可以配合 markPoint 来做告警提示。
常见坑点与避坑指南
学了一段时间之后,我总结了一些新手最容易踩的坑,你最好提前知道:
坑一:图表不显示,排查半天发现是容器没设高度
这个坑太经典了。ECharts需要容器有明确的宽高才能渲染,如果你用百分比设置高度,还要确保父元素的高度是确定的。最简单的解决方案是在CSS里直接给容器设置 height: 400px 之类的固定高度。
#main {
width: 100%;
height: 400px;
}
坑二:异步数据加载后图表不更新
这个坑的原因通常是 setOption 调用时机不对,或者数据格式不对。你需要注意:
- 确保在数据获取成功后再调用
setOption - 数据格式要和配置项中的
xAxis.data/series.data对应 - 如果是多图联动,记得所有图表都更新完再
setOption
坑三:地图不显示
地图不显示的原因通常是:
- 没有正确注册地图数据
- GeoJSON数据格式有问题
- 地图省份名称和数据中的名称不匹配(比如数据里写的是”广东”但GeoJSON里是”广东省”)
建议用浏览器的开发者工具Network面板检查一下GeoJSON数据是否正确加载。
坑四:大数据量性能问题
当数据量超过几千条时,图表可能会出现卡顿。解决方案:
- 开启
large: true模式 - 使用
sampling: 'lttb'进行降采样 - 分页加载数据,只展示当前页的数据
series: [{
type: 'line',
large: true,
sampling: 'lttb',
data: bigData
}]
坑五:echarts.getInstanceByDom 获取不到实例
这个坑比较隐蔽。有时候你在组件销毁后还想操作图表,但拿不到实例。正确做法是:
// 初始化时保存实例引用
var myChart = echarts.init(document.getElementById('main'));
// 销毁时清理
myChart.dispose();
在Vue/React等框架中,记得在组件的 beforeDestroy / useEffect cleanup 中调用 dispose(),否则会有内存泄漏。
学习路径建议
学完这些之后,你可能还是会有点迷茫:下一步该往哪个方向走?我给你梳理一条比较清晰的学习路径:
第一阶段:基础入门(1-2周)
这个阶段的目标是能独立做出常见的几种图表。你需要掌握:
- HTML + CSS + JavaScript 基础(如果你已经会了可以跳过)
- ECharts 基础配置项
- 柱状图、折线图、饼图、散点图的制作
- 响应式适配
第二阶段:进阶提升(2-4周)
这个阶段要开始接触更复杂的应用场景:
- 地图可视化
- 仪表盘、雷达图等高级图表
- 实时数据更新
- 图表联动(多个图表共享一个数据源)
- 自定义主题和配色
第三阶段:工程化实践(4-8周)
这个阶段要像真实项目一样去写代码:
- 在 Vue / React 项目中集成 ECharts
- 封装通用图表组件
- 对接后端API,处理异步数据
- 性能优化
- 做1-2个完整的项目放到GitHub上
第四阶段:求职准备
这个阶段重点整理项目经验和准备面试题:
- 整理你的项目作品集
- 准备常见的ECharts面试题
- 了解数据可视化相关的其他技术(如 D3.js、AntV)
面试题准备
最后,我给你整理了一些常见的ECharts面试题,你面试前可以看看:
Q1:ECharts和D3.js有什么区别,各适用于什么场景?
ECharts开箱即用,配置简单,适合快速开发,内置图表类型丰富;D3.js更底层、更灵活,适合做高度定制化的可视化,但学习曲线更陡峭。国内企业用ECharts的多,国外用D3的多。
Q2:ECharts图表不显示的可能原因有哪些?
容器没有设置宽高、ECharts实例初始化时DOM还未加载完成、配置项语法错误(不报错但不生效)、数据格式不对、浏览器兼容性等问题。
Q3:如何实现图表的实时数据更新?
用 setInterval 定时获取新数据,然后调用 setOption 更新 series.data,注意不要用 clear 方法,否则会导致闪烁。
Q4:ECharts如何处理大量数据的性能问题?
开启 large: true 模式、使用降采样(sampling 属性)、分页加载数据、虚拟滚动等。
Q5:如何给ECharts图表添加点击事件?
使用 myChart.on('click', function(params) { ... }) 来监听点击事件,params 中包含当前点击的数据信息。
学ECharts这件事,我最大的感触是:它真的不难,难的是你坚持学下去。很多小伙伴一开始信心满满,结果学到中途遇到配置项记不住、样式调不好看、数据联不上等问题就开始放弃了。
我的建议是:不要试图一次性把所有东西都学会,先把最基础的几种图表做熟,然后边做项目边学,遇到什么问题就查文档,这样学到的东西最扎实。等你做出第一个完整的项目,那种成就感会推着你继续往下走。
ECharts的技能在找工作的时候是一个很大的加分项,尤其是数据分析师、前端开发、BI开发这几个方向。我见过太多因为一个不错的可视化项目而拿到offer的例子。
好了,说了这么多,我希望这篇内容能帮到你。如果你在学习过程中遇到什么问题,随时可以来交流。记住,每个高手都是从小白一步步走过来的,你现在的每一个代码片段,都是在为未来的自己铺路。
加油,期待看到你的第一个完整作品!
