由于微信小程序本身框架的限制,很難集成目前已有的圖表工具,顯示圖表目前有兩種方案:
下面我們來看下怎么在微信小程序中繪制圖表。 API查看微信小程序詳細 Canvas API 文檔。 在模板文件中使用<canvas></canvas>聲明一個canvas組件。 使用wx.createContext獲取繪圖上下文 context。 調用wx.drawCanvas進行繪制。 wx.drawCanvas({ canvasId: 'firstCanvas', actions: context.getActions() // 獲取繪圖動作數組 }); 開始圖表的繪制繪制折線圖 // 獲取繪圖上下文 context var context = wx.createContext(); // 設置描邊顏色 context.setStrokeStyle("#7cb5ec"); // 設置線寬 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); // 對當前路徑進行描邊 context.stroke(); wx.drawCanvas({ canvasId: 'testCanvas', actions: context.getActions() }); 說明:moveTo方法不記錄到路徑中 效果圖: 好像沒有想象中難,看上去效果還不錯。 繪制每個數據點的標識圖案 ... context.beginPath(); // 設置描邊顏色 context.setStrokeStyle("#ffffff"); // 設置填充顏色 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(); 效果圖: 說明:避免之前繪制的折線路徑影響到標識圖案的路徑,這里包裹在了beginPath和closePath中。 繪制橫坐標 規(guī)定我們的參數格式是這樣的。 opts = { width: 640, // 畫布區(qū)域寬度 height: 400, // 畫布區(qū)域高度 categories: ['2016-08', '2016-09', '2016-10', '2016-11', '2016-12', '2017'] } 我們根據參數中的categories來繪制橫坐標。 稍微整理下思路:
var eachSpacing = Math.floor(opts.width / opts.categories.length); var points = []; // 起始點x坐標 var startX = 0; // 起始點y坐標 var startY = opts.height - 30; // 終點x坐標 var endX = opts.width; // 終點y坐標 var endY = opts.height; // 計算每個分類的起始點x坐標 opts.categories.forEach(function(item, index) { points.push(startX + index * eachSpacing); }); points.push(endX); // 繪制橫坐標 context.beginPath(); context.setStrokeStyle("#cccccc"); context.setLineWidth(1); // 繪制坐標軸橫線 context.moveTo(startX, startY); context.lineTo(endX, startY); // 繪制坐標軸各區(qū)塊豎線 points.forEach(function(item, index) { context.moveTo(item, startY); context.lineTo(item, endY); }); context.closePath(); context.stroke(); context.beginPath(); // 設置字體大小 context.setFontSize(20); // 設置字體填充顏色 context.setFillStyle('#666666'); opts.categories.forEach(function(item, index) { context.fillText(item, points[index], startY + 28); }); context.closePath(); context.stroke(); 效果圖: 效果不錯,除了文字沒有居中…… 查看微信小程序官方提供的文檔并沒有提供HTML5 Canvas中的mesureText(獲取文案寬度)方法,下面我們自己簡單的實現,并不是絕對精確,但是誤差基本可以忽略。 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; } 這里分別處理了字母、數字、 .、 -、漢字這幾個常用字符。 上面的代碼稍微修改下: opts.categories.forEach(function(item, index) { var offset = eachSpacing / 2 - mesureText(item) / 2; context.fillText(item, points[index] + offset, startY + 28); }); 大功告成! 如何在折線上繪制出每個數據點的數值文案大家可以動手自己實現下。 確定縱坐標的范圍并繪制為了避免縱坐標的刻度出現小數的情況,我們把縱坐標分為5個區(qū)塊,我們取最小單位刻度為例如10(能夠被5整除),當然真實情況會比這復雜,待會兒我們再討論。 所以我們的處理輸入輸出應該是下面的結果。 (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; } 好了,初步的確定范圍已經完成了,但是細想一下這個范圍還是不是很理想,比如用戶傳入的數據都是小數級別的,比如 (0.2, 0.8),我們輸出的范圍是(0, 5)這個范圍偏大,圖表展現的效果則會是上面有大部分的留白,同樣用戶輸入的數據很大,比如(10000, 18000),我們得到的范圍是(10000, 18010),這個范圍則沒什么意義,所以我們需要根據傳入的數據的范圍來分別確定我們的最小單位刻度。 規(guī)定我們的參數格式是這樣的: opts = { ... series: [{ ... data: [15, 20, 45, 37, 4, 80] }, { |