echarts绘图双y轴坐标如何对齐,且图形不触顶还很饱满

产品里绘制了大量的图表,柱状图有单轴的也有双轴的,但是双轴的图如果使用echarts默认的绘制,发现两边的坐标并没有对齐,如果绘制辅助线,会发现grid区域有大量错开的辅助线,图形整体就很乱,产品不止一次让我想办法,为此多掉了好多头发,今天就来聊聊数学的重要性,没错是数学!

  1. 现象的产生

当两个Y轴对应的数据差距很大,比如一个是总量,一个是占比,单纯设置两个y轴的splitNumber并不能起到将两个y轴分成同样份数的效果,因为我们设置的splitNumber只是一个建议的值,但实际绘制中echarts并不会完全按照splitNumber来分割y轴,而是根据对应的数据自己选择最美观的绘制区间,但这个区间是对应一组数据来说的,不会去配合另外的数据来使他们对齐。
在这里插入图片描述

  1. 解决方法:上图是echarts官方示例中的一个,原图中给其两个y轴都设置了最大值Max,最小值Min,另外坐标轴还有个属性interval(每个刻度的长度),那么这三个属性就是脱坑的关键,下面上正菜:
  • 确定数据的max和min
    在实际开发中不可能写死最大值和最小值,因为实际数据的大小并不可控而且封装成组件时,这样写死也会造成组件的实用性降低,所以我们要根据实际获取到的数据来设置max和min, 那么就先要获取到数据的max和min
calMax(arr) { // arr是传入的series
      const yAxisData = [[], []]  // 连个y轴,用两个数组将不同y轴对应数据分开
      const maxArr = [] // 用来缓存计算出来的所有Y轴的最大值
      arr.forEach(item => {
        if (item.yAxisIndex === 0) { // 根据数据对应的y轴的下标将数据分别缓存在yAxisData中
          yAxisData[0] = yAxisData[0].concat(item.data)
        }
        if (item.yAxisIndex === 1) {
          yAxisData[1] = yAxisData[1].concat(item.data)
        }
      })
      yAxisData.forEach((item, index) => {
        let max = Number(item[0])
        item.forEach((i, index) => {
          if (Number(i) && Number(i) > max) {
            max = Number(i)
          }
        })
        maxArr[index] = max
      })
      return maxArr
    },

最小值参照上面,一样的操作

  • 确定我们期望绘制的max和min,用差值除以你需要的splitNumber来定义interval

通过 以上一同操作获取到数据的最大值,下面就开始重头戏,设置我们期望绘制的max和min,这就用到了数学,直接上代码

const max = this.calMax(this.baseOptions.series)
const min = this.calMin(this.baseOptions.series)

this.baseOptions.yAxis.forEach((item, index) => {
   if (options.yAxis[index] && !options.yAxis[index].max) {  // 做个截断这样最大值和最小值也可以是手动传入的,例如y轴是月份等固定的数,可以手动传入
	   item.max = max[index]
	   item.min = min[index]
	   if (item.max > 0) {
	      const maxDigit = Math.floor(Math.log(Math.abs(item.max)) / Math.log(10)) - 1  // 根据求最大值以10为底的对数计算最大值得位数(不用管是不是小数,都是可以实现的)
	      // Math没有以10为底的对数求法,这里用了对数的换底公式
	      // 减1是因为省略了一步,如果直接用位数继续下面的计算,求出来的最大值可能会比数据真实的最大值大太多,图形一般会集中分布在grid的下方
	      // 减去一位再进行计算,计算所得的最大值一般会比数据的最大值低一位,这样图形整体就比较丰满,一般距离图表顶部一格左右
	      const maxMultiple = Math.pow(10, maxDigit)
	      // 用pow方法记录我们需要最终精确地位数
	      tem.max = Math.ceil((Math.abs(item.max) * 1.2) / maxMultiple) * maxMultiple
	      // 先将数据最大值放大1.2倍(根据自己的需要),在利用之前的记录的精度对齐向上取整,这样就能获取到你想要的数据(10, 100, 5000, 0.3, 0.005, ...)
	   } else {
	      item.max = 0
	      // 这里如果最大值<= 0,我直接取0, 根据需求自己确定
	   }
	   if (item.min >= 0) {
	       item.min = 0
	   } else {
	       const minDigit = Math.floor(Math.log(-item.min) / Math.log(10)) - 1
	       const minMultiple = Math.pow(10, minDigit)
	       tem.min = -Math.ceil((Math.abs(item.min) * 1.2) / minMultiple) * minMultiple
	       // 这里只给最小值为负时设置的算法,因为为正时直接赋值为0,图形会更好
	   }
	   // 设置Interval,我这里所有的splitNumber都默认为5,也可以选择自己传入,一幅丰满且适用于多种多样是坐标系图就完成了
	   item.interval = (item.max - item.min) / 5
	}
}

以上方法基本你可以解决所有双轴问题,至少我们项目中现在很nice,夸一下自己,一开始我们选择了分层,根据最大值的范围,10, 100, 1000,…分出一个个的范围,最终觉得枚举就算列完了所有情况。但代码也不好维护,最终我只能默默的掏出了珍藏了7,8年的高中数学,终于完成了。

最后,希望还在采坑的猿们可以试试,应该能够帮到你,有bug请留言,毕竟自己想出来的,不一定没有bug,谢谢

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值