概述
近期面試問到了一些原理性的東西,所以打算把這個也做一個整理,記錄下來,供以后開發時參考,相信對其他人也有用。
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.以后在其它地方進行分段的時候,可以參考這里的分段代碼了。
