Echarts可视化入门视频手把手教你从零搭建数据看板完整实战案例详解
先聊聊,为啥要用 ECharts?
说实话,我第一次接触数据可视化的时候,被那些乱七八糟的图表配置文档吓退了好几次。但后来发现,ECharts 真的是前端可视化领域的”国民级”武器——百度开源、社区活跃、文档中文友好,关键是它啥都能画:折线图、柱状图、散点图、地图、雷达图、K线图……甚至有3D地球、热力图这些”高级货”。
今天咱们不搞虚的,直接从零开始,带你搭建一个完整的数据看板,过程中我会把每一个坑都标出来,让你少走弯路。
第一步:环境搭建——别慌,很简单
1.1 引入 ECharts
最基础的方式是用 CDN,新建一个 index.html:
<!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: #eee; font-family: 'PingFang SC', sans-serif; }
.dashboard { padding: 20px; }
.title { font-size: 24px; margin-bottom: 20px; text-align: center; color: #00d4ff; }
.chart-row { display: flex; gap: 20px; margin-bottom: 20px; }
.chart-card {
background: #16213e;
border-radius: 12px;
padding: 15px;
flex: 1;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.chart { width: 100%; height: 300px; }
.big-chart { height: 400px; }
</style>
</head>
<body>
<div class="dashboard">
<h1 class="title">📊 2024年度销售数据实时看板</h1>
<!-- 第一行:两个小图 -->
<div class="chart-row">
<div class="chart-card">
<div id="chart1" class="chart"></div>
</div>
<div class="chart-card">
<div id="chart2" class="chart"></div>
</div>
</div>
<!-- 第二行:一个大图 -->
<div class="chart-row">
<div class="chart-card">
<div id="chart3" class="chart big-chart"></div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
💡 小贴士:这里用了深色主题,因为数据看板配深色背景会更有”科技感”,而且长时间盯着看眼睛不累。
第二步:第一个图表——折线图(趋势分析)
新建 app.js,开始写第一个图表:
// 初始化第一个图表:月度销售额趋势
const chart1 = echarts.init(document.getElementById('chart1'));
const option1 = {
backgroundColor: 'transparent',
title: {
text: '月度销售额趋势',
left: 'center',
textStyle: { color: '#00d4ff', fontSize: 14 }
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(22,33,62,0.9)',
borderColor: '#00d4ff',
textStyle: { color: '#eee' }
},
legend: {
data: ['2023年', '2024年'],
bottom: 0,
textStyle: { color: '#aaa' }
},
grid: {
left: '3%',
right: '4%',
bottom: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' }
},
yAxis: {
type: 'value',
name: '销售额(万)',
nameTextStyle: { color: '#aaa' },
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' },
splitLine: { lineStyle: { color: '#222' } }
},
series: [
{
name: '2023年',
type: 'line',
data: [820, 932, 901, 934, 1290, 1330, 1320, 1400, 1350, 1420, 1500, 1580],
smooth: true,
itemStyle: { color: '#ff6b6b' },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(255,107,107,0.3)' },
{ offset: 1, color: 'rgba(255,107,107,0.05)' }
])
}
},
{
name: '2024年',
type: 'line',
data: [950, 1050, 1100, 1180, 1350, 1420, 1500, 1580, 1620, 1700, 1780, 1850],
smooth: true,
itemStyle: { color: '#00d4ff' },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(0,212,255,0.3)' },
{ offset: 1, color: 'rgba(0,212,255,0.05)' }
])
}
}
]
};
chart1.setOption(option1);
代码拆解(别嫌啰嗦,懂原理才能改)
| 配置项 | 作用 |
|---|---|
tooltip |
鼠标悬停时的提示框,trigger: 'axis' 表示整条轴都触发 |
grid |
控制图表在卡片中的位置,containLabel: true 防止标签被截断 |
smooth: true |
让折线变得平滑,不用直角拐弯 |
areaStyle |
给折线填充渐变底色,提升视觉层次 |
LinearGradient |
线性渐变,0,0,0,1 表示从上到下 |
🎯 重点:
setOption是 ECharts 的”灵魂方法”,所有配置都通过它传入。后面你会无数次用到它。
第三步:第二个图表——柱状图(品类对比)
// 初始化第二个图表:各品类销售对比
const chart2 = echarts.init(document.getElementById('chart2'));
const option2 = {
backgroundColor: 'transparent',
title: {
text: '品类销售 TOP5',
left: 'center',
textStyle: { color: '#00d4ff', fontSize: 14 }
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
backgroundColor: 'rgba(22,33,62,0.9)',
borderColor: '#00d4ff',
textStyle: { color: '#eee' },
formatter: '{b}: {c}万件'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' },
splitLine: { lineStyle: { color: '#222' } }
},
yAxis: {
type: 'category',
data: ['电子产品', '服装鞋帽', '家居用品', '食品饮料', '美妆护肤'],
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' }
},
series: [{
type: 'bar',
data: [4200, 3800, 2900, 2500, 2100],
itemStyle: {
borderRadius: [0, 4, 4, 0],
color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
{ offset: 0, color: '#00d4ff' },
{ offset: 1, color: '#0083b0' }
])
},
label: {
show: true,
position: 'right',
color: '#00d4ff',
formatter: '{c}万'
}
}]
};
chart2.setOption(option2);
这里有个容易踩的坑
横向柱状图 vs 纵向柱状图——很多人分不清。
- 横轴是
category(类目),纵轴是value(数值)→ 竖向柱状图 - 横轴是
value,纵轴是category→ 横向柱状图(我们这里用的就是这种)
横向柱状图在展示品类名称较长时更友好,因为纵轴有足够空间显示文字。
第四步:第三个图表——混合图表(组合拳才是王道)
数据看板的核心魅力在于多种图表组合,下面是一个复杂一点的组合图:
// 初始化第三个图表:仪表盘 + 散点图 + 饼图
const chart3 = echarts.init(document.getElementById('chart3'));
const option3 = {
backgroundColor: 'transparent',
title: {
text: '年度综合数据概览',
left: 'center',
textStyle: { color: '#00d4ff', fontSize: 16 }
},
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(22,33,62,0.95)',
borderColor: '#00d4ff',
textStyle: { color: '#eee' }
},
// 使用 grid 布局来放置多个图表
grid: [
{ left: '5%', right: '55%', top: '15%', bottom: '10%' },
{ left: '55%', right: '5%', top: '15%', bottom: '10%' }
],
// 多个 xAxis/yAxis 配置
xAxis: [
{
gridIndex: 0,
type: 'category',
data: ['Q1','Q2','Q3','Q4'],
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' },
splitLine: { show: false }
},
{
gridIndex: 1,
type: 'category',
data: ['华东','华南','华北','西部','海外'],
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' }
}
],
yAxis: [
{
gridIndex: 0,
type: 'value',
name: '销售额(万)',
nameTextStyle: { color: '#aaa' },
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' },
splitLine: { lineStyle: { color: '#222' } }
},
{
gridIndex: 1,
type: 'value',
name: '占比(%)',
nameTextStyle: { color: '#aaa' },
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#aaa' },
splitLine: { show: false }
}
],
series: [
// 折线图:季度趋势
{
name: '销售额',
type: 'line',
gridIndex: 0,
xAxisIndex: 0,
yAxisIndex: 0,
data: [3200, 4100, 4800, 5200],
smooth: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: { color: '#00d4ff' },
lineStyle: { width: 3 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(0,212,255,0.4)' },
{ offset: 1, color: 'rgba(0,212,255,0.02)' }
])
}
},
// 柱状图:区域占比
{
name: '区域销售额',
type: 'bar',
gridIndex: 1,
xAxisIndex: 1,
yAxisIndex: 1,
data: [
{ value: 35, itemStyle: { color: '#ff6b6b' } },
{ value: 28, itemStyle: { color: '#ffd93d' } },
{ value: 20, itemStyle: { color: '#6bcb77' } },
{ value: 12, itemStyle: { color: '#4d96ff' } },
{ value: 5, itemStyle: { color: '#c77dff' } }
],
label: {
show: true,
position: 'top',
color: '#fff',
formatter: '{c}%'
},
barWidth: '50%'
},
// 饼图:产品品类分布(浮动在右上角)
{
name: '品类分布',
type: 'pie',
radius: ['35%', '60%'],
center: ['82%', '25%'],
data: [
{ value: 40, name: '电子', itemStyle: { color: '#00d4ff' } },
{ value: 25, name: '服装', itemStyle: { color: '#ff6b6b' } },
{ value: 18, name: '家居', itemStyle: { color: '#ffd93d' } },
{ value: 17, name: '其他', itemStyle: { color: '#6bcb77' } }
],
label: {
color: '#aaa',
formatter: '{b}\n{d}%'
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0,0,0,0.5)'
}
}
}
]
};
chart3.setOption(option3);
组合图表的精髓
ECharts 支持多 grid + 多 xAxis/yAxis,这是搭建复杂数据看板的核心技能。上面这个例子中:
- 左侧:折线图展示季度趋势(
gridIndex: 0) - 右侧:横向柱状图展示区域占比(
gridIndex: 1) - 右上角:饼图展示品类分布(通过
center和radius定位)
🎨 技巧:饼图用
center定位时,['82%', '25%']表示饼图中心在画布的 82% 宽、25% 高的位置,radius控制内外半径,做出甜甜圈效果。
第五步:数据交互——让图表”活”起来
看板不是静态的,数据要能动态更新。下面演示模拟实时数据刷新:
// 模拟实时数据更新
function updateChartData() {
// 模拟新数据
const newData = [
Math.floor(Math.random() * 2000) + 3000,
Math.floor(Math.random() * 2000) + 3000,
Math.floor(Math.random() * 2000) + 3000,
Math.floor(Math.random() * 2000) + 3000
];
// 更新折线图
chart1.setOption({
series: [{
data: newData
}]
}, true); // 第二个参数 true 表示不合并,完全替换
}
// 每3秒刷新一次
setInterval(updateChartData, 3000);
// 监听窗口大小变化,自适应
window.addEventListener('resize', () => {
chart1.resize();
chart2.resize();
chart3.resize();
});
两个关键知识点
1. setOption 的第二个参数
setOption(option, notMerge)
notMerge = false(默认):新配置和旧配置合并,部分更新notMerge = true:完全替换,不用旧配置
数据刷新时通常用 true,避免配置冲突。
2. resize() 是必须调用的
看板在不同屏幕、不同窗口大小下显示效果不同,必须监听 resize 事件并调用 resize(),否则图表会拉伸变形。
第六步:完整看板实战——数据看板模板
把前面所有技术整合到一个完整的看板项目中:
📁 dashboard/
├── index.html # 主页面
├── css/
│ └── style.css # 样式文件
├── js/
│ ├── app.js # 主逻辑
│ ├── charts.js # 图表配置
│ └── data.js # 模拟数据/接口数据
└── assets/
└── logo.png # 可选:logo
完整的 HTML 结构
<!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>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="dashboard">
<!-- 顶部标题栏 -->
<header class="header">
<div class="logo">📊 企业数据监控中心</div>
<div class="time" id="currentTime">加载中...</div>
</header>
<!-- 核心指标卡片 -->
<div class="metrics">
<div class="metric-card">
<div class="metric-value" id="totalSales">12,580</div>
<div class="metric-label">年度总销售额(万)</div>
<div class="metric-change up">↑ 12.5%</div>
</div>
<div class="metric-card">
<div class="metric-value" id="totalOrders">38,920</div>
<div class="metric-label">总订单数</div>
<div class="metric-change up">↑ 8.3%</div>
</div>
<div class="metric-card">
<div class="metric-value" id="totalUsers">156,000</div>
<div class="metric-label">注册用户数</div>
<div class="metric-change up">↑ 15.2%</div>
</div>
<div class="metric-card">
<div class="metric-value" id="conversionRate">4.8%</div>
<div class="metric-label">转化率</div>
<div class="metric-change down">↓ 0.3%</div>
</div>
</div>
<!-- 图表区域 -->
<div class="charts">
<div class="chart-card wide">
<div class="chart-title">📈 销售趋势分析</div>
<div id="trendChart" class="chart"></div>
</div>
<div class="chart-card">
<div class="chart-title">🗺️ 区域销售分布</div>
<div id="regionChart" class="chart"></div>
</div>
<div class="chart-card">
<div class="chart-title">📊 品类销售占比</div>
<div id="categoryChart" class="chart"></div>
</div>
<div class="chart-card wide">
<div class="chart-title">⏱️ 实时订单动态</div>
<div id="realtimeChart" class="chart"></div>
</div>
</div>
</div>
<script src="js/data.js"></script>
<script src="js/charts.js"></script>
<script src="js/app.js"></script>
</body>
</html>
CSS 样式(科技风深色主题)
/* css/style.css */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(135deg, #0f0c29 0%, #1a1a2e 50%, #16213e 100%);
color: #eee;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
min-height: 100vh;
}
.dashboard {
padding: 20px;
max-width: 1920px;
margin: 0 auto;
}
/* 顶部标题 */
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background: rgba(255,255,255,0.05);
border-radius: 12px;
margin-bottom: 20px;
border: 1px solid rgba(0,212,255,0.2);
}
.logo {
font-size: 22px;
font-weight: bold;
color: #00d4ff;
text-shadow: 0 0 10px rgba(0,212,255,0.5);
}
.time {
color: #aaa;
font-size: 14px;
}
/* 核心指标卡片 */
.metrics {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 20px;
}
.metric-card {
background: rgba(22,33,62,0.8);
border-radius: 12px;
padding: 20px;
text-align: center;
border: 1px solid rgba(0,212,255,0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.metric-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,212,255,0.2);
}
.metric-value {
font-size: 32px;
font-weight: bold;
color: #00d4ff;
margin-bottom: 8px;
}
.metric-label {
color: #aaa;
font-size: 14px;
margin-bottom: 8px;
}
.metric-change {
font-size: 12px;
}
.metric-change.up { color: #6bcb77; }
.metric-change.down { color: #ff6b6b; }
/* 图表区域 */
.charts {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows: auto auto;
gap: 20px;
}
.chart-card {
background: rgba(22,33,62,0.8);
border-radius: 12px;
padding: 15px;
border: 1px solid rgba(0,212,255,0.1);
}
.chart-card.wide {
grid-column: span 2;
}
.chart-title {
color: #00d4ff;
font-size: 14px;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid rgba(0,212,255,0.2);
}
.chart {
width: 100%;
height: 300px;
}
.chart-card.wide .chart {
height: 280px;
}
/* 响应式 */
@media (max-width: 1200px) {
.metrics { grid-template-columns: repeat(2, 1fr); }
.charts { grid-template-columns: 1fr; }
.chart-card.wide { grid-column: span 1; }
}
@media (max-width: 768px) {
.metrics { grid-template-columns: 1fr; }
}
第七步:进阶技巧——那些老手才知道的”骚操作”
7.1 数据看板常用的 5 种图表组合
| 场景 | 推荐图表 | 用途 |
|---|---|---|
| 时间趋势 | 折线图 / 面积图 | 看销量、用户增长趋势 |
| 占比分析 | 饼图 / 环形图 | 各品类占比、渠道来源 |
| 对比分析 | 柱状图 / 条形图 | 区域对比、产品对比 |
| 分布分析 | 散点图 / 热力图 | 用户分布、价格分布 |
| 关联分析 | 桑基图 / 雷达图 | 资金流向、能力评估 |
7.2 让图表动起来的 3 种方式
// 方式1:定时刷新(轮询)
setInterval(() => {
fetch('/api/sales-data')
.then(res => res.json())
.then(data => chart.setOption({ series: [{ data: data }] }, true));
}, 5000);
// 方式2:WebSocket 实时推送
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
chart.setOption({ series: [{ data: data.series }] }, true);
};
// 方式3:动画过渡(setOption 自带动画)
chart.setOption({
series: [{ data: newData }]
// ECharts 默认有 1000ms 的动画过渡,不需要额外配置
});
7.3 性能优化——看板卡?试试这些
// 1. 按需加载模块(减小体积)
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([LineChart, CanvasRenderer]);
// 2. 大数据量时使用 dataZoom
option.dataZoom = [
{ type: 'inside', start: 0, end: 100 },
{ type: 'slider', start: 0, end: 100 }
];
// 3. 大量数据时开启采样
option.series[0].sampling = 'average';
// 4. 定时清理不再需要的图表实例
chart.dispose(); // 彻底销毁实例,释放内存
第八步:常见坑及解决方案
❌ 坑1:图表显示空白
原因:容器高度为 0 或没设置。
/* 必须给容器设置高度! */
#chart1 { width: 100%; height: 300px; }
❌ 坑2:图表大小不自适应
原因:没监听 resize 事件。
window.addEventListener('resize', () => {
chart1.resize();
chart2.resize();
chart3.resize();
});
❌ 坑3:数据更新后图表”闪烁”
原因:setOption 没有正确使用。
// ❌ 错误:每次都重新初始化,导致闪烁
chart = echarts.init(dom);
chart.setOption(option);
// ✅ 正确:复用实例,只更新数据
chart.setOption({ series: [{ data: newData }] }, true);
❌ 坑4:深色主题下字体看不清
原因:默认主题不适合深色背景。
// 方案1:自定义颜色
xAxis: { axisLabel: { color: '#aaa' } }
// 方案2:使用内置暗黑主题
echarts.registerTheme('dark', {
backgroundColor: '#1a1a2e',
textStyle: { color: '#eee' }
});
const chart = echarts.init(dom, 'dark');
第九步:实战扩展——接入真实数据
上面的例子都是模拟数据,实际项目中你需要对接后端 API:
// 模拟异步获取数据
async function fetchData() {
try {
// 真实项目中替换为实际接口
// const response = await fetch('https://api.example.com/sales');
// const data = await response.json();
const data = {
sales: [820, 932, 901, 934, 1290, 1330],
products: ['手机', '电脑', '平板', '耳机', '手表', '音箱'],
regions: ['华东', '华南', '华北', '西部']
};
updateCharts(data);
} catch (error) {
console.error('数据获取失败:', error);
// 显示错误提示
document.getElementById('errorTip').style.display = 'block';
}
}
function updateCharts(data) {
// 更新折线图
trendChart.setOption({
series: [{ data: data.sales }]
}, true);
// 更新饼图
categoryChart.setOption({
series: [{ data: data.products.map((name, i) => ({ name, value: Math.random() * 1000 })) }]
}, true);
}
// 页面加载完成后获取数据
fetchData();
// 定时刷新
setInterval(fetchData, 30000);
第十步:学习路线建议
如果你刚接触 ECharts,按这个顺序来:
① 先跑通 Hello World(5分钟)
→ 用 CDN 引入,画一个简单的柱状图
② 理解核心概念(30分钟)
→ option 配置项、series、xAxis/yAxis、tooltip
③ 掌握常用图表(2小时)
→ 折线图、柱状图、饼图、散点图
④ 学习组合图表(1小时)
→ 多 grid、混合图表
⑤ 实战项目(4小时+)
→ 搭一个完整的数据看板
⑥ 进阶探索(持续)
→ 地图、3D地球、大数据量优化、动画交互
最后说几句
学 ECharts 最忌讳的就是看文档不动手。文档再厚,看十遍不如自己敲一遍。建议你现在就新建一个 index.html,把本文的代码复制粘贴,跑起来看看效果。
数据看板的本质不是”画图表”,而是用图表讲故事——让老板一眼就能看到关键指标,让运营能快速发现异常趋势。所以,图表只是手段,业务价值才是目的。
💡 记住这句话:最好的数据看板,是让用户不需要解释就能看懂的看板。
如果本文对你有帮助,建议收藏起来反复看。有问题随时留言,咱们一起交流!🚀
