ECharts高级功能
知识点总览
| 任务 |
核心知识点 |
| 任务一:下载和应用主题 |
主题下载、主题注册、主题应用、自定义主题 |
| 任务二:设置富文本标签 |
文本块(rich)、文本片段样式、格式化函数、样式继承 |
| 任务三:三维可视化 |
GL扩展库引入、三维柱状图、三维散点图、三维曲面图 |
| 任务四:实现异步加载 |
异步数据加载、Loading动画、动态更新、定时刷新 |
任务一:下载和应用主题
1.1 主题的下载
知识点
- ECharts主题:预定义的图表样式配置集合,包含颜色、字体、背景等。
- 官方主题 :ECharts提供多种内置主题(如
light、dark)。
- 自定义主题:可通过主题构建工具生成或手动配置。
主题下载方式
html
复制代码
<!-- 方式一:使用 ECharts 内置主题 -->
<!-- 无需额外引入,直接在初始化时指定主题名称 -->
<!-- 方式二:引入外部主题 JS 文件 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/theme/dark.js"></script>
<!-- 方式三:下载主题 JSON 后注册 -->
<script src="js/myTheme.js"></script>
内置主题列表
| 主题名称 |
说明 |
适用场景 |
light |
浅色主题(默认) |
常规报表、白底页面 |
dark |
深色主题 |
大屏展示、科技感页面 |
1.2 主题的应用
语法
javascript
复制代码
// 方式一:初始化时指定主题
const chart = echarts.init(domElement, 'themeName');
// 方式二:注册自定义主题后使用
echarts.registerTheme('myTheme', themeObject);
const chart = echarts.init(domElement, 'myTheme');
案例代码:设置矩形树图的主题
javascript
复制代码
// 完整案例:为矩形树图设置多种主题并进行切换
const chartDom = document.getElementById('treemapChart');
let currentChart = null;
// ========== 1. 定义自定义主题 ==========
// 自定义主题配置对象(继承默认主题)
const customTheme = {
// 全局颜色调色板
color: ['#4dabf7', '#69db7e', '#ff8787', '#ffd43b', '#be4bdb', '#15aabf'],
// 背景色
backgroundColor: '#f8f9fa',
// 文本样式
textStyle: {
fontFamily: 'Microsoft YaHei, sans-serif',
fontSize: 12,
color: '#212529'
},
// 标题样式
title: {
textStyle: { color: '#212529', fontSize: 16, fontWeight: 'bold' },
subtextStyle: { color: '#868e96', fontSize: 12 }
},
// 工具提示
tooltip: {
backgroundColor: 'rgba(0,0,0,0.8)',
borderColor: '#4dabf7',
borderWidth: 1,
textStyle: { color: '#fff', fontSize: 12 }
},
// 矩形树图特定样式
series: {
treemap: {
itemStyle: {
borderColor: '#fff',
borderWidth: 2,
gapWidth: 2
},
label: {
show: true,
fontSize: 12,
fontWeight: 'normal',
color: '#fff'
},
breadcrumb: {
itemStyle: { color: '#4dabf7' }
}
}
}
};
// ========== 2. 准备数据 ==========
const treemapData = {
name: '电动汽车销量',
children: [
{
name: '品牌A',
children: [
{ name: 'A1型号', value: 1250 },
{ name: 'A2型号', value: 980 },
{ name: 'A3型号', value: 720 }
]
},
{
name: '品牌B',
children: [
{ name: 'B1型号', value: 2100 },
{ name: 'B2型号', value: 1850 },
{ name: 'B3型号', value: 1430 }
]
},
{
name: '品牌C',
children: [
{ name: 'C1型号', value: 950 },
{ name: 'C2型号', value: 870 },
{ name: 'C3型号', value: 620 }
]
}
]
};
// ========== 3. 注册并使用自定义主题 ==========
// 注册主题(主题名称:myCustomTheme)
echarts.registerTheme('myCustomTheme', customTheme);
// 使用自定义主题初始化图表
const myChart = echarts.init(chartDom, 'myCustomTheme');
// 设置图表配置
const option = {
title: {
text: '各品牌电动汽车销量矩形树图',
subtext: '使用自定义主题 | 矩形面积越大销量越高',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} 辆'
},
series: [{
type: 'treemap',
data: [treemapData],
visualMin: 500,
visualMax: 2100,
colorMappingBy: 'value',
leafDepth: 2,
levels: [
{ show: false }, // 根节点
{ color: ['#4dabf7', '#69db7e', '#ff8787'] }, // 品牌层
{ colorSaturation: [0.5, 0.9], label: { fontSize: 11 } } // 型号层
]
}]
};
myChart.setOption(option);
// ========== 4. 主题切换功能(可选) ==========
// 创建主题切换按钮功能
function switchTheme(themeName) {
// 销毁当前图表实例
myChart.dispose();
// 使用新主题重新初始化
const newChart = echarts.init(chartDom, themeName);
// 重新设置配置
newChart.setOption(option);
// 将新实例保存到全局(可选)
return newChart;
}
// 示例:切换到 dark 主题
// const darkChart = switchTheme('dark');
// 示例:切换到自定义主题
// const customChart = switchTheme('myCustomTheme');
任务二:设置富文本标签
2.1 文本块和文本片段
知识点
- 富文本标签(Rich Text Label):在图表标签中混合多种样式(不同字体、颜色、大小)。
- 文本块(Text Block):标签的整体容器,可设置对齐方式、边距等。
- 文本片段(Text Fragment) :文本块内的独立样式单元,通过
rich 配置定义。
语法结构
javascript
复制代码
label: {
show: true,
formatter: '{a|前缀} {b|主体} {c|后缀}', // 使用 | 分隔样式块
rich: {
a: { color: 'red', fontSize: 12 }, // 样式块 a
b: { color: 'blue', fontWeight: 'bold' },// 样式块 b
c: { color: 'green', fontSize: 10 } // 样式块 c
}
}
2.2 富文本标签的设置
案例代码:为南丁格尔玫瑰图设置富文本标签
javascript
复制代码
// 南丁格尔玫瑰图(极坐标柱状图)+ 富文本标签
const chartDom = document.getElementById('roseChart');
const myChart = echarts.init(chartDom);
// 准备数据:各品牌电动汽车销量
const brands = ['品牌A', '品牌B', '品牌C', '品牌D', '品牌E', '品牌F'];
const sales = [1250, 2100, 950, 1680, 1430, 880];
const growthRates = [12.5, 23.8, 8.6, 18.2, 15.4, 6.3]; // 同比增长率(%)
const option = {
title: {
text: '各品牌电动汽车销量玫瑰图',
subtext: '半径表示销量 | 角度表示品牌',
left: 'center',
top: 10
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>销量: {c} 辆<br/>同比增长: {d}%',
params: { d: growthRates }
},
legend: {
data: brands,
orient: 'vertical',
left: 'left',
top: 'center'
},
// 极坐标系
polar: {
radius: [20, '75%'], // 半径范围(内径20,外径75%)
center: ['50%', '55%'] // 圆心位置
},
// 角度轴(分类轴)
angleAxis: {
type: 'category',
data: brands,
axisLabel: { show: false } // 隐藏默认标签,使用富文本替代
},
// 半径轴(数值轴)
radiusAxis: {
type: 'value',
axisLabel: { show: true },
axisLine: { show: false },
axisTick: { show: false }
},
series: [{
type: 'bar', // 柱状图(在极坐标中即为玫瑰图)
data: sales,
coordinateSystem: 'polar', // 使用极坐标系
barCategoryGap: '20%', // 柱子间距
// 标签样式(核心:富文本配置)
label: {
show: true,
position: 'outside', // 标签位置:outside/inside
// 富文本格式化:使用多段样式
// {a|品牌名} 换行 {b|销量} 换行 {c|增长率}
formatter: function(params) {
// params.name: 品牌名
// params.value: 销量
const brand = params.name;
const sale = params.value;
const rate = growthRates[params.dataIndex];
// 根据增长率正负显示不同箭头
const arrow = rate > 0 ? '▲' : '▼';
const rateColor = rate > 0 ? '#e74c3c' : '#27ae60';
// 返回富文本格式字符串
return `{name|${brand}}\n{sale|${sale}辆}\n{rate|${arrow} ${Math.abs(rate)}%}`;
},
// 富文本样式定义
rich: {
// 品牌名样式
name: {
fontSize: 14,
fontWeight: 'bold',
color: '#2c3e50',
fontFamily: 'Microsoft YaHei',
lineHeight: 22,
backgroundColor: 'rgba(255,255,255,0.7)',
padding: [2, 6, 2, 6],
borderRadius: 4
},
// 销量样式
sale: {
fontSize: 12,
color: '#2980b9',
fontWeight: 'normal',
lineHeight: 20,
fontFamily: 'Arial'
},
// 增长率样式(动态设置,这里用默认)
rate: {
fontSize: 11,
fontWeight: 'bold',
lineHeight: 18,
padding: [2, 4, 2, 4],
borderRadius: 10
}
}
},
// 柱子颜色
itemStyle: {
borderRadius: [4, 4, 0, 0], // 顶部圆角
color: function(params) {
// 根据销量动态设置颜色深浅
const colors = ['#74b9ff', '#a29bfe', '#fd79a8', '#fdcb6e', '#00cec9', '#e17055'];
return colors[params.dataIndex % colors.length];
},
shadowBlur: 10,
shadowColor: 'rgba(0,0,0,0.2)'
}
}]
};
myChart.setOption(option);
拓展:饼图富文本标签
javascript
复制代码
// 饼图富文本标签示例(支持引导线)
const pieOption = {
series: [{
type: 'pie',
data: [
{ value: 1250, name: '品牌A' },
{ value: 2100, name: '品牌B' },
{ value: 950, name: '品牌C' }
],
label: {
show: true,
position: 'outside',
formatter: '{icon|}{name| {b}}\n{value| {d}%}',
rich: {
icon: {
fontSize: 14,
color: '#fff',
backgroundColor: '#4dabf7',
width: 20,
height: 20,
borderRadius: 10,
align: 'center',
padding: [2, 0, 0, 0],
formatter: '●'
},
name: { fontSize: 12, fontWeight: 'bold', color: '#333' },
value: { fontSize: 11, color: '#666' }
}
},
labelLine: { length: 15, length2: 10, smooth: true }
}]
};
任务三:三维可视化
3.1 GL扩展库
知识点
- ECharts GL:ECharts 的扩展库,用于绘制三维图表(3D柱状图、3D散点图、3D曲面图等)。
- 引入方式 :在 ECharts 之后引入
echarts-gl 扩展。
引入方式
html
复制代码
<!-- 先引入 ECharts 核心库 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<!-- 再引入 ECharts GL 扩展库 -->
<script src="https://cdn.jsdelivr.net/npm/echarts-gl@2/dist/echarts-gl.min.js"></script>
支持的三维图表类型
| 图表类型 |
配置 type |
说明 |
| 三维柱状图 |
bar3D |
在三维空间展示柱状数据 |
| 三维散点图 |
scatter3D |
展示三维坐标点分布 |
| 三维曲面图 |
surface |
展示函数曲面或地形数据 |
| 三维地图 |
map3D |
3D 地球或区域地图 |
3.2 三维图表的绘制
案例代码:绘制各品牌电动汽车的销量三维柱状图
javascript
复制代码
// 三维柱状图:展示各品牌在不同季度的销量
const chartDom = document.getElementById('bar3dChart');
const myChart = echarts.init(chartDom);
// 准备数据:品牌(x轴)、季度(y轴)、销量(z轴)
const brands = ['品牌A', '品牌B', '品牌C', '品牌D', '品牌E'];
const quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
// 生成销量数据 [品牌索引, 季度索引, 销量]
const salesData = [
// 品牌A 各季度销量
[0, 0, 320], [0, 1, 450], [0, 2, 580], [0, 3, 620],
// 品牌B
[1, 0, 510], [1, 1, 680], [1, 2, 750], [1, 3, 890],
// 品牌C
[2, 0, 230], [2, 1, 310], [2, 2, 420], [2, 3, 380],
// 品牌D
[3, 0, 420], [3, 1, 530], [3, 2, 610], [3, 3, 670],
// 品牌E
[4, 0, 180], [4, 1, 250], [4, 2, 340], [4, 3, 390]
];
const option = {
title: {
text: '各品牌电动汽车季度销量三维柱状图',
subtext: 'X轴: 品牌 | Y轴: 季度 | Z轴: 销量(辆)',
left: 'center',
top: 10
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return `${brands[params.data[0]]} - ${quarters[params.data[1]]}<br/>销量: ${params.data[2]} 辆`;
}
},
// 三维坐标系配置
xAxis3D: {
type: 'category',
data: brands,
name: '品牌',
nameLocation: 'middle',
nameGap: 30,
axisLabel: { rotate: 30, fontSize: 11 }
},
yAxis3D: {
type: 'category',
data: quarters,
name: '季度',
nameLocation: 'middle',
nameGap: 40
},
zAxis3D: {
type: 'value',
name: '销量(辆)',
nameLocation: 'middle',
nameGap: 40,
min: 0,
max: 1000,
axisLabel: { fontSize: 11 }
},
// 三维视觉配置
visualMap: {
show: true,
min: 0,
max: 900,
calculable: true,
inRange: {
color: ['#2c7bb6', '#abd9e9', '#ffffbf', '#fdae61', '#d7191c'] // 颜色渐变
},
outOfRange: { color: ['#999'] },
left: 'left',
top: 'bottom'
},
// 三维图表系列
series: [{
type: 'bar3D', // 图表类型:三维柱状图
data: salesData, // 数据格式 [x, y, z]
// 柱状样式
itemStyle: {
color: null, // 使用 visualMap 控制颜色
borderWidth: 1,
borderColor: '#fff',
opacity: 0.85
},
// 标签显示
label: {
show: true,
formatter: '{c}',
fontSize: 10,
position: 'top'
},
// 柱状尺寸
barSize: 0.6, // 柱子相对尺寸(0-1)
// 高亮效果
emphasis: {
label: { show: true, fontSize: 12, fontWeight: 'bold' },
itemStyle: { opacity: 1, shadowBlur: 10 }
},
// 动画效果
animation: true,
animationDuration: 1000,
animationEasing: 'elasticOut'
}],
// 网格样式
grid3D: {
viewControl: {
projection: 'perspective', // 透视投影
autoRotate: false, // 自动旋转(可开启)
autoRotateSpeed: 5,
distance: 200, // 相机距离
alpha: 25, // 上下旋转角度
beta: 45 // 左右旋转角度
},
boxWidth: 80,
boxHeight: 60,
boxDepth: 80,
// 坐标轴平面样式
axisLine: { lineStyle: { color: '#ccc', width: 1 } },
axisTick: { show: false },
splitLine: { lineStyle: { color: '#e0e0e0', width: 1 } },
// 背景平面
light: {
main: { intensity: 1.2, shadow: true },
ambient: { intensity: 0.6 }
}
}
};
myChart.setOption(option);
拓展:三维散点图
javascript
复制代码
// 三维散点图:展示电池容量、续航里程、售价的关系
const scatterData = [
[65, 420, 18.5], // [电池容量(kWh), 续航(km), 售价(万元)]
[75, 510, 22.8],
[82, 580, 26.5],
[92, 650, 31.2],
[100, 720, 35.8],
[58, 380, 15.6],
[70, 480, 20.3],
[88, 620, 29.9]
];
const scatterOption = {
title: { text: '电池容量、续航里程与售价关系三维散点图', left: 'center' },
xAxis3D: { name: '电池容量(kWh)', min: 50, max: 110 },
yAxis3D: { name: '续航里程(km)', min: 350, max: 750 },
zAxis3D: { name: '售价(万元)', min: 10, max: 40 },
series: [{
type: 'scatter3D',
data: scatterData,
symbolSize: 8,
itemStyle: { color: '#4dabf7', opacity: 0.8 },
label: { show: true, formatter: '{c}', position: 'top' }
}],
grid3D: { viewControl: { distance: 180, alpha: 20, beta: 40 } }
};
任务四:实现异步加载
4.1 异步加载数据
知识点
- 异步加载:图表数据通过 AJAX/Fetch 从服务器动态获取。
- Loading 动画:数据加载过程中显示加载提示。
- 动态更新 :使用
setOption 更新数据(注意 notMerge 参数)。
语法
javascript
复制代码
// 显示加载动画
myChart.showLoading();
// 异步获取数据
fetch(url)
.then(response => response.json())
.then(data => {
myChart.hideLoading();
myChart.setOption({ series: [{ data: data }] });
});
4.2 动画设置
知识点
- 初始动画:图表首次渲染时的入场动画。
- 更新动画:数据更新时的过渡动画。
- 动画配置 :
animation、animationDuration、animationEasing。
案例代码:异步加载A品牌电动汽车在某地区的日销量数据
javascript
复制代码
// 完整案例:异步加载 + 动画效果 + 动态更新
const chartDom = document.getElementById('asyncChart');
const myChart = echarts.init(chartDom);
// ========== 1. 初始配置(空数据占位) ==========
let currentOption = {
title: {
text: 'A品牌电动汽车日销量趋势',
subtext: '数据加载中...',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' }
},
xAxis: {
type: 'category',
name: '日期',
data: [] // 初始为空
},
yAxis: {
type: 'value',
name: '销量(辆)'
},
series: [{
name: '日销量',
type: 'line',
data: [], // 初始为空
smooth: true, // 平滑曲线
lineStyle: { width: 3, color: '#4dabf7' },
areaStyle: { opacity: 0.3, color: '#4dabf7' },
symbol: 'circle',
symbolSize: 8,
itemStyle: { color: '#ff6b6b' },
// 动画配置
animation: true,
animationDuration: 1500, // 动画时长(毫秒)
animationEasing: 'cubicOut', // 缓动效果:linear, quadraticOut, elasticOut, bounceOut
animationDelay: 0,
animationThreshold: 2000 // 数据量超过此值时关闭动画
}],
// 全局动画
animation: true,
animationDuration: 1000,
animationEasing: 'backOut'
};
// 设置初始空配置
myChart.setOption(currentOption);
// 显示加载动画
myChart.showLoading({
text: '正在加载数据...',
color: '#4dabf7',
textColor: '#333',
maskColor: 'rgba(255, 255, 255, 0.8)',
zlevel: 0,
fontSize: 14,
spinnerRadius: 20,
lineWidth: 3
});
// ========== 2. 模拟异步加载数据 ==========
// 模拟 API 请求(实际开发中使用 fetch/axios)
function fetchSalesData() {
return new Promise((resolve) => {
// 模拟网络延迟(500ms)
setTimeout(() => {
// 生成最近30天的模拟销量数据
const dates = [];
const sales = [];
const today = new Date();
for (let i = 29; i >= 0; i--) {
// 生成日期
const date = new Date(today);
date.setDate(today.getDate() - i);
const dateStr = `${date.getMonth() + 1}/${date.getDate()}`;
dates.push(dateStr);
// 生成销量数据(包含周末高峰和随机波动)
const dayOfWeek = date.getDay();
let baseSales = 60;
if (dayOfWeek === 0 || dayOfWeek === 6) {
baseSales = 95; // 周末销量更高
}
// 添加随机波动
const randomFactor = 0.7 + Math.random() * 0.6;
const sale = Math.floor(baseSales * randomFactor);
sales.push(sale);
}
resolve({ dates, sales });
}, 800);
});
}
// ========== 3. 加载数据并更新图表 ==========
async function loadData() {
try {
// 异步获取数据
const { dates, sales } = await fetchSalesData();
// 隐藏加载动画
myChart.hideLoading();
// 更新标题
myChart.setOption({
title: { subtext: `数据更新于 ${new Date().toLocaleTimeString()}` }
});
// 方式一:完全替换数据(带动画过渡)
myChart.setOption({
xAxis: { data: dates },
series: [{ data: sales }]
});
// 方式二:使用 notMerge 完全替换(不合并旧配置)
// myChart.setOption(newOption, { notMerge: true });
// 方式三:使用 lazyUpdate 延迟更新
// myChart.setOption(newOption, { lazyUpdate: true });
} catch (error) {
console.error('数据加载失败:', error);
myChart.hideLoading();
myChart.setOption({
title: { subtext: '数据加载失败,请刷新重试' }
});
}
}
// 执行数据加载
loadData();
// ========== 4. 定时刷新(实时监控场景) ==========
// 每隔30秒自动刷新数据
let refreshInterval = null;
function startAutoRefresh(intervalMs = 30000) {
if (refreshInterval) clearInterval(refreshInterval);
refreshInterval = setInterval(() => {
// 显示加载动画(可选)
myChart.showLoading({ text: '数据更新中...' });
loadData();
}, intervalMs);
}
function stopAutoRefresh() {
if (refreshInterval) {
clearInterval(refreshInterval);
refreshInterval = null;
}
}
// 可选:启动自动刷新(注释掉以禁用)
// startAutoRefresh(30000);
// ========== 5. 手动刷新按钮(HTML 中需要对应按钮) ==========
// 假设有一个刷新按钮:<button id="refreshBtn">刷新数据</button>
// document.getElementById('refreshBtn').onclick = () => {
// myChart.showLoading({ text: '手动刷新中...' });
// loadData();
// };
// ========== 6. 数据更新时的动画效果演示 ==========
// 模拟动态添加数据点(如实时监控)
let dataCounter = 0;
function addDataPoint() {
const currentOption = myChart.getOption();
const currentDates = currentOption.xAxis[0].data || [];
const currentSales = currentOption.series[0].data || [];
// 添加新数据点
const newDate = `Day ${currentDates.length + 1}`;
const newSale = Math.floor(Math.random() * 80) + 30;
currentDates.push(newDate);
currentSales.push(newSale);
// 保持最近30个数据点
if (currentDates.length > 30) {
currentDates.shift();
currentSales.shift();
}
// 更新图表(自动带动画过渡)
myChart.setOption({
xAxis: { data: [...currentDates] },
series: [{ data: [...currentSales] }]
});
}
// 取消注释以测试动态添加数据(每5秒添加一点)
// setInterval(addDataPoint, 5000);
项目实训:综合案例
javascript
复制代码
// 综合案例:异步加载数据 + 三维图表 + 富文本标签 + 自定义主题
async function buildAdvancedDashboard() {
// 1. 注册自定义主题
const dashboardTheme = {
color: ['#0f0c29', '#302b63', '#24243e', '#4a4e9a', '#7b6cb5'],
backgroundColor: '#0f0c29',
textStyle: { color: '#fff', fontFamily: 'Microsoft YaHei' }
};
echarts.registerTheme('dashboardTheme', dashboardTheme);
// 2. 初始化图表
const chart = echarts.init(document.getElementById('dashboard'), 'dashboardTheme');
chart.showLoading({ text: '加载仪表板数据...', color: '#7b6cb5' });
// 3. 异步加载多组数据
const [sales3D, keywords] = await Promise.all([
fetch('/api/sales3d').then(r => r.json()),
fetch('/api/keywords').then(r => r.json())
]);
chart.hideLoading();
// 4. 设置三维图表配置
chart.setOption({
title: { text: '销量3D分析', left: 'center' },
xAxis3D: { name: '品牌', data: ['A', 'B', 'C'] },
yAxis3D: { name: '季度', data: ['Q1', 'Q2', 'Q3', 'Q4'] },
zAxis3D: { name: '销量' },
series: [{
type: 'bar3D',
data: sales3D,
label: { show: true, formatter: '{c}' }
}],
grid3D: { viewControl: { autoRotate: true, autoRotateSpeed: 3 } }
});
}
项目评价知识点总结
| 知识点 |
掌握要求 |
考核方式 |
| 主题注册与应用 |
能够创建和使用自定义主题 |
代码实现 |
| 富文本标签 |
能够配置多样式混合标签 |
饼图/玫瑰图应用 |
| 三维图表 |
能够使用 GL 扩展绘制 3D 图表 |
三维柱状图/散点图 |
| 异步加载 |
能够实现数据动态加载和更新 |
API 数据获取 + 动画 |