微信canvas畫一個進度條刻度扇形

大致的效果如下

圖中的扇形總共需要用到兩個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)
  },

寫的比較匆忙粗糙,想要理解的話還是需要一段時間的,若是有什麼不足也歡迎交流

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章