微信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)
  },

写的比较匆忙粗糙,想要理解的话还是需要一段时间的,若是有什么不足也欢迎交流

猜你喜欢

转载自blog.csdn.net/qq_20686495/article/details/82892313