美文网首页
小程序表盘进度动画(类似芝麻信用动画)

小程序表盘进度动画(类似芝麻信用动画)

作者: 疯子不需要风 | 来源:发表于2019-07-26 16:51 被阅读0次

    先上个效果图:


    timer.gif

    本案例是用微信小程序实现,canvas属性方法跟H5 canvas略有些不同,不过大体意思一样,所以在H5中实现原理也是一样的
    下面是样式布局,相对比较简单

    <!--pages/charge/charging/charging.wxml-->
    <view class="charging-view">
        <view class="charging-top">
            <view class="charging-title">充电站</view>
            <view class="charging-canvas">
                <canvas canvas-id="canvas" style="width: {{canvasWidth}}px; height: {{canvasWidth*4/5}}px; margin: auto auto;"></canvas>
            </view>
            <view class="v-flex charging-time">
                <view>21</view>
                <view>21</view>
                <view>21</view>
            </view>
        </view>
        <view class="charging-item">
            <view class="charging-item-title">开始电池电量</view>
            <view class="charging-item-bg item-bg1">
                <view class="charging-item-step" style="width: {{startElec}}%">{{startElec}}%</view>
            </view>
        </view>
        <view class="charging-item">
            <view class="charging-item-title">当前电池电量</view>
            <view class="charging-item-bg item-bg2">
                <view class="charging-item-step" style="width: {{currentElec}}%">{{currentElec}}%</view>
            </view>
        </view>
        <view class="charging-item">
            <view class="charging-item-title">已充电量</view>
            <view class="charging-item-bg item-bg3">
                <view class="charging-item-step" style="width: {{currentElec-startElec}}%">{{(currentElec-startElec)}}%</view>
            </view>
        </view>
        <view class="v-flex charging-status">
            <view class="v-flex-item charging-item-title">预计剩余时长</view>
            <view class="charging-status-text">01:00:00</view>
        </view>
        <view class="v-flex charging-status">
            <view class="v-flex-item charging-item-title">消费金额</view>
            <view class="charging-status-text">100元</view>
        </view>
        <view class="charging-btn">
            <button class="v-button" hover-class="v-active" bindtap="endCharge">结束充电</button>
            <view class="charging-tips">温馨提示:充电完成后将在钱包中自动划扣消费金额。</view>
        </view>
    </view>
    

    接下来是js实现部分,在代码里基本上都有详细的注释说明,直接上代码了

    // pages/charge/charging/charging.js
    var context; //canvas上下文环境
    const lineWidth = 15; //蓝色环形边框宽度
    const pointR = 12; //动画圆圈半径
    let centerX, centerY, circleR; //大圆圆心半径
    let timer;
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
          canvasWidth: '', //canvas宽度
          startElec: 30, //起始电量
          currentElec: 30, //当前电量
          alreadyElec: 0  //已充电量
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
          // 获取设备信息
          this.getSystemInfo()
      },
    
      /**
       * 生命周期函数--监听页面初次渲染完成
       */
      onReady: function () {
          // 开始绘制画布
          this.createCanvas()
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function () {
    
      },
    
      /**
       * 生命周期函数--监听页面隐藏
       */
      onHide: function () {
    
      },
    
      /**
       * 生命周期函数--监听页面卸载
       */
      onUnload: function () {
    
      },
    
      /**
       * 页面相关事件处理函数--监听用户下拉动作
       */
      onPullDownRefresh: function () {
    
      },
    
      /**
       * 页面上拉触底事件的处理函数
       */
      onReachBottom: function () {
    
      },
    
      /**
       * 用户点击右上角分享
       */
      onShareAppMessage: function () {
    
      },
      /**
       * 自定义事件
       */
      endCharge() {
          wx.navigateTo({
              url: "./../endCharge/endCharge"
          })
      },
      // 獲取設備信息
      getSystemInfo() {
          const that = this
          wx.getSystemInfo({
              success (res) {
                  that.setData({
                    canvasWidth: res.windowWidth * 0.6
                  })
              }
           })
      },
      // canvas绘制
      createCanvas() {
          context = wx.createCanvasContext('canvas')
          centerX = (this.data.canvasWidth)/2
          centerY = (this.data.canvasWidth)/2
          circleR = centerX-10
          this.startAnimate()
          timer = setInterval(() => {
              this.startAnimate()
          }, 1000)
      },
      startAnimate() {
          this.setData({
              currentElec: this.data.currentElec+3
          })
          if(this.data.currentElec>100){
              this.setData({
                  currentElec: 100
              })
          }
          context.clearRect(0, 0, this.data.canvasWidth, this.data.canvasWidth)
          this.drawLightCircle()
          this.drawLineCircle()
          this.drawText(this.data.currentElec + '%')
          this.drawAnimateCircle(this.data.currentElec)
          this.drawAnimateDot(this.data.currentElec)
      },
      // 绘制浅蓝色静态大圆
      drawLightCircle() {
          context.save();
          context.setStrokeStyle('#E1EAF5');
          context.setLineWidth(lineWidth);
          context.beginPath();
          context.translate(centerX, centerY);
          context.rotate(150 * Math.PI/180);
          context.arc(0, 0, circleR-lineWidth/2, (Math.PI/180)*0, (Math.PI/180)*240, false);
          context.stroke();
          context.closePath();
          context.restore();
      },
      // 绘制间隔线条
      drawLineCircle() {
          let angel = 4.5 //每间隔多少度画一条线
          let outR = circleR - lineWidth - 12  //间条线外边点距离中心点的长度(即外边半径)
          let inR = circleR - lineWidth * 2 - 5 //间条线内边点距离中心点的长度(即内边半径)
          context.save()
          context.translate(centerX, centerY);  //把中心点移动到
          context.rotate(150 * Math.PI/180); //旋转画布150弧度
          // 遍历,通过两个半径长度outR和inR,利用三角函数得到两个点的坐标绘制线条
          // 遍历的序列号i即为角度值
          for(var i = 0;i<54;i++){
              let startX = outR * Math.cos(angel * i / 180 * Math.PI)
              let startY = outR * Math.sin(angel * i / 180 * Math.PI)
              let endX = inR * Math.cos(angel * i / 180 * Math.PI)
              let endY = inR * Math.sin(angel * i / 180 * Math.PI)
              context.beginPath();
              context.setLineWidth(1);
              context.setStrokeStyle("#9E9CBC");
              context.moveTo(startX, startY)
              context.lineTo(endX, endY)
              context.stroke();
              context.closePath();
          }
          context.restore()
      },
      // 绘制中间百分数文字
      drawText(text) {
          context.save()
          context.translate(centerX, centerY);
          context.beginPath()
          context.setFontSize(30)
          context.setFillStyle("#519FF7")
          context.setTextAlign('center')
          context.setTextBaseline('middle')
          context.fillText(text, 0, 0)
          context.closePath()
          context.restore()
      },
      // 绘制蓝色动态大圆
      drawAnimateCircle(percent) {
          // 整个大圆240度,将240度分为100份,那么每份的角度是2.4度
          let angel = percent * 2.4
          context.save();
          context.setStrokeStyle('#8CC2FF');
          context.setLineWidth(lineWidth);
          context.beginPath();
          context.translate(centerX, centerY);
          context.rotate(150 * Math.PI/180);
          // 绘制半径为大圆半径减去线边框一半,绘制角度从0-angel
          context.arc(0, 0, circleR-lineWidth/2, (Math.PI/180)*0, (Math.PI/180)*angel, false);
          context.stroke();
          context.closePath();
          context.restore();
      },
      // 绘制动画圆点
      drawAnimateDot(percent) {
          let angel = percent * 2.4
          // 计算出circleR-lineWidth/2即为中心点到小圆圆心的长度,利用三角函数关系得到小圆圆心坐标点
          let pointX = (circleR-lineWidth/2) * Math.cos(angel/180 * Math.PI)
          let pointY = (circleR-lineWidth/2) * Math.sin(angel/180 * Math.PI)
          context.save();
          context.translate(centerX, centerY);
          context.rotate(150 * Math.PI/180);
          context.beginPath();
          context.setFillStyle("#ffffff")
          context.setLineWidth(1);
          context.setShadow(0, 0, 5, '#519FF7')
          // 再有圆心点和小圆半径绘制小圆所在的位置
          context.arc(pointX, pointY, pointR, 0, 2 * Math.PI)
          context.fill()
          context.closePath();
          context.draw()
          context.restore();
          if(this.data.currentElec>=100){
              clearInterval(timer)
          }
      }
      
    })
    

    有需要的欢迎转载,有问题欢迎留言~

    相关文章

      网友评论

          本文标题:小程序表盘进度动画(类似芝麻信用动画)

          本文链接:https://www.haomeiwen.com/subject/ksydrctx.html