EchartJS 双Y轴 0刻度对齐处理

9/23/2022 Echart

# 奇怪需求

Echart双Y轴,如果数据中包含负数,就会出现0刻度不对其的情况。

0刻度不对其

现客户希望能做到0刻度线对齐。因为Excel能做到。😀
按理来说,这应该算一个常规需求,可Echart并没有相关API参数。

# 镜像 正区间部分,实现0刻度线对齐

镜像坐标轴中的正区间

通过镜像处理的方式,也就是把双轴中的最大值,分别设置到Min Max中。
就可以完成0刻度线对齐。

		// 数据
			var LeftNum = [503, 1689, 118, 165, 686, 662, 645, 320, 15, -113, 40, 143, 740, 182, -29];
			var LeftData = {
				max: Math.max(...LeftNum),
				min: Math.min(...LeftNum)
			}
			var RightNum = [2, 0, 6, 2, 2, 3, 11, 6, 7, 4, 1, 2, 1, 6, 7];
			var RightData = {
				max: Math.max(...RightNum),
				min: Math.min(...RightNum)
			}
			console.log(LeftData)
			console.log(RightData)
			// 选中项
			var selected = {
				注册: true,
				活跃: true
			}


			var dom = document.getElementById("container");
			var myChart = echarts.init(dom);
			var app = {};
			option = null;

			option = {
				//1、 格式化提示信息
				tooltip: {
					trigger: 'axis',
				},
				toolbox: {
					feature: {
						dataView: {
							show: true,
							readOnly: false
						},
						magicType: {
							show: true,
							type: ['line', 'bar']
						},
						restore: {
							show: true
						},
						saveAsImage: {
							show: true
						}
					}
				},
				legend: {
					data: ['注册', '活跃'],
					selected,
				},
				grid: {
					width: '50%',
					height: '50%'
				},
				xAxis: [{
					type: 'category',
					data: [
						"2022-08-31",
						"2022-09-01",
						"2022-09-02",
						"2022-09-03",
						"2022-09-04",
						"2022-09-05",
						"2022-09-06",
						"2022-09-07",
						"2022-09-08",
						"2022-09-09",
						"2022-09-10",
						"2022-09-11",
						"2022-09-12",
						"2022-09-13",
						"2022-09-14"
					],
					axisPointer: {
						type: 'shadow'
					}
				}],
				yAxis: [{
						type: 'value',
						name: '注册',
						max: function(value) {
							if (Math.abs(value.max) > Math.abs(value.min)) {
								return (Math.abs(value.max)).toFixed(2);
							} else {
								return (Math.abs(value.min)).toFixed(2);
							}
						},
						min: function(value) {
							if (Math.abs(value.max) > Math.abs(value.min)) {
								return (-Math.abs(value.max)).toFixed(2);
							} else {
								return (-Math.abs(value.min)).toFixed(2);
							}
						}
					},
					{
						type: 'value',
						name: '活跃',
						max: function(value) {
							if (Math.abs(value.max) > Math.abs(value.min)) {
								return (Math.abs(value.max)).toFixed(2);
							} else {
								return (Math.abs(value.min)).toFixed(2);
							}
						},
						min: function(value) {
							if (Math.abs(value.max) > Math.abs(value.min)) {
								return (-Math.abs(value.max)).toFixed(2);
							} else {
								return (-Math.abs(value.min)).toFixed(2);
							}
						}
					}
				],
				series: [{
						name: '注册',
						type: 'bar',
						data: LeftNum
					},
					{
						name: '活跃',
						type: 'bar',
						yAxisIndex: 1,
						data: RightNum
					},

				]
			};

			if (option && typeof option === "object") {
				myChart.setOption(option, true);
				myChart.on('legendselectchanged', function(params) {
					option.legend.selected = params.selected
					selected = params.selected
					myChart.setOption(option);
				})
			}

# 通过比例计算最小值

通过镜像正区间的方式,能实现效果,但是不尽如意。下方留白会过多

从上图中分析可以知道:

  • 1.正区间双轴最大值可以从数据中算出
  • 2.负区间双轴最大值也是可以算出来的
  • 3.只有负区间的较小值需要通过比例计算

通过列方程简化后可解得:min1 = max1 * min2 / max2

  • min1 max1 表示负区间中的较小值的轴,图中右轴
  • min2 max2 表示负区间中的较大值的轴,图中左轴
通过比例计算最小值

注:不要去 format 计算出来的数据,不然会出现对不齐(悬空、挤出)等情况。可以用 yAxis.axisLabel.formatter 处理展示内容。

					// 数据
		var LeftNum = [0, 1336, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, ]
		//var LeftNum = [503, 1689, 118, 165, 686, 662, 645, 320, 15, -113, 40, 143, 740, 182, -29];

		var LeftData = {
			max: Math.max(...LeftNum),
			min: Math.min(...LeftNum)
		}
		var RightNum = [-571840, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
		//var RightNum = [2, 0, 6, 2, 2, 3, 11, 6, 7, 4, 1, 2, 1, 6, 7];

		var RightData = {
			max: Math.max(...RightNum),
			min: Math.min(...RightNum)
		}
		console.log(LeftData)
		console.log(RightData)
		// 选中项
		var selected = {
			注册: true,
			活跃: true
		}


		var dom = document.getElementById("container");
		var myChart = echarts.init(dom);
		var app = {};
		option = null;

		option = {
			//1、 格式化提示信息
			tooltip: {
				trigger: 'axis',
			},
			toolbox: {
				feature: {
					dataView: {
						show: true,
						readOnly: false
					},
					magicType: {
						show: true,
						type: ['line', 'bar']
					},
					restore: {
						show: true
					},
					saveAsImage: {
						show: true
					}
				}
			},
			legend: {
				data: ['注册', '活跃'],
				selected,
			},
			grid: {
				width: '50%',
				height: '50%'
			},
			xAxis: [{
				type: 'category',
				data: [
					"2022-09-01",
					"2022-09-02",
					"2022-09-03",
					"2022-09-04",
					"2022-09-05",
					"2022-09-06",
					"2022-09-07",
					"2022-09-08",
					"2022-09-09",
					"2022-09-10",
					"2022-09-11",
					"2022-09-12",
					"2022-09-13",
					"2022-09-14"
				],
				axisPointer: {
					type: 'shadow'
				}
			}],
			yAxis: [{
					type: 'value',
					name: '注册',
					min: function(value) {
						let t = Min(value, 'left')
						console.log("Left", t);
						return t;
					},
					max: function(value) {
						return Max(value)
					}
				},
				{
					type: 'value',
					name: '活跃',
					min: function(value) {
						let t = Min(value, 'right')
						console.log("Right", t);
						return t;
					},
					max: function(value) {
						return Max(value)
					}
				}
			],
			series: [{
					name: '注册',
					type: 'bar',
					data: LeftNum
				},
				{
					name: '活跃',
					type: 'bar',
					yAxisIndex: 1,
					data: RightNum
				},

			]
		};

		if (option && typeof option === "object") {
			myChart.setOption(option, true);
			myChart.on('legendselectchanged', function(params) {
				option.legend.selected = params.selected
				selected = params.selected
				myChart.setOption(option);
			})
		}

		// 计算最小值
		function Min(value, direction) {
			if (LeftData.min >= 0 && RightData.min >= 0) {
				return 0;
			}
			if (direction === 'left') {
				if (Math.abs(LeftData.min) > Math.abs(RightData.min)) {
					if(LeftData.min > 0) return 0;
					return LeftData.min;
				} else {
					if (RightData.max === 0) {
						return -Math.abs(LeftData.max)
					}
					// max1 * min2 / max2
					let t = LeftData.max * RightData.min / RightData.max;
					return t; // 不要 format 数据,不然会出现对不齐的情况
				}
			}
			if (direction === 'right') {
				if (Math.abs(RightData.min) > Math.abs(LeftData.min)) {
					return RightData.min;
				} else {
					if (LeftData.max === 0) {
						return -Math.abs(RightData.max)
					}
					// max1 * min2 / max2
					let t = RightData.max * LeftData.min / LeftData.max;
					if(t > 0) return 0;
					return t; // 不要 format 数据,不然会出现对不齐的情况
				}
			}

		}

		function Max(value) {
			console.log("MAX", value);
			if (value.max === 0) {
				return Math.abs(value.min)
			}
			return value.max;
		}

# 最后

学好数学是很重要滴!😀

Last Updated: 12/29/2022, 4:03:50 PM