在数据可视化场景中,双Y轴图表常用于展示具有不同量纲的数据。但默认配置下,左右Y轴的0刻度线、刻度线可能无法对齐,影响图表可读性。本文将详细介绍该功能的实现方法
1. 实现双Y轴
- 一个Y轴时的 yAxis 是对象
yAxis: { type: 'value', name:'Y轴名称', },- 两个Y轴时的 yAxis 是数组,且要在series中指定yAxisIndex
yAxis : [{ type: 'value', name:'左侧Y轴名称', }, { type: 'value', name:'右侧Y轴名称', }], series: [{ name: '速度', type: 'line', smooth: true, data: [] }, { name: '钻进深度', type: 'line', smooth: true, yAxisIndex: 1, //存在多个Y轴时使用,重要!!! data: [] }]2. 双Y轴0刻度线对齐
直接设置 yAxis 为数组,Y轴刻度线是不对齐的,因为它俩的数值范围不一样,且分割段数不一样,导致左右的刻度线不一致,不能重合在一起。
那么我们就设置相同的分割段数:
yAxis : [{ type: 'value', name:'左侧Y轴名称', max: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.ceil(absMax * 1.2); }, min: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.floor(-absMax * 1.2); }, splitNumber: 8, //y轴的分割段数 axisLabel: { formatter: function(value:any) { return value.toFixed(2); } }, }, { type: 'value', name:'右侧Y轴名称', max: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.ceil(absMax * 1.2); }, min: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.floor(-absMax * 1.2); }, splitNumber: 8, //y轴的分割段数 axisLabel: { formatter: function(value:any) { return value.toFixed(2); } }, }],有最大值最小值,也有相同的分割段数,那么0刻度线就一致了。
但是此时,因为数据的原因,左右的刻度线有时会对不齐,如图
3. 双Y轴刻度线对齐
通过设置alignTicks: true属性,自动计算左右Y轴的刻度间隔,确保对齐效果。该属性仅对value和log类型的坐标轴有效。
注:alignTicks属性需要ECharts v5.3.0+版本支持
yAxis : [{ type: 'value', name:'左侧Y轴名称', alignTicks: true, // 左右刻度线对齐 }, { type: 'value', name:'右侧Y轴名称', alignTicks: true, // 左右刻度线对齐 }],这样左右的刻度线就都对齐了。
最终效果:
全部option:
let option = { grid: { top: '50px', left: '80px', right: '90px', }, legend: { bottom: 10, textStyle: { color: 'rgba(255,255,255,0.7)' }, data: ['速度', '钻进深度'] }, xAxis: { name: '时间', nameTextStyle: { padding: [0, 0, 0, 25] }, axisTick: { alignWithLabel: true, }, axisLine: { lineStyle: { color: 'rgba(255,255,255,0.7)', }, }, axisLabel: { formatter: function (value:any) { return value.replace(/\s/g, '\r\n'); } }, data: ['2025-12-17 09:57:21', '2025-12-17 10:57:21', '2025-12-17 11:57:21', '2025-12-17 12:57:21', '2025-12-17 13:57:21', '2025-12-17 14:57:21', '2025-12-17 15:57:21', '2025-12-17 16:57:21', '2025-12-17 17:57:21', '2025-12-17 18:57:21'] }, yAxis: [ { type: 'value', name: 左侧y轴, alignTicks: true, // 左右刻度线对齐 max: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.ceil(absMax * 1.2); }, min: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.floor(-absMax * 1.2); }, splitNumber: 8, //设置坐标轴的分割段数 axisLabel: { formatter: function(v:any) { return v.toFixed(2); } }, axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.7)', } }, splitLine: { lineStyle: { type: 'dashed', color: 'rgba(255,255,255,0.3)', } } }, { type: 'value', name: 右侧y轴, position: 'right', alignTicks: true, // 左右刻度线对齐 max: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.ceil(absMax * 1.2); }, min: (value:any) => { const {max, min} = value; const absMax = Math.max(Math.abs(max), Math.abs(min)); return Math.floor(-absMax * 1.2); }, splitNumber: 8, //设置坐标轴的分割段数 axisLabel: { formatter: function(v:any) { return v.toFixed(2); } }, axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.7)', }, }, splitLine: { lineStyle: { type: 'dashed', color: 'rgba(255,255,255,0.3)', } } } ], series: [{ name: '速度', type: 'line', smooth: true, data: [-1, 1, -1.1, 1.2, -0.92, 1, -1, 0.88, -0.87, 0.89] }, { name: '钻进深度', type: 'line', smooth: true, yAxisIndex: 1, //存在多个Y轴时使用 data: [-1.14, 8.15, -9.95, 1.14, -1.14, 1.14, -1.14, 8.15, -8.15, 8.15] }], emphasis: { focus: 'series' //鼠标悬浮到某条线时,其他线淡化 }, }