大致的效果如下
圖中的扇形總共需要用到兩個canvas
wxml
<view class="progress">
<canvas canvas-id="canvasProgress" style="width: {{canvasWidth}}rpx; height: {{canvasHeitht}}rpx;"> </canvas>
</view>
<view class="progress">
<canvas canvas-id="canvasProgressReal" style="width: {{canvasWidth}}rpx; height: {{canvasHeitht}}rpx;"> </canvas>
</view>
wxss因爲兩個canvas需要重合所以用ablolute
.progress {
position:absolute;
z-index: 1;
}
js裏的內容比較多,首先要初始化然後將刷新動畫寫成函數形式
Page({
data: {
canvasWidth: 365,
canvasHeitht: 270,
radioPos: 98,
footNum: 0,
footNumAll: 0,
myTargetFoot: 10000,
degree: 210,
})
timer: undefined,
timerNum: undefined,
onLoad需要初始化背景即淡藍色背景扇形
onLoad: function (options) {
let widthPX = wx.getSystemInfoSync().windowWidth;
let r = this.data.radioPos = widthPX * (365/750) * (270/365) * (2/3)
var context = wx.createCanvasContext('canvasProgress')
context.setStrokeStyle("#DBE9FF");
context.setLineWidth(1);
context.beginPath();
for (let i = 210 ; i >= -30 ; i -= 3){//每3度繪製一條線
let degree = i / 360 * Math.PI * 2
let radio = r * 0.87 - r * 0.05 * (210 - i) / 240
context.moveTo(r + radio * Math.cos(degree), r - radio * Math.sin(degree));//向量加減
context.lineTo(r + r * Math.cos(degree), r - r * Math.sin(degree));//向量加減
context.stroke();
}
context.draw();
},
首先要明白的一點就是canvas的單位是px而不是rpx,所以寬高半徑都是需要從屏幕的寬度來手動設置的
這裏稍微需要一些數學基礎和向量加減運算
頁面切換需要清理canvas並在進入當前頁面重新繪製所以需要在onshow裏做一些事
onShow: function () {
let that = this
//清理
var context = wx.createCanvasContext('canvasProgressReal')
context.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeitht)
context.draw({
reserve: true
})
//掉接口獲取新數據後在回調函數裏調用繪製函數
掉接口({
url:xxx,
header:xxxx,
success:function(){
that.walkAction()
}
})
}
調用已經封裝好的動畫函數
walkAction: function () {
console.log('walk')
this.setData({
degree: 210
})
let that = this
let r = this.data.radioPos
let widthPX = wx.getSystemInfoSync().windowWidth;
var context = wx.createCanvasContext('canvasProgressReal')
context.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeitht)
context.setStrokeStyle("#499AFF");
context.setLineWidth(1);
let degreeMax = 210 - (this.data.footNumAll / this.data.myTargetFoot) * 240;
if (Number.parseInt(this.data.footNumAll) >= Number.parseInt(this.data.myTargetFoot)) {
console.log('footNumAll is smaller than myTargetFoot')
degreeMax = -33
}
this.timer = setInterval(() => {
if (that.data.degree > degreeMax) {
context.beginPath();
let degreeOne = that.data.degree / 360 * Math.PI * 2
let radio = r * 0.87 - r * 0.05 * (210 - that.data.degree) / 240
context.moveTo(r + radio * Math.cos(degreeOne), r - radio * Math.sin(degreeOne));
context.lineTo(r + r * Math.cos(degreeOne), r - r * Math.sin(degreeOne));
context.stroke();
// context.draw({
// reserve: true
// })//這個方法真機上繪製有問題
wx.drawCanvas({
canvasId: 'canvasProgressReal',
actions: context.getActions(),
reserve: true
})
that.data.degree -= 3;
} else {
clearInterval(that.timer)
}
},50)
let tempTimes = 0;
let times = (this.data.footNumAll / this.data.myTargetFoot) * 240 / 3;
if (Number.parseInt(this.data.footNumAll) >= Number.parseInt(this.data.myTargetFoot)) {
times = 80
}
let step = this.data.footNumAll / times
this.timerNum = setInterval(() => {
if (tempTimes < times) {
that.setData({
footNum: Math.floor(that.data.footNum + step)
})
tempTimes += 1;
} else {
that.setData({
footNum: that.data.footNumAll
})
clearInterval(that.timerNum)
}
}, 50)
},
寫的比較匆忙粗糙,想要理解的話還是需要一段時間的,若是有什麼不足也歡迎交流