只有canvas的api,要搞一個成熟的K線圖組件出來,對我來說是一個巨大的挑戰,但是沒辦法,小程序中,由于api的細微差別,成熟的三方框架用不了,只好硬著頭皮自己來。從熟讀api開始,一步一步嘗試,希望能有所成就。- -!壓力巨大,開擼吧!!
先創建一個canvas元素,以后所有的例子都要用到他,設置好id,綁定好事件,不出意外,canvas元素應該不會改動了
// canvas.wxml <canvas canvas-id="stage" class="stage" bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend" bindtouchcancel="touchcancel" bindlongtap="longtap" > </canvas>
// canvas.wxss .stage { width: 100%; height: 200px; margin: 20px auto; background-color: #fff; }
通過官方文檔api的學習,發現一個圖形,從繪制開始,到結束都有一定的規律,比如畫一個矩形
// 第一步:聲明一個canvas對象 const ctx = wx.createCanvasContext('stage') // 第二步:定義要繪制的內容 ctx.setFillStyle('red') ctx.fillRect(10, 10, 150, 75) // 第三步:根據第二步中繪制的內容,將圖像畫出來 ctx.draw()
這樣,就搞定了矩形
填充樣式很多,比如說線性漸變,圓角漸變等,這些都不是重點,需要的時候找api即可,重點在于如果想要繪制圖片的同時,還想畫一條線,并且寫入幾個文字應該怎么玩?
根據剛才發現的規律,在第二步中分別定義就行,試試看
const ctx = wx.createCanvasContext('stage') ctx.setFillStyle('red') ctx.fillRect(10, 10, 150, 75) ctx.beginPath() ctx.moveTo(10, 100) ctx.lineTo(150, 100) ctx.setStrokeStyle('red') ctx.stroke() ctx.setFontSize(20) ctx.setFillStyle('orange') ctx.fillText('canvas 真尼瑪難!', 10, 150) ctx.draw()
發現凡是填充內容,都是用的跟fill有關的api,凡是填充線條,都是跟stroke有關的api,每一個圖形的繪制,都以一次填充結束,上面我們畫的圖形如下
.
canvas 畫布的坐標跟我們數學上常用的坐標不太一樣,它的(0, 0)點在畫布的左上角,可是實際使用時,我們要將坐標原點放在左下角,或者我們生成的坐標系的原點處。因此,在傳入數據時,我們要講數據進行處理才能符合我們的實際使用。
我的canvas高度為200,因此左下角的坐標點為(0, 200),這時我們根據常識希望畫一個從(0, 0)到(200, 100)的直線,那么我們應該這樣做
line([0, 0], [200, 100]) function line (coors, coore) { const ctx = wx.createCanvasContext('stage') ctx.beginPath() ctx.setStrokeStyle('red') ctx.moveTo(coors[0], 200 - coors[1]) ctx.lineTo(coore[0], 200 - coore[1]) ctx.stroke() ctx.draw() }
如果我們想要畫一個折線圖,從上面的例子可以看出,無非就是根據傳入的數據,多做幾次ctx.lineTo操作即可,根據這個思路可以封裝一個折線圖方法
line (canvasId, options) { let windowWidth = 0 wx.getSystemInfo({ success (result) { windowWidth = result.windowWidth } }) let a = windowWidth / (options.xAxis.length-1) let data = [] options.xAxis.map((item, i) => { data.push([i * a, 200 - options.yAxis[i]]) }) const ctx = wx.createCanvasContext(canvasId) ctx.beginPath() data.map((item, i) => { if (i == 0) { ctx.moveTo(item[0], item[1]) } ctx.lineTo(item[0], item[1]) }) ctx.setLineWidth(1) ctx.setLineCap('square') ctx.setStrokeStyle('red') ctx.stroke() ctx.draw() }
在onLoad中調用
onLoad (e) { this.line('stage', { xAxis: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], yAxis: [11, 33, 22, 32, 14, 15, 20, 60, 23, 44, 77, 122, 133, 89, 156, 122,128, 143, 111, 101, 132, 99, 98, 44, 12, 14, 111, 13, 12, 55] }) },