ECharts 高级图表
在四大件之上过一遍进阶系列:玫瑰图、平滑面积线、渐变柱、
涟漪散点、热力图、K 线,以及 dataset、dataZoom、富文本标签三大利器。
1. 进阶系列速览
1.1 pie:roseType 南丁格尔玫瑰图
{
type: 'pie',
radius: ['15%', '70%'], // 内外半径
roseType: 'area', // 半径映射数值,形成花瓣
itemStyle: { borderRadius: 6 },
label: { show: true, formatter: '{b}: {d}%' },
data: [
{ value: 420, name: '华东' },
{ value: 350, name: '华南' },
{ value: 280, name: '华北' },
{ value: 190, name: '西南' }
]
}{d} 是百分比占位符;{c} 数值、{b} 名称,
formatter 三剑客记住即可。
1.2 line:areaStyle / smooth / markLine / markPoint
{
type: 'line',
smooth: true, // 平滑曲线
areaStyle: { // 渐变面积
opacity: 0.25
},
markLine: {
data: [
{ type: 'average', name: '均值' }, // 自动算均线
{ yAxis: 500, name: '目标线',
lineStyle: { color: '#e74c3c', type: 'dashed' } }
]
},
markPoint: {
data: [
{ type: 'max', name: '峰值' }, // 最大值标注
{ type: 'min', name: '谷值' }
]
},
data: [320, 450, 280, 520, 410, 600]
}markLine/markPoint 的 type: average/max/min 是免费的分析能力,
不用自己算。
1.3 bar:graphic 线性渐变
{
type: 'bar',
barWidth: '45%',
itemStyle: {
borderRadius: [6, 6, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#36a3f7' }, // 顶部亮色
{ offset: 1, color: '#1e88c7' } // 底部深色
])
},
data: [320, 450, 280, 520, 410, 600]
}LinearGradient 参数是 (x0,y0,x1,y1) 归一化坐标——
(0,0,0,1) 表示垂直向下渐变,横向柱改 (0,0,1,0)。
1.4 scatter 与 effectScatter:涟漪地标点
series: [
{ // 普通散点:底层数据
type: 'scatter',
symbolSize: d => Math.sqrt(d[2]) * 2,
data: cities
},
{ // 涟漪特效:重点城市
type: 'effectScatter',
rippleEffect: { scale: 3, brushType: 'stroke' },
symbolSize: 10,
data: keyCities
}
]effectScatter 常用于地图上强调重点城市,与 geo/map 组件配合使用。
1.5 heatmap:需要 visualMap
{
type: 'heatmap',
data: [
// [x索引, y索引, 值]
[0, 0, 5], [0, 1, 9], [1, 0, 3], [1, 1, 12]
]
},
// visualMap 把数值映射成颜色(热力图必需)
visualMap: {
min: 0,
max: 20,
calculable: true, // 手柄可拖动过滤
orient: 'horizontal',
inRange: { color: ['#50a3ba', '#eac736', '#d94e5d'] }
}没有 visualMap 时热力图没有颜色语义,这是新手常见遗漏。
1.6 boxplot 与 kline
// 箱线图:[min, Q1, median, Q3, max]
{ type: 'boxplot', data: [[20, 45, 68, 80, 95], [30, 50, 62, 75, 90]] }
// K 线:[开盘, 收盘, 最低, 最高]
{ type: 'candlestick', data: [
[2320, 2400, 2290, 2450],
[2400, 2380, 2350, 2430],
[2380, 2510, 2360, 2550]
] }K 线是金融场景核心,完整实战见本章末尾。
2. dataset:维度式数据源
把”数据”与”系列”解耦,一份 source 喂多个 series:
const option = {
dataset: {
dimensions: ['月份', '销量', '利润'],
source: [
['一月', 320, 42],
['二月', 450, 58],
['三月', 280, 36]
]
// 或者 source 直接是二维数组,首行为维度名
},
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [
{ type: 'bar', encode: { x: '月份', y: '销量' } },
{ type: 'line', encode: { x: '月份', y: '利润' } }
]
};优势:
- 换数据源只改一处,series 配置不动。
encode用维度名绑定轴,可读性远好于列下标。- 接口返回的表格数据几乎可以原样塞进 source。
3. 多系列联动 grid 多图
一个 option 里放多个 grid/xAxis/yAxis,实现上下两块绘图区:
grid: [
{ left: 60, right: 20, top: 40, height: '55%' }, // 主图区
{ left: 60, right: 20, top: '72%', height: '18%' } // 副图区
],
xAxis: [
{ type: 'category', gridIndex: 0, data: months },
{ type: 'category', gridIndex: 1, data: months }
],
yAxis: [
{ type: 'value', gridIndex: 0 },
{ type: 'value', gridIndex: 1, axisLabel: { show: false } }
],
series: [
{ type: 'line', xAxisIndex: 0, yAxisIndex: 0, data: prices },
{ type: 'bar', xAxisIndex: 1, yAxisIndex: 1, data: volumes,
itemStyle: {
// 成交量按涨跌着色
color: p => p.value >= p.dataIndex ? '#e74c3c' : '#2ecc71'
} }
]这套”主图 + 副图”结构就是 K 线 + 成交量联动的骨架。
副图的缩放同步靠下一节的 dataZoom。
4. dataZoom 缩放:inside + slider
dataZoom: [
{ // 内置型:滚轮/手势直接缩放
type: 'inside',
start: 60, // 初始窗口起点(百分比)
end: 100
},
{ // 滑条型:底部拖动条
type: 'slider',
height: 24,
bottom: 12
}
]要点:
- 多个 dataZoom 同时生效,一个 option 里通常两个都配。
- 多图联动缩放:给主副图的 dataZoom 设相同
xAxisIndex,
或用id+dataZoomId关联,滑动一个另一个自动跟随。 - 大数据量时配合
sampling: 'lttb'(见下一章交互篇)。
5. 富文本标签 formatter
formatter 支持字符串模板和回调函数两级:
// 字符串模板
label: { formatter: '{b}\n{c} 万元 ({d}%)' }
// 回调函数(类型标注齐全)
tooltip: {
formatter(params) {
if (Array.isArray(params)) { // trigger:'axis' 时是数组
return params.map(p =>
`${p.marker}${p.seriesName}:${p.value}`
).join('<br/>');
}
return `${params.name}<br/>数值:${params.value}`;
}
}富文本还能在标签里混排多种样式:
yAxis: {
axisLabel: {
formatter: v => `{big|${v}}{unit|万}`,
rich: {
big: { fontSize: 14, fontWeight: 'bold', color: '#333' },
unit: { fontSize: 10, color: '#999',
padding: [0, 0, 0, 2] }
}
}
}rich 定义命名样式片段,formatter 里用 {name|文本} 引用,
可以做出”大数字 + 小单位”的精致效果。
6. 实战:K 线图 + 成交量副图联动
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<style>
body { font-family: sans-serif; margin: 0; padding: 24px; background: #10141a; }
#kline { width: 100%; height: 560px; background: #10141a; }
</style>
</head>
<body>
<div id="kline"></div>
<script>
// 模拟 30 天行情数据:[日期, 开, 收, 低, 高, 成交量]
const raw = Array.from({ length: 30 }, (_, i) => {
const base = 100 + i * 0.8;
const open = base + Math.sin(i) * 4;
const close = base + Math.sin(i + 1) * 5;
const low = Math.min(open, close) - Math.random() * 3;
const high = Math.max(open, close) + Math.random() * 3;
const volume = Math.round(800 + Math.random() * 600);
return [`D${i + 1}`,
+open.toFixed(2), +close.toFixed(2),
+low.toFixed(2), +high.toFixed(2), volume];
});
const dates = raw.map(r => r[0]);
const kdata = raw.map(r => r.slice(1, 5));
const vols = raw.map((r, i) => ({
value: r[5],
itemStyle: {
color: r[2] >= r[1] ? '#ef4444' : '#22c55e'
}
}));
const chart = echarts.init(document.getElementById('kline'), 'dark');
chart.setOption({
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
axisPointer: { type: 'cross' }
},
grid: [
{ left: 70, right: 20, top: 30, height: '58%' },
{ left: 70, right: 20, top: '74%', height: '16%' }
],
xAxis: [
{ type: 'category', gridIndex: 0, data: dates, boundaryGap: true },
{ type: 'category', gridIndex: 1, data: dates }
],
yAxis: [
{ scale: true, gridIndex: 0 }, // scale 不强制含零
{ gridIndex: 1, axisLabel: { show: false },
splitLine: { show: false } }
],
// 关键:一个 inside 缩放同时控制两个坐标系的 x 轴
dataZoom: [
{ type: 'inside',
xAxisIndex: [0, 1], // 联动双图
start: 40, end: 100 },
{ type: 'slider',
xAxisIndex: [0, 1],
bottom: 8, height: 20 }
],
series: [
{
name: '日 K',
type: 'candlestick',
xAxisIndex: 0, yAxisIndex: 0,
data: kdata,
itemStyle: {
color: '#ef4444', // 阳线
color0: '#22c55e', // 阴线
borderColor: '#ef4444',
borderColor0: '#22c55e'
},
markLine: {
symbol: 'none',
data: [{ type: 'average', name: '均价' }]
}
},
{
name: '成交量',
type: 'bar',
xAxisIndex: 1, yAxisIndex: 1,
data: vols
}
]
});
window.addEventListener('resize', () => chart.resize());
</script>
</body>
</html>实现要点回顾:
- 双 grid 结构:主图 58% 高度放 K 线,副图放成交量。
- dataZoom 的 xAxisIndex 写数组 [0,1]:一次缩放同时驱动
两张图的窗口——这就是”联动”的全部秘密。 - 成交量按阴阳着色:收盘大于开盘红、否则绿,
通过 itemStyle 回调逐柱设置。 - yAxis.scale: true:K 线不强制从零开始,放大波动细节。
小结
- roseType/markLine/markPoint/graphic 渐变都是 series 级一行配置。
- visualMap 是热力图的”颜色图例”,缺了它热力没有语义。
- dataset + encode 把数据与系列解耦,接口表格数据可直塞 source。
- 多 grid 多轴时,series 用 gridIndex/xAxisIndex 挂载到指定绘图区。
- dataZoom 的 xAxisIndex 写数组即可实现主副图缩放联动。
下一篇处理交互事件、resize 与大数据量优化:
交互与响应式