Fork me on GitHub

Echarts获取纵坐标刻度间距的算法思考

概述

近期面试问到了一些原理性的东西,所以打算把这个也做一个整理,记录下来,供以后开发时参考,相信对其他人也有用。

Echarts获取纵坐标刻度间距的博文请见这里

其实刚开始看Echarts的这段代码我也是一脸懵逼的,但是如果仔细看一下还是觉得挺简单的。

原理

首先,对于纵坐标,我们对它有一个期望的分段值,这个期望的分段值是通过最大数/分段数算出来的,代码如下:

// this.data 是数据
const round = true;
const splitNumber = 4;
const max = this.data.reduce((x,y) => x > y ? x : y);
let val = max / splitNumber;

然后,这个val就是我们的期望分段值,它可能是500,也可能是333等不规则的数。我们希望能够把它矫正为一个整十整百整千这样的数。怎么做呢?分为两步,第一步是确认到底是整十还是整百还是整千,其实就是看它的0有多少个。第二步是确定最高位上的数是多少,打个比方就是确定500、3000等里面的5、3。

对于第一步很简单,我们对期望的分段值取10的对数,然后 floor 一下,最后还原就得到了:

const exponent = Math.floor(Math.log(val) / Math.LN10);
const exp10 = Math.pow(10, exponent);

比如说,期望分段值是66666,因为他是整万的,所以我们期望得到10000,用上面的代码计算出来果然是10000.

对于第二步,那就更简单了,只需要把66666/10000 = 6.6进行约分即可,我们可以约成7,那么70000就是我们的实际分段值。所以Echarts用了它自己的一套约分规则:

// 如果传入了 round 参数,则往小的约分
if (round) {
  if (f < 1.5) { nf = 1; }
  else if (f < 2.5) { nf = 2; }
  else if (f < 4) { nf = 3; }
  else if (f < 7) { nf = 5; }
  else { nf = 10; }
}
else {
  // 如果没有传入 round 参数,则往大的约分
  if (f < 1) { nf = 1; }
  else if (f < 2) { nf = 2; }
  else if (f < 3) { nf = 3; }
  else if (f < 5) { nf = 5; }
  else { nf = 10; }
}

实际上,我们这一步可以向上约分一个最近的整数就行了,比如1.5约分为2,4.6约分为5,7.3约分为8,但是Echarts这里只约到1、2、3、5、10这几个数,把大于5的全部越成了10,可能在实际生产环境中是为了好看吧。

最后把我们第一步和第二步的值相乘就得到了最终的分段值,比如第一步是10000,第二步约成了3,那么最终的分段值为30000。不过最后Echarts处理了一下精度问题:

// Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).
// 20 is the uppper bound of toFixed.
return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;

总结

1.怎么样?是不是很简单呢?

2.以后在其它地方进行分段的时候,可以参考这里的分段代码了。

posted @ 2020-10-14 11:38  馒头加梨子  阅读(1082)  评论(0编辑  收藏  举报