canvas实战(一)

上篇《canvas初识》讲解了canvas的一些基本功能,本篇开始讲解canvas在项目中的应用。

前言

在项目中,UI给出了下图这样一个仪表盘的设计

当然,echart也有类似的仪表盘的功能,因项目中没有引入echart,且与设计稿还是有些不同,本人还是决定用canvas手绘一个。

实战

分析

        1、创建画布 

        2、画底色大半圆(灰色的)

        3、画实际进度圆弧(蓝色)

        4、画刻度

        5、填充文本

<div class="inline-block relative">
    <canvas ref="canvas" :width="width" :height="height"></canvas>
    <div class="absolute content">
      <slot></slot>
    </div>
  </div>

props: {
    percent: {
      type: Number,
      default: 0
    },
    background: {
      type: String,
      default: '#5a8cf9'
    },
    width: {
      type: Number,
      default: 125
    },
    height: {
      type: Number,
      default: 125
    }
  }
const canvas = ref(null)
    const bgX = 70
    const bgY = 70
    const lineW = 12
    const dashW = 4

    const scale = context => {
      // const dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1
      const dpr = 2

      // Get the size of the canvas in CSS pixels.
      const oldWidth = canvas.value.width
      const oldHeight = canvas.value.height
      // Give the canvas pixel dimensions of their CSS
      // size * the device pixel ratio.
      // console.log(
      //   dpr,
      //   'dprdpr',
      //   window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1
      // )
      const _dpr = dpr + 0.3
      canvas.value.width = Math.round(oldWidth * _dpr)
      canvas.value.height = Math.round(oldHeight * _dpr)
      canvas.value.style.width = oldWidth + 'px'
      canvas.value.style.height = oldHeight + 'px'
      context.scale(dpr, dpr)
      return [Math.round(oldWidth * dpr), Math.round(oldHeight * dpr)]
    }

    const drawBg = context => {
      context.save()
      context.beginPath()
      context.arc(bgX, bgY, Math.abs(bgX - lineW / 2), Math.PI * 0.7, 2.3 * Math.PI, false)
      context.strokeStyle = '#F4F6FA'
      context.lineWidth = lineW
      context.lineCap = 'round'
      context.stroke()
      // context.fill()
      // context.closePath()

      // context.beginPath()
      // context.arc(bgX, bgY, Math.abs(bgX - lineW), 0, 2 * Math.PI, false)
      // context.fillStyle = '#fff'
      // context.fill()
      // context.closePath()
      // context.restore()
    }

    const drawCycle = (context, percent) => {
      context.save()
      context.beginPath()
      context.lineWidth = lineW
      context.lineCap = 'round'
      context.arc(bgX, bgY, Math.abs(bgX - lineW / 2), Math.PI * 0.7, 1.6 * Math.PI * percent + Math.PI * 0.7, false)
      context.strokeStyle = props.background
      context.stroke()
      context.closePath()
      context.restore()
    }

    const drawDash = context => {
      context.save()
      context.beginPath()
      // 设置线宽
      context.lineWidth = dashW
      //  "butt" | "round" | "square";
      context.lineCap = 'butt'
      // 设置间距(参数为无限数组,虚线的样式会随数组循环)
      context.setLineDash([1, 11])

      context.arc(bgX, bgY, Math.abs(bgX - lineW - dashW), Math.PI * 0.75, Math.PI * 2.25, false)
      // 填充颜色
      context.strokeStyle = props.background
      // 开始填充
      context.stroke()
      context.closePath()
      context.restore()
    }

    const draw = () => {
      // CanvasRenderingContext2D
      const context = canvas.value.getContext('2d')

      const [width, height] = scale(context)
      const id = requestAnimationFrame(() => {
        drawBg(context)
        drawDash(context)
        //  如果百分比小于0.2 精度设置为0.0001
        let steps = 0.01
        if (props.percent < 0.02) steps = 0.0001
        for (let i = 0; i < props.percent; i += steps) {
          setTimeout(() => {
            context.clearRect(0, 0, width, height)
            drawBg(context)
            drawDash(context)
            drawCycle(context, i)
          }, 1000 * i)
          if (i >= props.percent) {
            cancelAnimationFrame(id)
          }
        }
      })
    }

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逝流水1234

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值