|
由于微信小程序本身框架的限制,很難集成目前已有的圖表工具,顯示圖表目前有兩種方案:
下面我們來看下怎么在微信小程序中繪制圖表。 API查看微信小程序詳細(xì) Canvas API 文檔。 在模板文件中使用<canvas></canvas>聲明一個canvas組件。 使用wx.createContext獲取繪圖上下文 context。 調(diào)用wx.drawCanvas進(jìn)行繪制。
wx.drawCanvas({
canvasId: 'firstCanvas',
actions: context.getActions() // 獲取繪圖動作數(shù)組
});
開始圖表的繪制繪制折線圖
// 獲取繪圖上下文 context
var context = wx.createContext();
// 設(shè)置描邊顏色
context.setStrokeStyle("#7cb5ec");
// 設(shè)置線寬
context.setLineWidth(4);
context.moveTo(50, 70);
context.lineTo(150, 150);
context.lineTo(250, 30);
context.lineTo(350, 120);
context.lineTo(450, 150);
context.lineTo(550, 95);
// 對當(dāng)前路徑進(jìn)行描邊
context.stroke();
wx.drawCanvas({
canvasId: 'testCanvas',
actions: context.getActions()
});
說明:moveTo方法不記錄到路徑中 效果圖: 好像沒有想象中難,看上去效果還不錯。 繪制每個數(shù)據(jù)點(diǎn)的標(biāo)識圖案
...
context.beginPath();
// 設(shè)置描邊顏色
context.setStrokeStyle("#ffffff");
// 設(shè)置填充顏色
context.setFillStyle("#7cb5ec");
context.moveTo(50 + 7, 70);
// 繪制圓形區(qū)域
context.arc(50, 70, 8, 0, 2 * Math.PI, false);
context.moveTo(150 + 7, 150);
context.arc(150, 150, 8, 0, 2 * Math.PI, false);
...
context.closePath();
// 填充路徑
context.fill();
context.stroke();
效果圖: 說明:避免之前繪制的折線路徑影響到標(biāo)識圖案的路徑,這里包裹在了beginPath和closePath中。 繪制橫坐標(biāo) 規(guī)定我們的參數(shù)格式是這樣的。
opts = {
width: 640, // 畫布區(qū)域?qū)挾?
height: 400, // 畫布區(qū)域高度
categories: ['2016-08', '2016-09', '2016-10', '2016-11', '2016-12', '2017']
}
我們根據(jù)參數(shù)中的categories來繪制橫坐標(biāo)。 稍微整理下思路:
var eachSpacing = Math.floor(opts.width / opts.categories.length);
var points = [];
// 起始點(diǎn)x坐標(biāo)
var startX = 0;
// 起始點(diǎn)y坐標(biāo)
var startY = opts.height - 30;
// 終點(diǎn)x坐標(biāo)
var endX = opts.width;
// 終點(diǎn)y坐標(biāo)
var endY = opts.height;
// 計(jì)算每個分類的起始點(diǎn)x坐標(biāo)
opts.categories.forEach(function(item, index) {
points.push(startX + index * eachSpacing);
});
points.push(endX);
// 繪制橫坐標(biāo)
context.beginPath();
context.setStrokeStyle("#cccccc");
context.setLineWidth(1);
// 繪制坐標(biāo)軸橫線
context.moveTo(startX, startY);
context.lineTo(endX, startY);
// 繪制坐標(biāo)軸各區(qū)塊豎線
points.forEach(function(item, index) {
context.moveTo(item, startY);
context.lineTo(item, endY);
});
context.closePath();
context.stroke();
context.beginPath();
// 設(shè)置字體大小
context.setFontSize(20);
// 設(shè)置字體填充顏色
context.setFillStyle('#666666');
opts.categories.forEach(function(item, index) {
context.fillText(item, points[index], startY + 28);
});
context.closePath();
context.stroke();
效果圖: 效果不錯,除了文字沒有居中…… 查看微信小程序官方提供的文檔并沒有提供HTML5 Canvas中的mesureText(獲取文案寬度)方法,下面我們自己簡單的實(shí)現(xiàn),并不是絕對精確,但是誤差基本可以忽略。
function mesureText (text) {
var text = text.split('');
var width = 0;
text.forEach(function(item) {
if (/[a-zA-Z]/.test(item)) {
width += 14;
} else if (/[0-9]/.test(item)) {
width += 11;
} else if (/\./.test(item)) {
width += 5.4;
} else if (/-/.test(item)) {
width += 6.5;
} else if (/[\u4e00-\u9fa5]/.test(item)) {
width += 20;
}
});
return width;
}
這里分別處理了字母、數(shù)字、 .、 -、漢字這幾個常用字符。 上面的代碼稍微修改下:
opts.categories.forEach(function(item, index) {
var offset = eachSpacing / 2 - mesureText(item) / 2;
context.fillText(item, points[index] + offset, startY + 28);
});
大功告成! 如何在折線上繪制出每個數(shù)據(jù)點(diǎn)的數(shù)值文案大家可以動手自己實(shí)現(xiàn)下。 確定縱坐標(biāo)的范圍并繪制為了避免縱坐標(biāo)的刻度出現(xiàn)小數(shù)的情況,我們把縱坐標(biāo)分為5個區(qū)塊,我們?nèi)∽钚挝豢潭葹槔?0(能夠被5整除),當(dāng)然真實(shí)情況會比這復(fù)雜,待會兒我們再討論。 所以我們的處理輸入輸出應(yīng)該是下面的結(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';
// 進(jìn)行取整操作,避免while時進(jìn)入死循環(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)完成了,但是細(xì)想一下這個范圍還是不是很理想,比如用戶傳入的數(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]
}, {
|