在微信小程序中绘制图表(part2)
本期大綱
1、確定縱坐標的范圍并繪制
2、根據(jù)真實數(shù)據(jù)繪制折線
相關(guān)閱讀:
在微信小程序中繪制圖表(part1)
在微信小程序中繪制圖表(part3)
關(guān)注我的 github 項目 查看完整代碼。
確定縱坐標的范圍并繪制
為了避免縱坐標的刻度出現(xiàn)小數(shù)的情況,我們把縱坐標分為5個區(qū)塊,我們?nèi)∽钚挝豢潭葹槔?0(能夠被5整除),當然真實情況會比這復雜,待會兒我們再討論。
所以我們的處理輸入輸出應該是下面的結(jié)果
(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時進入死循環(huán)if (type === 'upper') {num = Math.ceil(num);} else {num = Math.floor(num);}while (num % limit !== 0) {if (type === 'upper') {num++;} else {num--;}}return num; }好了,初步的確定范圍已經(jīng)完成了,但是細想一下這個范圍還是不是很理想,比如用戶傳入的數(shù)據(jù)都是小數(shù)級別的,比如 (0.2, 0.8),我們輸出的范圍是(0, 5)這個范圍偏大,圖表展現(xiàn)的效果則會是上面有大部分的留白,同樣用戶輸入的數(shù)據(jù)很大,比如(10000, 18000),我們得到的范圍是(10000, 18010),這個范圍則沒什么意義,所以我們需要根據(jù)傳入的數(shù)據(jù)的范圍來分別確定我們的最小單位刻度。
規(guī)定我們的參數(shù)格式是這樣的:
opts = {...series: [{...data: [15, 20, 45, 37, 4, 80]}, {...data: [70, 40, 65, 100, 34, 18]}] }讓我們繼續(xù)進行優(yōu)化
// 合并數(shù)據(jù),將series中的每項data整合到一個數(shù)組當中 function dataCombine(series) {return series.reduce(function(a, b) {return (a.data ? a.data : a).concat(b.data);}, []); }// 根據(jù)數(shù)據(jù)范圍確定最小單位刻度 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); // 獲取傳入數(shù)據(jù)的最小值 var minData = Math.min.apply(this, dataList); // 獲取傳入數(shù)據(jù)的最大值 var maxData = Math.max.apply(this, dataList);var limit = getLimit(maxData, minData);var minRange = findRange(minData, 'lower', limit); var maxRange = findRange(maxData, 'upper', limit);現(xiàn)在我們動態(tài)的確定除了合適的最小刻度范圍,接下來我們接著優(yōu)化一下上面的findRange方法,主要是增加對小數(shù)的支持
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; }現(xiàn)在我們已經(jīng)確定好了Y軸的取值范圍,關(guān)于如何畫出Y軸可以參看 part1 中X軸的繪制方法,此處不再累贅。
Y軸效果圖:
opts = {...series: [{...data: [15, 20, 45, 37, 4, 80]}, {...data: [70, 40, 65, 100, 34, 18]}] }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]}] }
效果還不錯,我們接著往下
根據(jù)真實數(shù)據(jù)繪制折線
問題的關(guān)鍵在于確定每個數(shù)據(jù)點的(x, y)坐標,x坐標比較好確定,我們根據(jù)畫布的寬度以及opts.categories即可確定。
規(guī)定我們的配置為:
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坐標稍微會復雜一點,需要根據(jù)Y軸的范圍已經(jīng)本身的數(shù)值進行計算得出。
所以我們計算出的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); }現(xiàn)在我們已經(jīng)確定了數(shù)據(jù)點在畫布上的繪制坐標,關(guān)于如何繪制折現(xiàn)請查看 part1 中相關(guān)內(nèi)容,此處不再累贅。
最終效果圖如下:
預告:下一部分我們一起討論繪制過程中的一些技巧、動畫效果和如何工程化我們的項目。
相關(guān)閱讀
在微信小程序中繪制圖表(part1)
在微信小程序中繪制圖表(part3)
總結(jié)
以上是生活随笔為你收集整理的在微信小程序中绘制图表(part2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ElasticSearch——学习笔记
- 下一篇: 【emWin】例程六:设置颜色