pin_drop当前位置:知识文库 ❯ 图文
数据可视化:ECharts图表库 - 从入门到实践详解
教程简介
ECharts是百度开源的强大数据可视化库,以丰富的图表类型、出色的视觉效果和强大的交互能力著称。它支持30多种图表类型,内置主题系统、数据集(dataset)转换、视觉映射、地理坐标系统和大数据优化,是构建企业级数据可视化应用的首选方案。本教程将全面讲解ECharts的安装与配置、图表类型、数据集(dataset)、视觉映射、交互组件、主题定制、地图可视化和大数据优化。
核心概念
ECharts的特点
图表类型丰富:30+种图表,覆盖绝大多数可视化需求
数据驱动:通过数据集(dataset)统一管理数据
视觉映射:自动将数据映射到视觉通道(颜色、大小等)
交互组件:内置tooltip、dataZoom、legend等交互组件
主题系统:内置多套主题,支持自定义主题
地图支持:内置中国地图和世界地图
大数据优化:支持百万级数据的渲染
无障碍:支持ARIA无障碍访问
安装方式
代码示例
<!-- CDN方式 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
<!-- npm方式 -->
<!-- npm install echarts -->基本使用模式
代码示例
const chart = echarts.init(document.getElementById('chart'));
const option = {
title: { text: '图表标题' },
tooltip: {},
xAxis: { type: 'category', data: ['A','B','C'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [10, 20, 30] }]
};
chart.setOption(option);语法与用法
Option配置结构
代码示例
option = {
// 标题
title: { text: '标题', subtext: '副标题', left: 'center' },
// 提示框
tooltip: { trigger: 'axis' }, // 'axis' | 'item'
// 图例
legend: { data: ['系列1', '系列2'], top: 30 },
// 数据集
dataset: { source: [...] },
// 坐标轴
xAxis: { type: 'category' },
yAxis: { type: 'value' },
// 数据缩放
dataZoom: [{ type: 'slider' }, { type: 'inside' }],
// 视觉映射
visualMap: { min: 0, max: 100, inRange: { color: ['#fff', '#4e79a7'] } },
// 系列
series: [{ type: 'bar', data: [...] }]
};代码示例
示例1:ECharts多种图表类型与交互
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ECharts图表类型展示</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f5f7fa; padding: 20px; }
h1 { text-align: center; color: #2c3e50; margin-bottom: 20px; }
.chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(450px, 1fr)); gap: 20px; max-width: 1200px; margin: 0 auto; }
.chart-card { background: #fff; border-radius: 12px; padding: 15px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
.chart-box { width: 100%; height: 380px; }
</style>
</head>
<body>
<h1>ECharts 图表类型展示</h1>
<div class="chart-grid">
<div class="chart-card"><div class="chart-box" id="lineChart"></div></div>
<div class="chart-card"><div class="chart-box" id="barChart"></div></div>
<div class="chart-card"><div class="chart-box" id="pieChart"></div></div>
<div class="chart-card"><div class="chart-box" id="radarChart"></div></div>
</div>
<script>
const colors = ['#4e79a7','#f28e2b','#e15759','#76b7b2','#59a14f','#edc948','#b07aa1','#ff9da7'];
// 折线图
echarts.init(document.getElementById('lineChart')).setOption({
title: { text: '月度销售趋势', left: 'center', textStyle: { fontSize: 15 } },
tooltip: { trigger: 'axis' },
legend: { data: ['线上','线下'], top: 30 },
grid: { top: 70, bottom: 30, left: 50, right: 20 },
xAxis: { type: 'category', data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'], boundaryGap: false },
yAxis: { type: 'value', splitLine: { lineStyle: { color: '#f0f0f0' } } },
series: [
{ name: '线上', type: 'line', smooth: true, data: [120,150,180,210,195,230,250,220,260,310,280,320], areaStyle: { opacity: 0.15 }, lineStyle: { width: 2.5 }, itemStyle: { color: colors[0] } },
{ name: '线下', type: 'line', smooth: true, data: [80,90,110,130,145,160,155,140,170,200,190,210], areaStyle: { opacity: 0.15 }, lineStyle: { width: 2.5 }, itemStyle: { color: colors[1] } }
]
});
// 柱状图
echarts.init(document.getElementById('barChart')).setOption({
title: { text: '区域销售对比', left: 'center', textStyle: { fontSize: 15 } },
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { top: 30 },
grid: { top: 70, bottom: 30, left: 50, right: 20 },
xAxis: { type: 'category', data: ['Q1','Q2','Q3','Q4'] },
yAxis: { type: 'value', splitLine: { lineStyle: { color: '#f0f0f0' } } },
series: [
{ name: '华东', type: 'bar', data: [320,450,380,520], itemStyle: { color: colors[0], borderRadius: [4,4,0,0] } },
{ name: '华南', type: 'bar', data: [280,350,420,480], itemStyle: { color: colors[1], borderRadius: [4,4,0,0] } },
{ name: '华北', type: 'bar', data: [200,280,350,400], itemStyle: { color: colors[2], borderRadius: [4,4,0,0] } }
]
});
// 饼图
echarts.init(document.getElementById('pieChart')).setOption({
title: { text: '浏览器市场份额', left: 'center', textStyle: { fontSize: 15 } },
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
legend: { orient: 'vertical', right: 10, top: 'center' },
series: [{
type: 'pie',
radius: ['40%', '70%'],
center: ['40%', '55%'],
avoidLabelOverlap: true,
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
label: { show: true, formatter: '{b}\n{d}%' },
emphasis: { label: { fontSize: 16, fontWeight: 'bold' }, itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.2)' } },
data: [
{ value: 64.7, name: 'Chrome', itemStyle: { color: colors[0] } },
{ value: 18.8, name: 'Safari', itemStyle: { color: colors[1] } },
{ value: 5.3, name: 'Edge', itemStyle: { color: colors[3] } },
{ value: 3.2, name: 'Firefox', itemStyle: { color: colors[2] } },
{ value: 8.0, name: '其他', itemStyle: { color: colors[5] } }
]
}]
});
// 雷达图
echarts.init(document.getElementById('radarChart')).setOption({
title: { text: '产品能力评估', left: 'center', textStyle: { fontSize: 15 } },
tooltip: {},
legend: { data: ['产品A','产品B'], top: 30 },
radar: {
indicator: [
{ name: '性能', max: 100 }, { name: '易用性', max: 100 },
{ name: '安全性', max: 100 }, { name: '可扩展', max: 100 },
{ name: '稳定性', max: 100 }, { name: '文档', max: 100 }
],
splitArea: { areaStyle: { color: ['#fff','#f8f9ff','#fff','#f8f9ff','#fff'] } },
splitLine: { lineStyle: { color: '#eee' } },
axisLine: { lineStyle: { color: '#ddd' } }
},
series: [{
type: 'radar',
data: [
{ value: [85,70,90,75,88,65], name: '产品A', areaStyle: { opacity: 0.2 }, lineStyle: { color: colors[0], width: 2 }, itemStyle: { color: colors[0] } },
{ value: [70,85,75,90,72,80], name: '产品B', areaStyle: { opacity: 0.2 }, lineStyle: { color: colors[2], width: 2 }, itemStyle: { color: colors[2] } }
]
}]
});
// 响应式
window.addEventListener('resize', () => {
document.querySelectorAll('.chart-box').forEach(el => {
const chart = echarts.getInstanceByDom(el);
if (chart) chart.resize();
});
});
</script>
</body>
</html>示例2:ECharts数据集与视觉映射
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ECharts数据集与视觉映射</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f5f7fa; padding: 20px; }
.container { max-width: 1000px; margin: 0 auto; }
h1 { text-align: center; color: #2c3e50; margin-bottom: 20px; }
.chart-card { background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); margin-bottom: 20px; }
.chart-box { width: 100%; height: 420px; }
</style>
</head>
<body>
<div class="container">
<h1>ECharts 数据集与视觉映射</h1>
<div class="chart-card"><div class="chart-box" id="datasetChart"></div></div>
<div class="chart-card"><div class="chart-box" id="visualMapChart"></div></div>
</div>
<script>
// 数据集:同一数据源驱动多种图表
const salesSource = [
['月份', '线上', '线下', '成本'],
['1月', 120, 80, 95], ['2月', 150, 90, 110],
['3月', 180, 110, 130], ['4月', 210, 130, 150],
['5月', 195, 145, 140], ['6月', 230, 160, 165],
['7月', 250, 155, 175], ['8月', 220, 140, 160],
['9月', 260, 170, 185], ['10月', 310, 200, 215],
['11月', 280, 190, 200], ['12月', 320, 210, 225]
];
echarts.init(document.getElementById('datasetChart')).setOption({
title: { text: '数据集(Dataset)驱动多系列', left: 'center', textStyle: { fontSize: 15 } },
tooltip: { trigger: 'axis' },
legend: {},
dataset: { source: salesSource },
grid: { top: 70, bottom: 60, left: 55, right: 30 },
xAxis: { type: 'category' },
yAxis: { type: 'value', splitLine: { lineStyle: { color: '#f0f0f0' } } },
dataZoom: [{ type: 'slider', bottom: 10 }],
series: [
{ type: 'bar', name: '线上', itemStyle: { color: '#4e79a7', borderRadius: [4,4,0,0] } },
{ type: 'bar', name: '线下', itemStyle: { color: '#f28e2b', borderRadius: [4,4,0,0] } },
{ type: 'line', name: '成本', smooth: true, lineStyle: { width: 2.5, color: '#e15759' }, itemStyle: { color: '#e15759' } }
]
});
// 视觉映射:散点图+颜色映射
const scatterSource = [];
for (let i = 0; i < 100; i++) {
scatterSource.push([
Math.round(Math.random() * 100),
Math.round(Math.random() * 100),
Math.round(Math.random() * 1000)
]);
}
echarts.init(document.getElementById('visualMapChart')).setOption({
title: { text: '视觉映射(VisualMap) - 颜色与大小编码', left: 'center', textStyle: { fontSize: 15 } },
tooltip: {
formatter: function(p) {
return `X: ${p.data[0]}<br>Y: ${p.data[1]}<br>值: ${p.data[2]}`;
}
},
grid: { top: 60, bottom: 40, left: 55, right: 120 },
xAxis: { type: 'value', splitLine: { lineStyle: { color: '#f0f0f0' } } },
yAxis: { type: 'value', splitLine: { lineStyle: { color: '#f0f0f0' } } },
visualMap: [
{
dimension: 2,
min: 0,
max: 1000,
text: ['高', '低'],
textStyle: { color: '#666' },
inRange: { color: ['#59a14f', '#edc948', '#e15759'] },
right: 10,
top: 'center',
calculable: true
}
],
series: [{
type: 'scatter',
symbolSize: function(data) { return Math.sqrt(data[2]) / 2 + 5; },
data: scatterSource,
itemStyle: { borderColor: '#fff', borderWidth: 1 },
emphasis: { itemStyle: { borderColor: '#333', borderWidth: 2 } }
}]
});
window.addEventListener('resize', () => {
['datasetChart','visualMapChart'].forEach(id => {
const c = echarts.getInstanceByDom(document.getElementById(id));
if (c) c.resize();
});
});
</script>
</body>
</html>示例3:ECharts主题定制与仪表盘
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ECharts主题定制与仪表盘</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #1a1a2e; color: #e0e0e0; padding: 20px; }
.dashboard { max-width: 1100px; margin: 0 auto; }
.dash-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
.dash-title { font-size: 22px; font-weight: 300; color: #fff; }
.metrics-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 20px; }
.metric-card { background: #16213e; border-radius: 12px; padding: 18px; border: 1px solid #1a2a4a; }
.metric-label { font-size: 12px; color: #888; }
.metric-value { font-size: 28px; font-weight: 700; margin-top: 4px; }
.chart-row { display: grid; grid-template-columns: 2fr 1fr; gap: 15px; margin-bottom: 15px; }
.chart-card { background: #16213e; border-radius: 12px; padding: 18px; border: 1px solid #1a2a4a; }
.chart-box { width: 100%; height: 300px; }
@media (max-width: 768px) { .chart-row { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="dashboard">
<div class="dash-header">
<div class="dash-title">数据分析仪表盘</div>
<div style="font-size:12px;color:#4ecca3">实时更新</div>
</div>
<div class="metrics-row" id="metricsRow"></div>
<div class="chart-row">
<div class="chart-card"><div class="chart-box" id="trendChart"></div></div>
<div class="chart-card"><div class="chart-box" id="gaugeChart"></div></div>
</div>
<div class="chart-row">
<div class="chart-card"><div class="chart-box" id="funnelChart"></div></div>
<div class="chart-card"><div class="chart-box" id="pieChart2"></div></div>
</div>
</div>
<script>
// 暗色主题配置
const darkTheme = {
backgroundColor: 'transparent',
textStyle: { color: '#ccc' },
title: { textStyle: { color: '#eee' } },
legend: { textStyle: { color: '#aaa' } },
tooltip: { backgroundColor: 'rgba(22,33,62,0.95)', borderColor: '#1a2a4a', textStyle: { color: '#eee' } },
categoryAxis: { axisLine: { lineStyle: { color: '#333' } }, axisLabel: { color: '#888' }, splitLine: { lineStyle: { color: '#1a2a4a' } } },
valueAxis: { axisLine: { lineStyle: { color: '#333' } }, axisLabel: { color: '#888' }, splitLine: { lineStyle: { color: '#1a2a4a' } } }
};
// KPI指标
const kpis = [
{ label: '总收入', value: '¥1,280,000', color: '#4ecca3', change: '+12.5%' },
{ label: '活跃用户', value: '28,450', color: '#4e79a7', change: '+8.2%' },
{ label: '转化率', value: '3.8%', color: '#f28e2b', change: '+0.5%' },
{ label: '客单价', value: '¥456', color: '#e15759', change: '-2.1%' }
];
document.getElementById('metricsRow').innerHTML = kpis.map(k =>
`<div class="metric-card"><div class="metric-label">${k.label}</div><div class="metric-value" style="color:${k.color}">${k.value}</div><div style="font-size:12px;margin-top:4px;color:${k.change.startsWith('+')?'#4ecca3':'#e15759'}">${k.change}</div></div>`
).join('');
// 趋势图
echarts.init(document.getElementById('trendChart')).setOption({
...darkTheme,
title: { text: '收入趋势', left: 10, top: 5, textStyle: { fontSize: 14, color: '#eee' } },
tooltip: { trigger: 'axis' },
legend: { data: ['收入','支出'], top: 5, right: 10, textStyle: { color: '#aaa' } },
grid: { top: 40, bottom: 25, left: 50, right: 15 },
xAxis: { type: 'category', data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] },
yAxis: { type: 'value' },
series: [
{ name: '收入', type: 'line', smooth: true, data: [82,93,90,93,95,100,110,115,108,120,125,128], areaStyle: { opacity: 0.15 }, lineStyle: { color: '#4ecca3', width: 2.5 }, itemStyle: { color: '#4ecca3' } },
{ name: '支出', type: 'line', smooth: true, data: [60,65,62,68,70,72,78,80,75,82,85,88], areaStyle: { opacity: 0.1 }, lineStyle: { color: '#e15759', width: 2 }, itemStyle: { color: '#e15759' } }
]
});
// 仪表盘
echarts.init(document.getElementById('gaugeChart')).setOption({
...darkTheme,
title: { text: '系统健康度', left: 'center', top: 5, textStyle: { fontSize: 14, color: '#eee' } },
series: [{
type: 'gauge',
center: ['50%', '60%'],
radius: '85%',
min: 0, max: 100,
splitNumber: 5,
axisLine: { lineStyle: { width: 15, color: [[0.3,'#e15759'],[0.7,'#edc948'],[1,'#4ecca3']] } },
pointer: { width: 5, length: '70%', itemStyle: { color: '#eee' } },
axisTick: { length: 8, lineStyle: { color: 'auto' } },
splitLine: { length: 15, lineStyle: { color: 'auto' } },
axisLabel: { color: '#888', fontSize: 10, distance: 20 },
detail: { formatter: '{value}%', fontSize: 22, color: '#4ecca3', offsetCenter: [0, '70%'] },
data: [{ value: 87, name: '健康度' }],
title: { color: '#888', fontSize: 12, offsetCenter: [0, '90%'] }
}]
});
// 漏斗图
echarts.init(document.getElementById('funnelChart')).setOption({
...darkTheme,
title: { text: '转化漏斗', left: 10, top: 5, textStyle: { fontSize: 14, color: '#eee' } },
tooltip: { trigger: 'item', formatter: '{b}: {c}' },
series: [{
type: 'funnel',
left: '10%', top: 40, bottom: 10, width: '80%',
min: 0, max: 100,
sort: 'descending',
gap: 4,
label: { show: true, position: 'inside', color: '#fff', fontSize: 12 },
itemStyle: { borderColor: '#16213e', borderWidth: 2 },
data: [
{ value: 100, name: '访问', itemStyle: { color: '#4e79a7' } },
{ value: 60, name: '注册', itemStyle: { color: '#f28e2b' } },
{ value: 35, name: '下单', itemStyle: { color: '#59a14f' } },
{ value: 20, name: '支付', itemStyle: { color: '#e15759' } },
{ value: 8, name: '复购', itemStyle: { color: '#76b7b2' } }
]
}]
});
// 饼图
echarts.init(document.getElementById('pieChart2')).setOption({
...darkTheme,
title: { text: '流量来源', left: 10, top: 5, textStyle: { fontSize: 14, color: '#eee' } },
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
series: [{
type: 'pie',
radius: ['35%', '65%'],
center: ['50%', '55%'],
itemStyle: { borderRadius: 5, borderColor: '#16213e', borderWidth: 2 },
label: { color: '#aaa', fontSize: 11 },
data: [
{ value: 45, name: '自然搜索', itemStyle: { color: '#4e79a7' } },
{ value: 25, name: '社交媒体', itemStyle: { color: '#f28e2b' } },
{ value: 15, name: '直接访问', itemStyle: { color: '#59a14f' } },
{ value: 10, name: '付费广告', itemStyle: { color: '#e15759' } },
{ value: 5, name: '其他', itemStyle: { color: '#76b7b2' } }
]
}]
});
window.addEventListener('resize', () => {
['trendChart','gaugeChart','funnelChart','pieChart2'].forEach(id => {
const c = echarts.getInstanceByDom(document.getElementById(id));
if (c) c.resize();
});
});
</script>
</body>
</html>浏览器兼容性
注意事项与最佳实践
渲染器选择:大数据量用Canvas渲染器(默认),需要精细交互用SVG渲染器。
响应式:监听窗口resize事件调用
chart.resize()。内存管理:不再使用的图表调用
chart.dispose()释放资源。大数据优化:使用
large: true和progressiveChunkMode处理大数据。主题定制:通过
echarts.registerTheme()注册自定义主题。数据集优先:使用dataset管理数据,比series内联数据更灵活。
动画控制:大数据量时关闭动画
animation: false。按需引入:使用ECharts的按需引入功能减小包体积。
代码规范示例
代码示例
// 好的做法:ECharts封装类
class EChartsWrapper {
constructor(el, theme) {
this.chart = echarts.init(el, theme);
this._resizeHandler = () => this.chart.resize();
window.addEventListener('resize', this._resizeHandler);
}
setOption(option, opts) {
this.chart.setOption(option, opts);
}
resize() {
this.chart.resize();
}
dispose() {
window.removeEventListener('resize', this._resizeHandler);
this.chart.dispose();
}
showLoading() {
this.chart.showLoading('default', { text: '加载中...', color: '#4e79a7' });
}
hideLoading() {
this.chart.hideLoading();
}
}常见问题与解决方案
问题1:图表不显示
原因:容器高度为0。
解决方案:确保容器有明确的高度(不能仅依赖内容撑开)。
问题2:resize后图表变形
原因:未调用chart.resize()。
解决方案:监听resize事件并调用chart.resize()。
问题3:大数据量渲染慢
解决方案:开启large: true,使用增量渲染progressive: 200,关闭动画。
问题4:主题不生效
原因:自定义主题未注册。
解决方案:使用echarts.registerTheme('myTheme', themeConfig)注册后再使用。
总结
本教程全面讲解了ECharts图表库的使用:
安装与配置:CDN引入、Option配置结构
图表类型:30+种图表,涵盖折线、柱状、饼图、雷达、仪表盘、漏斗等
数据集(dataset):统一数据源驱动多系列
视觉映射:颜色、大小自动映射数据维度
交互组件:tooltip、dataZoom、legend等
主题定制:暗色主题、自定义颜色方案
仪表盘设计:KPI卡片+多图表组合
大数据优化:large模式、增量渲染
ECharts是构建企业级数据可视化应用的强大工具,掌握其配置和优化能力可以高效构建专业的数据可视化系统。
常见问题
什么是ECharts图表库?
ECharts图表库是HTML5开发中的重要技术,本教程详细介绍了其核心概念和实践方法。
如何学习ECharts图表库的实际应用?
教程中提供了完整的代码示例和实践指导,建议结合示例代码动手练习。
ECharts图表库有哪些注意事项?
常见注意事项包括兼容性、性能优化等,教程的注意事项与最佳实践部分有详细说明。
ECharts图表库适合初学者吗?
本教程从基础概念讲起,循序渐进,适合有一定HTML和JavaScript基础的初学者。
ECharts图表库的核心要点是什么?
核心要点包括教程简介等内容,建议按教程顺序逐步学习。
本文由小确幸生活整理发布,转载请注明出处
本文涉及AI创作
内容由AI创作,请仔细甄别