从零基础到实战 用真实项目案例学Echarts 交互式图表入门视频教程 零基础也能画出漂亮图表
最近好多朋友问我,做数据可视化到底该怎么入手?其实我一开始也是摸不着头脑,但摸索久了发现,Echarts真的是一个特别友好的工具,上手快,效果还好看。今天就把我这些年的经验跟大家聊聊,保证你看完就能动手画出来。
什么是Echarts,它为什么这么火
Echarts是百度开源的一个用JavaScript实现的开源可视化库,说白了就是让你能在网页上画各种图表。它支持折线图、柱状图、饼图、散点图、地图等等几十种图表类型,而且交互效果特别丝滑。
为什么这么多人爱用它?我总结了几点:
- 零门槛:不用学什么复杂的框架,HTML+JS就能跑起来
- 文档全:官网配置项写得清清楚楚,复制粘贴就能用
- 社区大:出问题了随便一搜就能找到答案
- 性能好:数据量大了也能流畅渲染
我第一次用它的时候,就是一个简单的折线图,结果做出来的效果惊艳到我自己——线条动画、数据提示、缩放交互全都有,简直不敢相信这是纯前端画的。
准备工作,环境搭建其实很简单
在开始之前,你需要准备的东西少得可怜:
- 一个文本编辑器,VS Code或者Sublime都行
- 浏览器,Chrome推荐
- Echarts库,直接从官网下载或者用CDN引入
我来给你展示一下最快速上手的方式,用CDN引入:
<!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;
}
</style>
</head>
<body>
<!-- 图表容器 -->
<div id="main"></div>
<script>
// 初始化Echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 配置项
var option = {
title: {
text: '我的第一个图表'
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: true // 平滑曲线,颜值更高
}]
};
// 挂载配置
myChart.setOption(option);
</script>
</body>
</html>
把这个代码保存成html文件,双击打开,你就能看到一个带平滑曲线的折线图了。简单吧?这就是Echarts的魅力,五六十行代码就能出一个像样的图表。
用真实项目案例来练手,效果翻倍
光看理论没用,得来点实际的。我给你分享几个我平时用Echarts做项目时遇到的真实场景。
案例一:销售数据看板
假设你是一名电商运营,需要展示近几个月的销售数据。来,我们直接上代码:
<!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>
body {
background: #1a1a2e;
color: #eee;
font-family: 'Microsoft YaHei', sans-serif;
padding: 20px;
}
.dashboard {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
max-width: 1400px;
margin: 0 auto;
}
.card {
background: #16213e;
border-radius: 12px;
padding: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
}
.card h3 {
margin: 0 0 15px 0;
color: #e94560;
font-size: 16px;
}
.chart {
width: 100%;
height: 300px;
}
.stat-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
margin-bottom: 20px;
}
.stat-item {
background: #0f3460;
padding: 20px;
border-radius: 10px;
text-align: center;
}
.stat-value {
font-size: 28px;
font-weight: bold;
color: #e94560;
}
.stat-label {
font-size: 13px;
color: #aaa;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="dashboard">
<!-- 统计卡片 -->
<div class="stat-grid">
<div class="stat-item">
<div class="stat-value">¥128,450</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">96.8%</div>
<div class="stat-label">好评率</div>
</div>
<div class="stat-item">
<div class="stat-value">1,204</div>
<div class="stat-label">新增用户</div>
</div>
</div>
<!-- 销售趋势图 -->
<div class="card">
<h3>📈 近30天销售趋势</h3>
<div id="trendChart" class="chart"></div>
</div>
<!-- 品类分布 -->
<div class="card">
<h3>📊 品类销售占比</h3>
<div id="pieChart" class="chart"></div>
</div>
<!-- 热力图 -->
<div class="card">
<h3>🔥 用户活跃时段热力图</h3>
<div id="heatChart" class="chart"></div>
</div>
<!-- 雷达图 -->
<div class="card">
<h3>🎯 各区域销售能力评估</h3>
<div id="radarChart" class="chart"></div>
</div>
</div>
<script>
// ========== 销售趋势折线图 ==========
var trendChart = echarts.init(document.getElementById('trendChart'));
var trendOption = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(22,33,62,0.9)',
borderColor: '#e94560',
textStyle: { color: '#eee' }
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: Array.from({length: 30}, (_, i) => `${i+1}日`),
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa', formatter: '¥{value}' },
splitLine: { lineStyle: { color: '#1a1a3e' } }
},
series: [{
name: '销售额',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
itemStyle: { color: '#e94560' },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(233,69,96,0.4)' },
{ offset: 1, color: 'rgba(233,69,96,0.02)' }
])
},
data: [
8200, 9320, 9010, 9340, 12900, 13300, 13200,
11200, 12400, 13500, 14200, 13800, 12600, 11800,
13200, 14500, 15200, 14800, 13600, 12800, 14200,
15600, 16200, 15800, 14600, 13800, 15200, 16800,
17200, 16500
]
}]
};
trendChart.setOption(trendOption);
// ========== 品类饼图 ==========
var pieChart = echarts.init(document.getElementById('pieChart'));
var pieOption = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(22,33,62,0.9)',
borderColor: '#e94560',
textStyle: { color: '#eee' },
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
right: '5%',
top: 'center',
textStyle: { color: '#aaa' }
},
series: [{
name: '销售占比',
type: 'pie',
radius: ['40%', '70%'],
center: ['40%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#16213e',
borderWidth: 2
},
label: { show: false },
emphasis: {
label: { show: true, fontSize: 16, fontWeight: 'bold', color: '#eee' }
},
data: [
{ value: 1048, name: '电子产品', itemStyle: { color: '#e94560' } },
{ value: 735, name: '服装鞋帽', itemStyle: { color: '#0f3460' } },
{ value: 580, name: '食品饮料', itemStyle: { color: '#533483' } },
{ value: 484, name: '家居用品', itemStyle: { color: '#e3b33c' } },
{ value: 300, name: '运动户外', itemStyle: { color: '#2eb8a3' } }
]
}]
};
pieChart.setOption(pieOption);
// ========== 热力图 ==========
var heatChart = echarts.init(document.getElementById('heatChart'));
var hours = ['6时', '7时', '8时', '9时', '10时', '11时', '12时', '13时', '14时', '15时', '16时', '17时', '18时', '19时', '20时', '21时', '22时', '23时', '0时', '1时', '2时', '3时', '4时', '5时'];
var days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
var heatData = [];
for (var i = 0; i < 7; i++) {
for (var j = 0; j < 24; j++) {
var value = Math.floor(Math.random() * 500);
// 早晚高峰多一点
if ((j >= 8 && j <= 9) || (j >= 18 && j <= 20)) value += 200;
// 周末流量大一些
if (i >= 5) value += 100;
heatData.push([j, i, value]);
}
}
var heatOption = {
backgroundColor: 'transparent',
tooltip: {
position: 'top',
backgroundColor: 'rgba(22,33,62,0.9)',
borderColor: '#e94560',
textStyle: { color: '#eee' },
formatter: function(params) {
return days[params.value[1]] + ' ' + hours[params.value[0]] + '<br/>访问量: ' + params.value[2];
}
},
grid: { height: '70%', top: '10%', left: '10%', right: '10%' },
xAxis: {
type: 'category',
data: hours,
splitArea: { show: true, areaStyle: { color: ['rgba(22,33,62,0.5)', 'rgba(15,52,96,0.5)'] } },
axisLabel: { color: '#aaa', interval: 2 }
},
yAxis: {
type: 'category',
data: days,
splitArea: { show: true },
axisLabel: { color: '#aaa' }
},
visualMap: {
min: 0,
max: 800,
show: false,
calculable: true,
inRange: {
color: ['#0f3460', '#1a5490', '#e94560', '#ff6b6b']
}
},
series: [{
type: 'heatmap',
data: heatData,
label: { show: false }
}]
};
heatChart.setOption(heatOption);
// ========== 雷达图 ==========
var radarChart = echarts.init(document.getElementById('radarChart'));
var radarOption = {
backgroundColor: 'transparent',
tooltip: {
backgroundColor: 'rgba(22,33,62,0.9)',
borderColor: '#e94560',
textStyle: { color: '#eee' }
},
legend: {
data: ['华东区', '华南区', '华北区'],
textStyle: { color: '#aaa' },
top: 0
},
radar: {
indicator: [
{ name: '销售额', max: 10000 },
{ name: '订单量', max: 5000 },
{ name: '复购率', max: 100 },
{ name: '客单价', max: 500 },
{ name: '增长率', max: 100 },
{ name: '满意度', max: 100 }
],
shape: 'polygon',
splitNumber: 5,
axisName: { color: '#aaa' },
splitLine: { lineStyle: { color: 'rgba(233,69,96,0.2)' } },
splitArea: { show: false },
axisLine: { lineStyle: { color: 'rgba(233,69,96,0.3)' } }
},
series: [{
name: '区域销售能力',
type: 'radar',
data: [
{
value: [9200, 4200, 78, 380, 85, 92],
name: '华东区',
itemStyle: { color: '#e94560' },
areaStyle: { color: 'rgba(233,69,96,0.2)' }
},
{
value: [7800, 3800, 82, 420, 90, 88],
name: '华南区',
itemStyle: { color: '#0f3460' },
areaStyle: { color: 'rgba(15,52,96,0.3)' }
},
{
value: [6500, 3200, 75, 350, 70, 85],
name: '华北区',
itemStyle: { color: '#533483' },
areaStyle: { color: 'rgba(83,52,131,0.2)' }
}
]
}]
};
radarChart.setOption(radarOption);
// 响应式处理
window.addEventListener('resize', function() {
trendChart.resize();
pieChart.resize();
heatChart.resize();
radarChart.resize();
});
</script>
</body>
</html>
这个案例涵盖了一个完整的数据看板应该有的元素:顶部统计卡片、趋势折线图、品类饼图、热力图、雷达图。你拿去直接用,改改数据就能上项目。
案例二:交互式地图
地图可视化是Echarts的一大亮点,很多大屏项目都用它。比如下面这个中国地图销量分布的例子:
<!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>
<script src="https://cdn.jsdelivr.net/npm/echarts/map/js/china.js"></script>
<style>
body {
margin: 0;
background: #0a0a1a;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
#mapChart {
width: 90vw;
height: 80vh;
}
</style>
</head>
<body>
<div id="mapChart"></div>
<script>
var chart = echarts.init(document.getElementById('mapChart'));
// 模拟各省份销售数据
var data = [
{name: '广东', value: 9800},
{name: '浙江', value: 8600},
{name: '江苏', value: 8200},
{name: '上海', value: 7900},
{name: '北京', value: 7500},
{name: '山东', value: 6800},
{name: '河南', value: 6200},
{name: '四川', value: 5800},
{name: '湖北', value: 5200},
{name: '湖南', value: 4800},
{name: '福建', value: 4600},
{name: '安徽', value: 4200},
{name: '辽宁', value: 3800},
{name: '河北', value: 3600},
{name: '陕西', value: 3200},
{name: '江西', value: 2800},
{name: '云南', value: 2400},
{name: '广西', value: 2200},
{name: '山西', value: 2000},
{name: '吉林', value: 1800},
{name: '天津', value: 1700},
{name: '贵州', value: 1500},
{name: '重庆', value: 1400},
{name: '黑龙江', value: 1200},
{name: '内蒙古', value: 1000},
{name: '新疆', value: 800},
{name: '甘肃', value: 700},
{name: '海南', value: 600},
{name: '宁夏', value: 400},
{name: '青海', value: 300},
{name: '西藏', value: 200}
];
var option = {
backgroundColor: '#0a0a1a',
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(10,10,26,0.95)',
borderColor: '#e94560',
textStyle: { color: '#eee' },
formatter: function(params) {
if (params.data) {
return '<b style="font-size:16px">' + params.name + '</b><br/>' +
'销售额: <span style="color:#e94560;font-size:18px;font-weight:bold">' +
params.value.toLocaleString() + '</span> 元';
}
return params.name;
}
},
visualMap: {
min: 0,
max: 10000,
left: 'left',
top: 'bottom',
text: ['高', '低'],
textStyle: { color: '#aaa' },
inRange: {
color: ['#0a0a1a', '#0f3460', '#1a5490', '#e94560', '#ff6b6b']
},
calculable: true
},
geo: {
map: 'china',
roam: true, // 允许缩放和平移
zoom: 1.2,
label: {
show: true,
color: '#aaa',
fontSize: 10
},
itemStyle: {
areaColor: '#0f3460',
borderColor: '#e94560'
},
emphasis: {
itemStyle: {
areaColor: '#e94560'
},
label: {
color: '#fff',
fontSize: 14
}
}
},
series: [
{
name: '销售额',
type: 'map',
geoIndex: 0,
data: data
},
{
// 散点标记主要城市
name: '重点城市',
type: 'effectScatter',
coordinateSystem: 'geo',
data: [
{name: '北京', value: [116.4, 39.9, 7500]},
{name: '上海', value: [121.5, 31.2, 7900]},
{name: '广州', value: [113.3, 23.1, 9800]},
{name: '深圳', value: [114.1, 22.5, 9200]},
{name: '杭州', value: [120.2, 30.3, 8600]},
{name: '成都', value: [104.1, 30.7, 5800]},
{name: '武汉', value: [114.3, 30.6, 5200]}
],
symbolSize: function(val) {
return val[2] / 400;
},
encode: { value: 2 },
itemStyle: {
color: '#e94560'
},
emphasis: {
scale: true
}
}
]
};
chart.setOption(option);
window.addEventListener('resize', function() {
chart.resize();
});
</script>
</body>
</html>
这个地图有几个值得注意的地方:第一,roam: true 开启了缩放和平移,用户可以自己操作;第二,我用 visualMap 做了颜色映射,销售额越高的省份颜色越深;第三,额外加了一层散点图标记重点城市,脉冲动画效果很吸睛。
案例三:实时数据更新
在实际项目中,数据往往是实时刷新的。Echarts支持动态更新,而且不会闪烁:
// 模拟实时数据更新
var data = [];
var now = new Date();
var base = +now;
var value = Math.random() * 1000;
setInterval(function() {
now = new Date(+now + 1000);
data.push({
name: now.toString(),
value: [
[now.getHours(), now.getMinutes(), now.getSeconds()],
Math.round(value + Math.random() * 20 - 10)
]
});
if (data.length > 60) data.shift();
chart.setOption({
series: [{
data: data
}]
});
}, 1000);
这段代码每秒钟添加一个新数据点,同时移除最旧的一个,形成流畅的实时滚动效果。在实际项目中,你会把 setInterval 换成 WebSocket 或者轮询接口,逻辑是一样的。
一些新手容易踩的坑
我当初入门的时候也踩过不少坑,分享给你:
1. 图表容器必须设置高度
这是最常见的错误,容器没有高度,图表就显示不出来。记住要在CSS里给容器设 height。
2. 异步加载数据要注意时机
如果你从接口获取数据,要确保数据拿到之后再调用 setOption,否则会出现空白或者报错。
3. 响应式处理别忘记
图表容器大小变化时,要手动调用 resize() 方法,不然图表会变形。
4. 复杂图表拆分成多个实例
一个页面不要放太多Echarts实例,性能会受影响。复杂的大屏可以把多个图表合并成一个实例的不同系列。
5. 主题风格要统一
做项目的时候提前定好配色方案,不要东一个红西一个蓝,看起来会很乱。
学习路线建议
如果你是想系统性地学好Echarts,我建议这个路径:
- 先玩官网示例:echarts.apache.org/examples 这个站点有几百个示例,每个都可以直接改代码看效果,是最好的学习方式
- 动手做一个完整项目:比如我上面给的销售看板,把一个页面做完整
- 研究配置项:慢慢把常用配置项都过一遍,做到心中有底
- 学会调试:浏览器F12看报错,Network看数据,这是基本功
- 进阶学定制:学会用canvas自己画一些特殊图形,或者接入3D效果
最后想说
学Echarts真的没那么难,关键就是多动手。我给你说的这些代码,你最好自己敲一遍,改一改数据,换个颜色,你会发现原来图表可以这么有趣。
我见过很多刚开始学的人,觉得图表制作是高深技术,但实际上它就是”配参数”的游戏。参数配对了,图表自然就漂亮了。所以别怕,打开编辑器,从第一个Hello World图表开始,你很快就能做出惊艳的效果。
有什么具体问题欢迎随时问我,看到一定会回复。祝你在数据可视化的路上越走越顺!
