引言
Echarts 是一个由百度开源的功能强大的 JavaScript 图表库,广泛应用于数据可视化领域。它提供了丰富的图表类型、灵活的配置项和出色的交互体验,非常适合初学者和专业人士使用。本文将为零基础学习者提供一条从基础概念到实战项目的完整学习路线,帮助你系统地掌握 Echarts 的使用。
第一部分:基础概念与环境搭建
1.1 什么是 Echarts?
Echarts(Enterprise Charts)是一个使用 JavaScript 实现的开源可视化库,可以流畅地运行在 PC 和移动设备上。它最初由百度团队开发,现在由 Apache 基金会维护。Echarts 支持多种图表类型,包括折线图、柱状图、饼图、散点图、地图等,并且支持高度定制化。
1.2 环境搭建
在开始使用 Echarts 之前,你需要搭建一个基本的开发环境。以下是几种常见的引入方式:
方式一:通过 CDN 引入(推荐初学者)
<!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>
<!-- 引入 Echarts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<!-- 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
方式二:通过 npm 安装(适合项目开发)
# 安装 Echarts
npm install echarts --save
# 或者使用 yarn
yarn add echarts
在 Vue 或 React 项目中引入:
// Vue 项目中引入
import * as echarts from 'echarts';
// React 项目中引入
import * as echarts from 'echarts';
1.3 核心概念理解
在使用 Echarts 之前,需要理解几个核心概念:
- 实例(Instance):每个 Echarts 图表都是一个独立的实例,通过
echarts.init()创建。 - 配置项(Option):图表的所有配置都通过一个 JavaScript 对象(option)来定义。
- 系列(Series):图表的数据系列,可以包含多个系列,每个系列对应一种图表类型。
- 坐标系(Coordinate System):图表的坐标系统,如直角坐标系、极坐标系等。
第二部分:基础图表类型与配置
2.1 柱状图(Bar Chart)
柱状图是最常用的图表之一,用于比较不同类别的数据。
// 柱状图配置示例
var option = {
title: {
text: '2023年各季度销售额',
subtext: '单位:万元',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['电子产品', '服装', '食品'],
top: 30
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['Q1', 'Q2', 'Q3', 'Q4']
},
yAxis: {
type: 'value',
name: '销售额(万元)'
},
series: [
{
name: '电子产品',
type: 'bar',
data: [320, 332, 301, 334],
itemStyle: {
color: '#5470c6'
}
},
{
name: '服装',
type: 'bar',
stack: '总量',
data: [220, 182, 191, 234],
itemStyle: {
color: '#91cc75'
}
},
{
name: '食品',
type: 'bar',
data: [150, 212, 201, 154],
itemStyle: {
color: '#fac858'
}
}
]
};
2.2 折线图(Line Chart)
折线图用于显示数据随时间或其他连续变量的变化趋势。
// 折线图配置示例
var option = {
title: {
text: '2023年月度用户增长趋势',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['新增用户', '活跃用户'],
top: 30
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
},
yAxis: {
type: 'value',
name: '用户数'
},
series: [
{
name: '新增用户',
type: 'line',
data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330],
smooth: true,
lineStyle: {
width: 3
},
areaStyle: {
opacity: 0.3
}
},
{
name: '活跃用户',
type: 'line',
data: [220, 182, 191, 234, 290, 330, 310, 282, 291, 334, 390, 430],
smooth: true,
lineStyle: {
width: 3
},
areaStyle: {
opacity: 0.3
}
}
]
};
2.3 饼图(Pie Chart)
饼图用于显示各部分占总体的比例关系。
// 饼图配置示例
var option = {
title: {
text: '2023年产品销售占比',
subtext: '按产品类别',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: ['电子产品', '服装', '食品', '家居', '其他']
},
series: [
{
name: '销售额',
type: 'pie',
radius: '50%',
data: [
{ value: 335, name: '电子产品' },
{ value: 310, name: '服装' },
{ value: 234, name: '食品' },
{ value: 135, name: '家居' },
{ value: 154, name: '其他' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
itemStyle: {
borderRadius: 5,
borderColor: '#fff',
borderWidth: 2
}
}
]
};
2.4 散点图(Scatter Chart)
散点图用于显示两个变量之间的关系。
// 散点图配置示例
var option = {
title: {
text: '身高与体重关系',
left: 'center'
},
tooltip: {
formatter: function (params) {
return `身高: ${params.value[0]}cm<br/>体重: ${params.value[1]}kg`;
}
},
xAxis: {
name: '身高(cm)',
scale: true
},
yAxis: {
name: '体重(kg)',
scale: true
},
series: [
{
name: '男性',
type: 'scatter',
symbolSize: 10,
data: [
[170, 65], [175, 70], [180, 75], [185, 80], [190, 85],
[165, 60], [172, 68], [178, 73], [182, 78], [188, 82]
],
itemStyle: {
color: '#5470c6'
}
},
{
name: '女性',
type: 'scatter',
symbolSize: 10,
data: [
[155, 50], [160, 55], [165, 60], [170, 65], [175, 70],
[150, 45], [158, 52], [162, 58], [168, 63], [172, 68]
],
itemStyle: {
color: '#91cc75'
}
}
]
};
第三部分:高级配置与交互
3.1 响应式布局
Echarts 图表需要适应容器大小的变化,可以通过监听窗口大小变化来实现响应式。
// 响应式布局示例
function initChart() {
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
// 配置项...
var option = { /* ... */ };
myChart.setOption(option);
// 监听窗口大小变化
window.addEventListener('resize', function() {
myChart.resize();
});
}
// 在页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initChart);
3.2 交互功能
Echarts 提供了丰富的交互功能,如提示框(Tooltip)、图例(Legend)、数据区域缩放(DataZoom)等。
// 带有交互功能的折线图
var option = {
title: {
text: '2023年月度销售额',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['销售额', '利润'],
top: 30
},
dataZoom: [
{
type: 'slider',
show: true,
xAxisIndex: [0],
start: 0,
end: 100
},
{
type: 'inside',
xAxisIndex: [0],
start: 0,
end: 100
}
],
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
},
yAxis: {
type: 'value',
name: '金额(万元)'
},
series: [
{
name: '销售额',
type: 'line',
data: [820, 932, 901, 934, 1290, 1330, 1320, 1282, 1291, 1334, 1390, 1430],
smooth: true,
lineStyle: {
width: 3
}
},
{
name: '利润',
type: 'line',
data: [220, 182, 191, 234, 290, 330, 310, 282, 291, 334, 390, 430],
smooth: true,
lineStyle: {
width: 3
}
}
]
};
3.3 动态数据更新
Echarts 支持动态更新数据,这对于实时数据可视化非常重要。
// 动态更新数据示例
var myChart = echarts.init(document.getElementById('main'));
var option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
};
myChart.setOption(option);
// 模拟实时数据更新
setInterval(function() {
// 生成随机数据
var newData = [];
for (var i = 0; i < 7; i++) {
newData.push(Math.floor(Math.random() * 1000) + 500);
}
// 更新数据
myChart.setOption({
series: [{
data: newData
}]
});
}, 2000);
第四部分:实战项目:销售数据仪表盘
4.1 项目需求分析
我们将创建一个销售数据仪表盘,包含以下组件:
- 总销售额统计卡片
- 月度销售额趋势图(折线图)
- 产品类别占比图(饼图)
- 区域销售分布图(地图)
- 销售员业绩排行榜(柱状图)
4.2 项目结构
<!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>
body {
font-family: 'Microsoft YaHei', sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 20px;
}
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: 100px 300px 300px;
gap: 15px;
max-width: 1400px;
margin: 0 auto;
}
.card {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.card-title {
font-size: 14px;
color: #666;
margin-bottom: 10px;
}
.card-value {
font-size: 28px;
font-weight: bold;
color: #333;
}
.chart-container {
width: 100%;
height: 100%;
}
/* 网格布局 */
.stat-card-1 { grid-column: 1 / 2; }
.stat-card-2 { grid-column: 2 / 3; }
.stat-card-3 { grid-column: 3 / 4; }
.stat-card-4 { grid-column: 4 / 5; }
.chart-trend { grid-column: 1 / 3; grid-row: 2 / 3; }
.chart-pie { grid-column: 3 / 5; grid-row: 2 / 3; }
.chart-map { grid-column: 1 / 3; grid-row: 3 / 4; }
.chart-bar { grid-column: 3 / 5; grid-row: 3 / 4; }
</style>
</head>
<body>
<div class="dashboard">
<!-- 统计卡片 -->
<div class="card stat-card-1">
<div class="card-title">总销售额</div>
<div class="card-value">¥2,456,789</div>
</div>
<div class="card stat-card-2">
<div class="card-title">本月销售额</div>
<div class="card-value">¥345,678</div>
</div>
<div class="card stat-card-3">
<div class="card-title">订单数量</div>
<div class="card-value">1,234</div>
</div>
<div class="card stat-card-4">
<div class="card-title">客户数量</div>
<div class="card-value">567</div>
</div>
<!-- 图表区域 -->
<div class="card chart-trend">
<div class="card-title">月度销售额趋势</div>
<div id="trendChart" class="chart-container"></div>
</div>
<div class="card chart-pie">
<div class="card-title">产品类别占比</div>
<div id="pieChart" class="chart-container"></div>
</div>
<div class="card chart-map">
<div class="card-title">区域销售分布</div>
<div id="mapChart" class="chart-container"></div>
</div>
<div class="card chart-bar">
<div class="card-title">销售员业绩排行</div>
<div id="barChart" class="chart-container"></div>
</div>
</div>
<script>
// 初始化所有图表
function initDashboard() {
initTrendChart();
initPieChart();
initMapChart();
initBarChart();
}
// 1. 月度销售额趋势图
function initTrendChart() {
var chart = echarts.init(document.getElementById('trendChart'));
var option = {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['销售额', '利润'],
bottom: 0
},
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月']
},
yAxis: {
type: 'value',
name: '金额(万元)'
},
series: [
{
name: '销售额',
type: 'line',
data: [820, 932, 901, 934, 1290, 1330, 1320, 1282, 1291, 1334, 1390, 1430],
smooth: true,
lineStyle: { width: 3 },
areaStyle: { opacity: 0.3 }
},
{
name: '利润',
type: 'line',
data: [220, 182, 191, 234, 290, 330, 310, 282, 291, 334, 390, 430],
smooth: true,
lineStyle: { width: 3 },
areaStyle: { opacity: 0.3 }
}
]
};
chart.setOption(option);
window.addEventListener('resize', () => chart.resize());
}
// 2. 产品类别占比图
function initPieChart() {
var chart = echarts.init(document.getElementById('pieChart'));
var option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'middle'
},
series: [
{
name: '销售额',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 5,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 16,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 1048, name: '电子产品' },
{ value: 735, name: '服装' },
{ value: 580, name: '食品' },
{ value: 484, name: '家居' },
{ value: 300, name: '其他' }
]
}
]
};
chart.setOption(option);
window.addEventListener('resize', () => chart.resize());
}
// 3. 区域销售分布图(使用中国地图)
function initMapChart() {
var chart = echarts.init(document.getElementById('mapChart'));
// 注意:实际项目中需要引入中国地图数据
// 这里使用模拟数据演示
var option = {
tooltip: {
trigger: 'item',
formatter: '{b}<br/>销售额: {c}万元'
},
visualMap: {
min: 0,
max: 500,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true,
inRange: {
color: ['#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
}
},
series: [
{
name: '销售额',
type: 'map',
map: 'china',
roam: false,
emphasis: {
label: {
show: true
}
},
data: [
{ name: '北京', value: 320 },
{ name: '天津', value: 180 },
{ name: '上海', value: 450 },
{ name: '重庆', value: 220 },
{ name: '河北', value: 150 },
{ name: '河南', value: 200 },
{ name: '云南', value: 80 },
{ name: '辽宁', value: 120 },
{ name: '黑龙江', value: 90 },
{ name: '湖南', value: 160 },
{ name: '安徽', value: 140 },
{ name: '山东', value: 280 },
{ name: '新疆', value: 60 },
{ name: '江苏', value: 350 },
{ name: '浙江', value: 400 },
{ name: '江西', value: 130 },
{ name: '湖北', value: 190 },
{ name: '广西', value: 110 },
{ name: '甘肃', value: 70 },
{ name: '山西', value: 100 },
{ name: '内蒙古', value: 85 },
{ name: '陕西', value: 170 },
{ name: '吉林', value: 95 },
{ name: '福建', value: 210 },
{ name: '贵州', value: 75 },
{ name: '广东', value: 480 },
{ name: '青海', value: 50 },
{ name: '西藏', value: 30 },
{ name: '四川', value: 240 },
{ name: '宁夏', value: 55 },
{ name: '海南', value: 65 },
{ name: '台湾', value: 100 },
{ name: '香港', value: 150 },
{ name: '澳门', value: 80 }
]
}
]
};
// 注意:实际使用时需要注册地图
// echarts.registerMap('china', chinaJson);
chart.setOption(option);
window.addEventListener('resize', () => chart.resize());
}
// 4. 销售员业绩排行榜
function initBarChart() {
var chart = echarts.init(document.getElementById('barChart'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value',
name: '销售额(万元)'
},
yAxis: {
type: 'category',
data: ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九']
},
series: [
{
name: '销售额',
type: 'bar',
data: [320, 302, 301, 334, 390, 330, 320],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
},
label: {
show: true,
position: 'right',
formatter: '{c}'
}
}
]
};
chart.setOption(option);
window.addEventListener('resize', () => chart.resize());
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initDashboard);
</script>
</body>
</html>
4.3 项目优化与扩展
4.3.1 数据动态加载
// 使用 Fetch API 动态加载数据
async function loadChartData() {
try {
const response = await fetch('/api/sales-data');
const data = await response.json();
// 更新趋势图
trendChart.setOption({
series: [
{ data: data.trend.sales },
{ data: data.trend.profit }
]
});
// 更新饼图
pieChart.setOption({
series: [{
data: data.pie
}]
});
// 更新地图
mapChart.setOption({
series: [{
data: data.map
}]
});
// 更新柱状图
barChart.setOption({
series: [{
data: data.bar
}]
});
// 更新统计卡片
document.querySelector('.stat-card-1 .card-value').textContent =
`¥${data.stats.total.toLocaleString()}`;
document.querySelector('.stat-card-2 .card-value').textContent =
`¥${data.stats.month.toLocaleString()}`;
document.querySelector('.stat-card-3 .card-value').textContent =
data.stats.orders.toLocaleString();
document.querySelector('.stat-card-4 .card-value').textContent =
data.stats.customers.toLocaleString();
} catch (error) {
console.error('加载数据失败:', error);
}
}
// 每30秒自动刷新数据
setInterval(loadChartData, 30000);
4.3.2 主题切换
Echarts 支持自定义主题,可以轻松实现深色模式切换。
// 自定义深色主题
const darkTheme = {
color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
backgroundColor: 'rgba(0,0,0,0.8)',
textStyle: {
color: '#ccc'
},
title: {
textStyle: {
color: '#eee'
}
},
legend: {
textStyle: {
color: '#ccc'
}
},
tooltip: {
backgroundColor: 'rgba(0,0,0,0.8)',
textStyle: {
color: '#eee'
}
}
};
// 注册主题
echarts.registerTheme('dark', darkTheme);
// 使用主题初始化图表
var chart = echarts.init(document.getElementById('main'), 'dark');
第五部分:进阶学习与资源推荐
5.1 进阶功能
- 3D图表:Echarts 支持3D柱状图、3D饼图等。
- 自定义图形:通过
graphic组件绘制自定义图形。 - 混合图表:在同一图表中组合多种图表类型。
- 大数据量优化:使用
large模式处理大量数据。 - WebGL渲染:使用 Echarts GL 进行高性能渲染。
5.2 常见问题与解决方案
问题1:图表不显示或显示不全
解决方案:
- 确保容器有明确的宽高
- 检查 Echarts 是否正确引入
- 确保在 DOM 加载完成后初始化
问题2:图表在移动端显示异常
解决方案:
- 使用响应式布局
- 调整字体大小和间距
- 考虑使用
dataZoom简化显示
问题3:大数据量导致卡顿
解决方案:
- 使用
large模式 - 开启
progressive渲染 - 减少不必要的动画效果
5.3 学习资源推荐
- 官方文档:https://echarts.apache.org/zh/index.html
- 示例库:https://echarts.apache.org/examples/zh/index.html
- GitHub仓库:https://github.com/apache/echarts
- 社区论坛:https://github.com/apache/echarts/discussions
- 视频教程:B站、YouTube 上的 Echarts 系列教程
结语
通过本文的学习路线,你已经从零基础开始,逐步掌握了 Echarts 的基本概念、基础图表配置、高级交互功能,并完成了一个完整的实战项目。数据可视化是一个不断发展的领域,建议持续关注 Echarts 的更新和社区动态,不断实践和探索新的可视化方案。
记住,最好的学习方式是动手实践。尝试将 Echarts 应用到你的实际项目中,解决真实的数据可视化问题,这样才能真正掌握这个强大的工具。祝你学习愉快!
