移动端,cavans和svg绘制进度图

发布时间 2023-04-10 20:57:47作者: 珞珞9527

先看效果:

起初是用cavans绘制的 结果会模糊,倍数绘制再缩小也是模糊,最后换成了svg绘制:

cavans:

global.progressChart = {
    template: ` 
      <div class="process-chart-box">
        <canvas id="progressChart">当前浏览器不支持canvas</canvas>
        <img src="xxx/progress_icon.png" class="progress-icon" v-if="per>0" />
      </div>
      `,
    data() {
      return {
        isDark: false
      }
    },
    props: ['per'],
    methods: {
      handleCanvas() {
        const isDark = this.isDark
        const percent = Math.round(this.per) / 100
        let rem =
          (document.body.offsetWidth / 750) * 100 < 60
            ? (document.body.offsetWidth / 750) * 100
            : 60
        let labelW = Math.round(0.32 * rem)

        const box = document.querySelector('.process-chart-box')
        if (!box) return
        const w = box.offsetWidth
        const ctx = document.getElementById('progressChart').getContext('2d')
        ctx.canvas.width = w + 1
        ctx.canvas.height = w + 1

        //外圆环
        ctx.beginPath()
        ctx.arc(w / 2, w / 2, w / 2, 0, 2 * Math.PI)
        //strokeStyle边框  fillStyle填充
        ctx.strokeStyle = isDark ? '#262626' : '#fff'
        ctx.fillStyle = isDark ? '#283851' : '#d6e6ff'
        ctx.fill()
        ctx.stroke()
        //内圆环
        ctx.beginPath()
        ctx.arc(w / 2, w / 2, w / 2 - labelW, 0, 2 * Math.PI)
        ctx.strokeStyle = isDark ? '#262626' : '#fff'
        ctx.fillStyle = isDark ? '#262626' : '#fff'
        ctx.fill()
        ctx.stroke()
        //环形图的进度条
        if (percent > 0) {
          ctx.beginPath()
          ctx.arc(
            w / 2,
            w / 2,
            (w - labelW) / 2,
            -Math.PI / 2,
            -Math.PI / 2 + percent * (Math.PI * 2),
            false
          )
          ctx.lineWidth = labelW
          ctx.lineCap = 'round'
          ctx.strokeStyle = isDark ? '#2f71de' : '#3480ff'
          ctx.stroke()
        }
      }
    },
    mounted() {
      this.$nextTick(() => {
        this.getDisplayMode()
          .then(res => {
            this.isDark = !!res
            this.handleCanvas()
          })
          .catch(() => {
            this.handleCanvas()
          })
        window.addEventListener(
          'resize',
          () => {
            this.handleCanvas()
          },
          false
        )
      })
    },
    watch: {
      per() {
        this.handleCanvas()
      }
    }
  }

svg:

  global.progressChart = {
    template: ` 
      <div class="process-chart-box">
        <svg :width="w" :height="w" version="1.1" xmlns="http://www.w3.org/2000/svg">
          <circle  class="progress-bg" :cx="w/2" :cy="w/2" :r="r" :stroke="isDark ? '#283851' : '#d6e6ff'" :stroke-width="progressW" fill="none"/>
          <circle :style="+per>0?'':'display:none'" class="progress" :transform="rotate" :cx="w/2" :cy="w/2" :r="r" :stroke="isDark ? '#2f71de' : '#3480ff'" :stroke-width="progressW" fill="none" stroke-linecap="round" />
        </svg>
        <img src="xxx/progress_icon.png" class="progress-icon" v-if="per>0" />
      </div>
      `,
    data() {
      return {
        isDark: false
      }
    },
    props: ['per'],
    computed: {
      remToPx() {
        let rem =
          (document.body.offsetWidth / 750) * 100 < 60 ?
          (document.body.offsetWidth / 750) * 100 :
          60
        console.log('remToPx', rem);
        return rem
      },

      // 容器宽度
      w() {
        return 2.2 * this.remToPx
      },
      // 进度宽度
      progressW() {
        return 0.28 * this.remToPx
      },
      // 绘制半径
      r() {
        return (this.w - this.progressW) / 2
      },
      // 进度旋转
      rotate() {
        return `rotate(-90,${this.w/2},${this.w/2})`
      }
    },
    methods: {
      handleSvg() {
        //换成svg绘制
        var progressDom = document.querySelector(".progress");
        if (!progressDom) {
          return
        }
        let persent = this.per
        if (persent > 0) {
          var circleLength = Math.floor(2 * Math.PI * parseFloat(progressDom.getAttribute("r")));
          var value = persent * circleLength / 100;
          progressDom.setAttribute("stroke-dasharray", value + ",10000");
        }

      },
    },
    mounted() {
      this.$nextTick(() => {
        this.getDisplayMode()
          .then(res => {
            this.isDark = !!res
            this.handleSvg()
          })
          .catch(() => {
            this.handleSvg()
          })
      })
    },
    watch: {
      per() {
        this.handleSvg()
      }
    }
  }