小程序-Canvas繪製折線圖
自己在一個小程序項目中,希望通過繪製折線圖展示不同時間的數值變化趨勢,搜索了一番後沒找到特別好的第三方庫,故打算自己實現一個簡單的繪製折線圖方法,本文記錄自己如何在小程序中通過canvas繪製折線圖。
目標
最終目標是達到官方小程序數據助手中折線圖的效果:
除了UI目標外,還要便於在小程序其他地方使用或者在其他小程序中使用,所以API要有適當的通用性。
實現
實現的思路是在頁面上放置指定大小的canvas,然後調用API傳遞’canvas id’與配置選項完成繪製,配置選項主要用來指定繪製數據、有關顏色、繪製大小等,繪製的API可以封裝到一個單獨的模塊中便於公用。
接口
暫時設計了4個接口:init、draw、showLine、hideLine,分別用來初始化、繪製、顯示和隱藏某條線,具體API描述如下所示:
- init(ctx: string|CanvasContext, options: object): LineChart
init,返回一個LineChart實例,可以調用LineChart原型上的三個方法,其中:
- ctx: 'canvas id’或通過
wx.createCanvasContext
得到的CanvasContext對象- options:
{
width: 320, // canvas的寬度
height: 200, // canvas的高度
labelColor: '#888888', // label的顏色
axisColor: '#d0d0d0', // 軸的顏色
xUnit: '', // x軸label的單位
yUnit: '', // y軸label的單位
xAxis: [1, 2, 3, 4], // x軸label數組
lines: [{ // 需要繪製的線
color: '#1296db', // 線的顏色
points: [10, 29, 18, 20], // 線的y軸值
}],
margin: 20, // 內容與邊界的距離
fontSize: 12 // 文字大小
}
- LineChart.prototype.draw()
draw,按初始化給定的ctx和options繪製折線圖
- LineChart.prototype.showLine(index: number)
showLine,顯示options.lines[index]中的該條線
- LineChart.prototype.hideLine(index: number)
hideLine,隱藏options.lines[index]中的該條線
代碼
完整代碼移步Github,這裏只描述一下自己用canvas繪製折線圖的主要思路:
- 繪製x軸與label
繪製x軸相對簡單,但所有x軸label都繪製可能導致空間不一夠,所以這裏要依據label數量與寬度計算能夠繪製的個數,然後按等步長的方式從中挑選。同時因爲
ctx.fillText
的繪製位置是從左上角計算,爲避免溢出,x軸label繪製位置在x軸方向要有適當的偏移
- 繪製y軸label以及水平標度線
y軸label數可以根據cavans高度與希望的標度線間距計算,而每條水平標度線的取值則需要考慮options.lines在y軸的最大值。數量與取值決定後,繪製就相對容易
- 繪製線
繪製軸與label需要收集4個信息:xOffset、yOffset、xStep、yStep,分別表示原點的偏移量(座標)和單位步長,此時線上的點:(index, value)對應到的canvas中座標爲:(xOffset + index * xStep, yOffset - value * yStep),最後再使用
ctx.moveTo
結合ctx.lineTo
將所有點連起來即可
- 繪製線與x軸的陰影面積
將需要繪製的區域連接成一個閉合區域再使用
ctx.fill
填充即可,在繪製線的起點前添加其在x軸的投影點作爲新起點,以及在繪製線的終點後添加其在x軸的投影點作爲新終點,最後使用ctx.closePath
串聯起來並fill
- 繪製空心數據點
在每個點的位置使用
ctx.arc
繪製
繪製效果
最後通過LineChart繪製出來的折線圖效果如下:
總結
目前的折線圖還差一個重要的交互功能:“根據觸摸位置,顯示臨近點的y軸取值”,這個功能晚點補上。