最近開發了一款自己的小程序,名字叫做哎呦天氣,在這個小程序中有兩處使用到了畫布canvas,所以在此總結一下。首先看一下我用canvas做的兩個效果:
第一張截屏中的折線圖和第二張截屏中的帶有二維碼的圖片都是使用canvas生成。
OK,開始使用canvas,我們先從簡單的做起,先畫出帶有二維碼、地址、溫度、背景圖的這個圖片:
首先生成一個CanvasContext:
const ctx = wx.createCanvasContext('qrCanvas')
那字符串qrCanvas是怎麼來的呢,其實是在wxml文件中定義的:
<canvas hidden='{{canvasHide}}' style="width: 100%; height: 300px; background-color:#ddd" canvas-id="qrCanvas"></canvas>
可以看到canvas-id就爲qrCanvas.
得到CanvasContext之後呢,我們先畫背景圖,就是那張漂亮的風景圖,主要代碼如下:
let width = systemInfo.windowWidth
let height = 300
ctx.drawImage(bgPicturePath, 0, 0, width, height)
重點代碼爲ctx.drawImage,它有五個參數,第一個背景圖地址(必須爲本地地址,網絡地址不可以),第二個和第三個爲起點座標,第四個和第五個爲圖片的寬高。
下面我們畫一個白色的長方形,位於背景圖的下面,裏面有二維碼圖片等:
ctx.setFillStyle('white')//填充白色
ctx.fillRect(0, height - 60, width, 60)//座標x:0,y:height-60 寬高。。。
然後吧二維碼在畫上去:
ctx.drawImage(qrPicturePath, 5, height - 57, 55, 55)
下面我們就開始畫文字了,
ctx.moveTo(width / 2, 20)//畫筆移動到垂直居中位置(高度20不重要,我隨便寫的)
ctx.setTextAlign('center')//設置文字要垂直居中
ctx.setFillStyle('#333')//字體顏色
ctx.setFontSize(15)//字體大小
ctx.fillText("哎呦天氣,不錯哦!", width / 2, height - 25)//字體內容和位置
然後畫地址、溫度、風向等:
ctx.setFillStyle('white')
//地址
ctx.setFontSize(13)
ctx.fillText('上海', width / 2, 30)
//溫度
ctx.setFontSize(50)
ctx.fillText(currentTmp, width / 2, 120)
//天氣
ctx.setFontSize(15)
ctx.fillText(cond, width / 2, 160)
//風向
ctx.setFontSize(15)
ctx.fillText(wind, width / 2, 190)
最後呢,調用
ctx.draw()
就可以展示在Page上了,那怎麼保存成一張圖片呢:
wx.canvasToTempFilePath({
canvasId: 'qrCanvas',
success: function (res) {
console.log(res)
wx.hideLoading()
wx.previewImage({
urls: [res.tempFilePath]
})
}
})
下面的方法就是把畫布生成圖片並預覽。
OK 下面介紹溫度折線圖的製作,直接上代碼吧:
wxml中:
<canvas class='forecast_canvas' canvas-id="forcastCanvas">
</canvas>
js中:
function drawForecastView(forecast){//參數forecast爲數據模型
const forecastCtx = wx.createCanvasContext('forcastCanvas')
console.log("forecastWeather", forecast)
let width = systemInfo.windowWidth
let height = 130
let dot = width / 12
let maxTmp = parseInt(forecast[0].tmp_max)
let minTmp = parseInt(forecast[0].tmp_min)
forecast.forEach((item)=>{
if (maxTmp < parseInt(item.tmp_max)){
maxTmp = parseInt(item.tmp_max)
}
if (minTmp > parseInt(item.tmp_min)) {
minTmp = parseInt(item.tmp_min)
}
})
let average = (minTmp + maxTmp) / 2 //此溫度在height/2的位置
let dValue = maxTmp - average
let gradient = 4;
while (gradient * dValue > height / 2 - 30){
gradient = gradient - 0.5
}
console.log('倍數', gradient)
let flag = 1
forecastCtx.beginPath()
//最高溫度
forecast.forEach((item)=>{
let x1 = flag * dot;
let y1 = height / 2 - (parseInt(item.tmp_max) - average) * gradient
item.maxX = x1
item.maxY = y1
//畫線
if (flag == 1){
forecastCtx.moveTo(x1, y1)
}else{
forecastCtx.lineTo(x1, y1)
}
//畫圓圈
forecastCtx.arc(x1, y1, 3, 0, 2 * Math.PI)
flag = flag + 2
})
forecastCtx.setStrokeStyle("#FF8C00");
forecastCtx.stroke()
//最低溫度
forecastCtx.beginPath()
flag = 1
forecast.forEach((item) => {
let x2 = flag * dot;
let y2 = height / 2 + (average - parseInt(item.tmp_min)) * gradient
item.minX = x2
item.minY = y2
//畫線
if (flag == 1) {
forecastCtx.moveTo(x2, y2)
} else {
forecastCtx.lineTo(x2, y2)
}
//畫圓圈
forecastCtx.arc(x2, y2, 3, 0, 2 * Math.PI)
flag = flag + 2
})
forecastCtx.setStrokeStyle("#7cb5ec");
forecastCtx.stroke()
console.log(forecast)
forecastCtx.setFontSize(12)
forecastCtx.setTextAlign('center')
//畫文字
for (var i = 0; i < forecast.length; i++) {
forecastCtx.moveTo(forecast[i].maxX, 20)
forecastCtx.fillText(" " + forecast[i].tmp_max + "°", forecast[i].maxX, forecast[i].maxY - 10)
forecastCtx.fillText(" " + forecast[i].tmp_min + "°", forecast[i].minX, forecast[i].minY + 20)
}
forecastCtx.draw()
}
最後呢附上我的小程序的二維碼: