在微信小程序中繪製圖表(part2)

本期大綱

一、肯定縱座標的範圍並繪製javascript

二、根據真實數據繪製折線java

相關閱讀:
在微信小程序中繪製圖表(part1)
在微信小程序中繪製圖表(part3)git

關注個人 github 項目 查看完整代碼。 github

肯定縱座標的範圍並繪製

爲了不縱座標的刻度出現小數的狀況,咱們把縱座標分爲5個區塊,咱們取最小單位刻度爲例如10(可以被5整除),固然真實狀況會比這複雜,待會兒咱們再討論。canvas

因此咱們的處理輸入輸出應該是下面的結果小程序

(5, 34.1)  => (10, 40)
(10, 34)   => (10, 40)
(-5.1, 40) => (-10, 40)
// 肯定Y軸取值範圍
function findRange (num, type, limit) {
    limit = limit || 10;
    
    // upper向上查找,lower向下查找
    type = type ? type : 'upper';

    // 進行取整操做,避免while時進入死循環
    if (type === 'upper') {
        num = Math.ceil(num);
    } else {
        num = Math.floor(num);
    }
    while (num % limit !== 0) {
        if (type === 'upper') {
            num++;
        } else {
            num--;
        }
    }

    return num;
}

好了,初步的肯定範圍已經完成了,可是細想一下這個範圍仍是不是很理想,好比用戶傳入的數據都是小數級別的,好比 (0.2, 0.8),咱們輸出的範圍是(0, 5)這個範圍偏大,圖表展示的效果則會是上面有大部分的留白,一樣用戶輸入的數據很大,好比(10000, 18000),咱們獲得的範圍是(10000, 18010),這個範圍則沒什麼意義,因此咱們須要根據傳入的數據的範圍來分別肯定咱們的最小單位刻度。segmentfault

規定咱們的參數格式是這樣的:微信小程序

opts = {
    ...
    series: [{
            ...
            data: [15, 20, 45, 37, 4, 80]
        }, {
            ...
            data: [70, 40, 65, 100, 34, 18]
        }
    ]
}

讓咱們繼續進行優化數組

// 合併數據,將series中的每項data整合到一個數組當中
function dataCombine(series) {
    return series.reduce(function(a, b) {
        return (a.data ? a.data : a).concat(b.data);
    }, []);
}

// 根據數據範圍肯定最小單位刻度
function getLimit (maxData, minData)
    var limit = 0;
    var range = maxData - minData;
    if (range >= 10000) {
        limit = 1000;
    } else if (range >= 1000) {
        limit = 100;
    } else if (range >= 100) {
        limit = 10;
    } else if (range >= 10) {
        limit = 5;
    } else if (range >= 1) {
        limit = 1;
    } else if (range >= 0.1) {
        limit = 0.1;
    } else {
        limit = 0.01;
    }
}

var dataList = dataCombine(opts.series);
// 獲取傳入數據的最小值
var minData = Math.min.apply(this, dataList);
// 獲取傳入數據的最大值
var maxData = Math.max.apply(this, dataList);

var limit = getLimit(maxData, minData);

var minRange = findRange(minData, 'lower', limit);
var maxRange = findRange(maxData, 'upper', limit);

如今咱們動態的肯定除了合適的最小刻度範圍,接下來咱們接着優化一下上面的findRange方法,主要是增長對小數的支持微信

function findRange (num, type, limit) {
    limit = limit || 10;
    type = type ? type : 'upper';
    var multiple = 1;
    while (limit < 1) {
        limit *= 10;
        multiple *= 10;
    }
    if (type === 'upper') {
        num = Math.ceil(num * multiple);
    } else {
        num = Math.floor(num * multiple);
    }
    while (num % limit !== 0) {
        if (type === 'upper') {
            num++;
        } else {
            num--;
        }
    }

    return num / multiple;
}

如今咱們已經肯定好了Y軸的取值範圍,關於如何畫出Y軸能夠參看 part1 中X軸的繪製方法,此處再也不累贅。

Y軸效果圖:

opts = {
    ...
    series: [{
            ...
            data: [15, 20, 45, 37, 4, 80]
        }, {
            ...
            data: [70, 40, 65, 100, 34, 18]
        }
    ]
}

clipboard.png

opts = {
    ...
    series: [{
            ...
            data: [0.15, 0.2, 0.45, 0.37, 0.4, 0.8]
        }, {
            ...
            data: [0.30, 0.37, 0.65, 0.78, 0.69, 0.94]
        }
    ]
}

clipboard.png

效果還不錯,咱們接着往下

根據真實數據繪製折線

問題的關鍵在於肯定每一個數據點的(x, y)座標,x座標比較好肯定,咱們根據畫布的寬度以及opts.categories便可肯定。

規定咱們的配置爲:

config = {
    xAxisHeight: 30, // X軸高度
    yAxisWdith: 30   // Y軸寬度
}
var data = [15, 20, 45, 37, 4, 80];
var xPoints = [];
var validWidth = opts.width - config.yAxisWidth;
var eachSpace = validWidth / opts.categories.length;
var start = config.yAxisWidth;

data.forEach(function (item, index) {
    xPoints.push(start + (index + 0.5) * eachSpace);
});

y座標稍微會複雜一點,須要根據Y軸的範圍已經自己的數值進行計算得出。

clipboard.png

因此咱們計算出的y應該爲

y = validHeight * (data - min) / (max - min);
// 因爲canvas畫布是左上角爲原點座標,故咱們變化一下
// 獲得最終的y繪製點
y = valideHeight - y;

代碼以下:

var data = [15, 20, 45, 37, 4, 80];
var yPoints = [];
var validHeight = opts.height - config.xAxisHeight;
data.forEach(function(item) {
    var y = validHeight * (item - min) / (max - min);
    y = validHeight - y;

    yPoints.push(y);
}

如今咱們已經肯定了數據點在畫布上的繪製座標,關於如何繪製折現請查看 part1 中相關內容,此處再也不累贅。

最終效果圖以下:

clipboard.png

預告:下一部分咱們一塊兒討論繪製過程當中的一些技巧、動畫效果和如何工程化咱們的項目。

相關閱讀

在微信小程序中繪製圖表(part1)
在微信小程序中繪製圖表(part3)

相關文章
相關標籤/搜索