一文吃透 ECharts 多坐标系组合:从双轴混排到多网格联动的进阶实战
一文吃透 ECharts 多坐标系组合:从双轴混排到多网格联动的进阶实战
【免费下载链接】echartsApache ECharts is a powerful, interactive charting and data visualization library for browser项目地址: https://gitcode.com/GitHub_Trending/echa/echarts
把折线、柱状、极坐标、雷达一次性装进同一块画布,还要它们彼此联动、随用户操作自由切换——这正是 ECharts 多坐标系组合最迷人的地方。本文将用一个贯穿始终的电商业务案例,带你从"一个图放多个系列"出发,一路进阶到"多坐标系混排、多网格联动、运行时动态切换",让复杂数据真正实现"一屏讲清"。
一、老板的"一屏看尽",逼我学会了图表拼盘
运营负责人甩来一句话:"下周上线经营看板,我要在一屏里看到——十二个月的销售额走势、各品类占比、各省份分布、还有每次大促的转化效果。别让我翻页。"
我最初的方案很天真:并排挂四个独立的 ECharts 实例,各画各的。结果很快就发现问题——四个图表各自为政,tooltip 各弹各的、坐标轴互不对齐、布局还互相挤压,拼出来活像一块"马赛克瓷砖墙"。折腾了整整两天,我才真正意识到:一个 ECharts 实例本身就是一块完整的画布,画布上可以同时存在多个坐标系、多个系列,它们彼此独立、又共享同一套交互机制。
这个认知,就是本文想带你走完的路线图。📌
二、先建立心智模型:场地与演员
动手之前,先忘掉参数,记住一组类比:
- 画布:一个
echarts.init()出来的实例,决定"在哪画"; - 坐标系:画布上划分出的"场地",包括直角坐标
grid、极坐标polar、地图geo、雷达radar、日历calendar、平行坐标parallel等; - 系列:在场地里表演的"演员",也就是柱状、折线、散点、饼图这些
series; - 挂钩方式:系列通过
coordinateSystem、xAxisIndex、yAxisIndex、gridIndex等字段,声明"我属于哪个场地"。
顺着这个思路,两个核心概念就清晰了:
多坐标系组合,解决的是"一张画布装下多种数据结构";多图表联动,解决的是"装下的这些东西还能互相讲故事"。
什么场景需要它们?当数据同时涉及趋势、占比、分布多个维度,当量纲不同但彼此相关的指标需要同屏对比,当用户希望自由切换视角做数据探索——恭喜你,你需要的不是更多图表,而是把已有的图表组合得更聪明。🧩
三、第一块敲门砖:约 20 行代码,让柱状和折线先同框
先建立一个最小可跑通的例子,让你立刻获得正反馈。这段代码解决的是"不新增坐标系的前提下,用多个系列表达两层信息"。
const chart = echarts.init(document.getElementById('board')); chart.setOption({ tooltip: { trigger: 'axis' }, legend: { data: ['销售额', '订单量'] }, xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月', '6月'] }, yAxis: { type: 'value', name: '金额' }, series: [ { name: '销售额', type: 'bar', data: [320, 410, 380, 460, 520, 610] }, { name: '订单量', type: 'line', data: [12, 15, 13, 17, 19, 23] } ] });要点:
series本身就是一个数组,在同一坐标系里堆叠多个系列,是后面所有组合玩法的最小单元,图例、tooltip 也会自动为每个系列分配身份。
如果你想要两根 y 轴各管一摊(比如销售额用万元、订单量用万单),只需要把yAxis改成数组、再给系列加一个yAxisIndex: 0或1,思路完全一样。
四、四个台阶,把多坐标系组合真正用起来
有了最小案例打底,接下来我们一节一节往上爬。
台阶一:极坐标与直角坐标同屏混排(核心:coordinateSystem)
看板需求越来越具体:运营既要看"一周七天的销售节奏",又要看"近 30 天的整体走势"。前者是周期性数据,用极坐标的环状柱状图最直观;后者是时间序列,直角坐标系最擅长。为什么不能一屏同时呈现?
chart.setOption({ // 左侧安放极坐标:环形展示一周销量,分类放到角度轴上 polar: { center: ['22%', '50%'], radius: '36%' }, angleAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] }, radiusAxis: { type: 'value', max: 120 }, // 右侧留出直角坐标系:展示近 30 天销售额趋势 grid: { left: '52%', right: '6%', top: '14%', bottom: '16%' }, xAxis: { type: 'category', data: last30Days }, yAxis: { type: 'value', name: '万元' }, series: [ { name: '本周销量', type: 'bar', coordinateSystem: 'polar', // 关键:告诉这个系列去极坐标场地表演 data: [62, 78, 55, 90, 110, 96, 84] }, { name: '近30天销售额', type: 'line', data: salesTrend // 不写 coordinateSystem,默认挂到直角坐标 } ] });要点:
coordinateSystem: 'polar'是系列与极坐标场地之间的"签约合同";而polar.center/radius与grid.left/right共同负责"划地盘",让两块场地互不侵犯。
想验证这个配置的更多边界情况?项目自带的test/bar-polar-multi-series.html就是一个真实的多系列极坐标柱状图用例,直接打开对照学习。
台阶二:多网格布局,搭出"上趋势、下转化"的看板(核心:gridIndex)
需求继续升级:GMV 与转化率量纲不同、波动幅度也天差地别,硬塞进同一坐标系,转化率那条线会被压成一条直线。这时候就该动用多网格布局,把画布上下分成两个独立的场地。
chart.setOption({ grid: [ { left: '8%', right: '6%', top: '12%', height: '34%' }, // 上:GMV 柱状 { left: '8%', right: '6%', top: '58%', height: '34%' } // 下:转化率折线 ], xAxis: [ { type: 'category', data: months, gridIndex: 0 }, { type: 'category', data: months, gridIndex: 1 } ], yAxis: [ { type: 'value', name: 'GMV(万元)', gridIndex: 0 }, { type: 'value', name: '转化率(%)', gridIndex: 1 } ], series: [ { name: 'GMV', type: 'bar', xAxisIndex: 0, yAxisIndex: 0, data: gmv }, { name: '转化率', type: 'line', xAxisIndex: 1, yAxisIndex: 1, data: conv } ] });要点:
gridIndex、xAxisIndex、yAxisIndex三者共同决定"演员进哪个场地、站哪根轴",这套索引体系是整个多坐标系组合的地基,请务必吃透。
对照用例:项目里的test/multipleGrid.html展示了更复杂的时间轴多网格布局,值得翻一翻。
台阶三:让网格之间"互相讲故事"(核心:dispatchAction)
布局只是第一步。运营真正想要的交互是:点一下"5月",上面 GMV 的柱子高亮,下面转化率的点也同时高亮——让读者一眼看出两个指标的联动关系。
chart.on('click', function (params) { const idx = params.dataIndex; // 同一画布内,用 dispatchAction 给实例"发指令",同时驱动两个系列的高亮 chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: idx }); chart.dispatchAction({ type: 'highlight', seriesIndex: 1, dataIndex: idx }); });要点:
dispatchAction是 ECharts 事件系统的核心——图表不只是"画出来给你看",它还是一台能接收指令、反过来驱动自身的机器。
台阶四:运行时动态切换坐标系(核心:setOption 的 notMerge)
最后一步:同一个"各品牌销售额"数据集,业务侧有人想看柱状对比,有人想看环形占比。与其做两套页面,不如加一个切换按钮,让坐标系在运行时自由切换。
let usePolar = false; toggleBtn.addEventListener('click', function () { usePolar = !usePolar; // 第二个参数传 true 表示整体重建,避免旧坐标系残留 chart.setOption(usePolar ? polarViewOption() : cartesianViewOption(), true); }); function cartesianViewOption() { return { xAxis: { type: 'category', data: brands }, yAxis: { type: 'value' }, series: [{ type: 'bar', data: share, name: '销售额' }] }; } function polarViewOption() { return { angleAxis: { type: 'category', data: brands }, radiusAxis: { type: 'value' }, polar: {}, series: [{ type: 'bar', data: share, coordinateSystem: 'polar', name: '销售额' }] }; }要点:
setOption默认是增量合并(第二个参数false),适合局部更新;但坐标系结构完全不同时,请传true整体重建,这是切换场景中最容易踩的坑。
五、让图表真正"活"起来:交互与提示的进阶玩法
tooltip 增强:让悬浮提示学会"读数据"
多系列同框时,默认的trigger: 'item'只显示你鼠标指到的那一个系列,信息量太小。试试这个:
tooltip: { trigger: 'axis', // 把同一根时间线上所有系列都列出来 axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }, valueFormatter: (value) => (value == null ? '-' : value.toFixed(1) + ' 万') }axisPointer的十字准星帮用户对齐坐标,valueFormatter统一格式化数值,运营再也不用对着小数点发呆了。
多实例联动:一行代码"接线"两个独立图表
有时候两块图在页面上相距很远,必须各自init成独立实例(比如一个是组件,一个是弹窗)。交互怎么同步?ECharts 早就替你想好了:
const chartA = echarts.init(document.getElementById('chartA')); const chartB = echarts.init(document.getElementById('chartB')); // 把两个实例"接线":此后 tooltip、高亮、图例开关都会互相广播 echarts.connect([chartA, chartB]);要点:
echarts.connect是实例级的联动开关,适用于"物理上分离、逻辑上同源"的图表。项目test/connect.html里有现成的多实例联动演示。
给看板加点"操作感"
- 数据缩放:给网格加
dataZoom: [{ type: 'inside' }],鼠标滚轮就能在时间轴上缩放平移; - 图例开关:图例点击默认就能隐藏/显示对应系列,这是免费的"下钻"入口;
- 焦点聚焦:给系列加
emphasis: { focus: 'series' },悬停时其他系列自动变淡,主次分明。
六、排雷清单:这些坑我都替你踩过了
坑一:坐标轴被系列盖住
极坐标里柱状图容易把分类标签"吃掉"。解法是提升轴的层级:
radiusAxis: { z: 10 } // 让分类轴浮在柱状之上再配合polar.center和grid.left/right做好区域隔离,两层场地就不会打架。
坑二:多次 setOption 后,旧坐标系"阴魂不散"
增量合并的代价是:上次的极坐标没删掉,这次又加了直角坐标,两套轴叠在一起。切换结构时记得传true整体重建,或者干脆chart.clear()后再 set。
坑三:底层系列抢事件、tooltip 弹得乱七八糟
当某个系列只是"背景参考线",不需要交互时,直接把它静音:
series: [ { type: 'line', data: baseline, silent: true }, // 背景参考线:不响应任何事件 { type: 'line', data: real, z: 2 } // 前景系列:正常响应 ]坑四:数据一多就卡成 PPT
多坐标系叠加本就增加渲染压力,大数据量再加一层。两个救兵:
series: [{ type: 'line', data: streamData, sampling: 'average', // 先降采样,保留走势特征 large: true // 开启大数据量模式 }], animationDurationUpdate: 200 // 缩短更新动画,避免拖拽时卡顿如果还是慢,建议打开浏览器开发者工具,用 Performance 面板录制一段操作,逐帧检查是布局、绘制还是事件回调拖慢了主线程——就像排查任何一个前端性能问题一样,先定位再优化。
七、总结与延伸
回头看,这条进阶路线其实只围绕三个动作:划分场地(坐标系)、分配演员(系列与索引挂钩)、编排剧情(联动与切换)。掌握这套思维后,再多的图表类型也只是换了个场地而已。
接下来你可以按这个方向继续深入:
- 解锁更多坐标系:
radar雷达、calendar日历、geo地图、parallel平行坐标——思路完全一致,先建坐标系、再用索引把系列挂上去; - 让切换更丝滑:给系列加
universalTransition: true,坐标系切换时图形会自动补间过渡,告别生硬跳变; - 统一数据源:用
dataset管理数据,多系列共享一份数据,后续增删维度只需改一处; - 读源码:项目的
src/coord目录就是各坐标系的实现,src/chart是各系列,想深入原理的可以从这里入手。
文章里提到的所有测试用例都放在项目的test/目录下,按文件名直接搜索即可对照学习。把看板案例亲手跑一遍,你会发现——复杂数据从来不需要更复杂的图表,只需要更聪明的组合方式。🚀
【免费下载链接】echartsApache ECharts is a powerful, interactive charting and data visualization library for browser项目地址: https://gitcode.com/GitHub_Trending/echa/echarts
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
