mpvue 环形进度条

1,297 阅读2分钟

产品需求

小程序圆形进度条来表示任务的完成进度。

需求分析

初步分析

  1. canvas绘制背景
  2. canvas绘制进度条
  3. canvas绘制数字(为什么不用div绝对定位,原因是div会解析成小程序的view标签,而canvas是客户端创建的原生组件,原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上)

文件结构

<template>
  <div class="chart">
    <canvas :canvas-id="bgId" class="pie"></canvas>
    <canvas :canvas-id="progressId" class="pie"></canvas>
    <canvas :canvas-id="percentId" class="pie"></canvas>
  </div>
</template>
<script>
    export default {
      props: ['radius', 'item'],
      created() {
        const percent = this.item.percent
        // 因为是在列表中用到
        this.bgId = `${this.bgId}-${this.item.id}`
        this.progressId = `${this.progressId}-${this.item.id}`
        this.percentId = `${this.percentId}-${this.item.id}`
        // 绘制背景
        this.handleDrawBg()
        // 绘制进度条
        this.handleDrawCircle(percent)
        // 绘制百分数字
        this.handleDrawPercent(percent)
      },
      methods: {
          handleDrawBg() {},
          handleDrawCircle(percent = 0) {},
          handleDrawPercent(percent = 0){}
      }
    }
</script>
<style lang="scss">
    .chart {
        position: relative;
        .pie {
          position: absolute;
          top: 0;
          right: 10px;
          height: 100px;
          width: 100px;
        }
    }
</style>

文件中canvas-id用了变量绑定了变量,是因为列表会渲染多个相同canvas-idcanvas,导致除第一个canvas之外其他canvas标签自动加上了display:none

绘制背景

 handleDrawBg() {
      // 创建 canvas 的绘图上下文 CanvasContext 对象
      var ctx = wx.createCanvasContext(this.bgId)
      const radius = this.radius || 40
      ctx.setLineWidth(10) // 设置圆环的宽度
      ctx.setStrokeStyle('#EDF0F6') // 设置填充颜色
      ctx.beginPath() // 开始创建一个路径
      ctx.arc(radius + 10, radius + 10, radius - 10, 0, 2 * Math.PI, false) // 圆点(50,50)内半径为30
      ctx.stroke() // // 画出当前路径
      ctx.draw()
    },

效果如下:

绘制进度圆环

一个圆周的弧度是2π,一个圆周是360度,那么一度角对应2π/360弧度。 于是得出,任意度数角α对应的弧度是α*π/180

handleDrawCircle(percent = 0) {
      var ctx = wx.createCanvasContext(this.progressId)
      const radius = this.radius || 40
      var gradient = ctx.createLinearGradient(90, 0, 0, 90) // 圆环为从右上到左下渐变
      gradient.addColorStop('0', '#00B9FF')
      gradient.addColorStop('1.0', '#98DEF8')
      ctx.setLineWidth(10) // 宽度为10
      ctx.setStrokeStyle(gradient) // 填充颜色
      // 若设置线条的端点样式为圆形,当进度为0时会显示一个圆点
      if (percent !== 0) {
        ctx.setLineCap('round')
      }
      ctx.beginPath()
      // -Math.PI / 2 将起始角设在12点钟位置
      ctx.arc(
        radius + 10,
        radius + 10,
        radius - 10,
        -Math.PI / 1.75,
        percent / 100 * Math.PI * 2 - Math.PI / 1.75,
        false
      )
      ctx.stroke()
      ctx.draw()
    },

效果图:

绘制百分比

文字有个加粗效果。因此文字绘制了两次有个叠加效果,看起来和加粗效果一样

handleDrawPercent(percent = 0) {
      var ctx = wx.createCanvasContext(this.percentId)
      ctx.setFontSize(20)
      ctx.setFillStyle('#41444A')
      ctx.fillText(percent, 34, 59 - 0.5)
      ctx.fillText(percent, 34 - 0.5, 59)
      ctx.setFontSize(13)
      ctx.fillText('%', 57, 59)
      ctx.draw()
    }

最后

文笔粗糙,请多指教。