美文网首页Web 前端开发
进阶版一步一步去实现一个环形进度条

进阶版一步一步去实现一个环形进度条

作者: cb12hx | 来源:发表于2018-02-28 21:42 被阅读0次

    曾经我写过一个简单的环形进度条
    本篇文章对进度条再进行一下优化,效果如下

    QQ20180228-204416-HD.gif

    由图可见,进度加了渐变,文字和进度都加了动画
    首先,我们来一步步分解
    一个进度条由三个部分组成
    1.底部背景线
    2.中间文字
    3.当前进度

    注意事项1

    先讲一下大概的思路吧,这个的难点是画渐变,首先,这里面的渐变是由一条条圆弧组成的,每一条圆弧都有自己的颜色,那么我们要平分圆弧和颜色,只要解决了这个,基本上渐变就出来了,这里要注意,不能用canvas自己的渐变,因为线性渐变要么是上下,要么是左右,没有沿着圆弧的,径向渐变就更加不行了,只能由内而外

    注意事项2

    一般情况下,假如我们用css来定义canvas时,还要给canvas定义宽度和高度,其值为css的两倍,如下所示

    <style>
    #canvas1{
      width:200px;
      height:100px
    }
    </style>
    

    那么此时canvas要定义如下

    <canvas width=400 height=200 />
    

    但是,现在我们主要做手机端,要兼容各种分辨率,一般我们都是用rem来定义大小,此时就不能直接给canvas赋值width和height了,但是也很简单,假如我们的css这样定义

    <style>
    #canvas1{
      width:10rem;
      height:5rem
    }
    </style>
    

    那么可以用js来定义canvas的大小,如下

      canvas.width = canvas.offsetWidth * 2
      canvas.height = canvas.offsetHeight * 2
    

    1.底部背景线

    这个比较简单,就是画一个圆即可,大概的代码如下

        ctx.lineWidth = percentageWidth / 2
        ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2 - percentageWidth / 2, 0, Math.PI * 2)
        ctx.strokeStyle = '#00FFFF'
        ctx.stroke()
    

    其中的percentageWidth是指进度的宽度,这里把底部背景线设为了它的一半,另外注意arc中的半径,是canvas宽度的一般减去了进度条宽度的一半,如果不减的话,就超出了canvas了

    2.画进度条

    从上面我们知道,进度条是由一段一段的圆弧组成的,所以这里的核心就是怎么去分割圆弧,并且拼起来的圆弧的颜色要是渐变的,首先,需要定义一个变量来设置每一个段圆弧的大小,那么就能根据圆弧的起始点和结束点,算出需要画多少条圆弧才能拼起来
    首先把一些全局变量列出来,注释就写清楚了

      var canvas = document.getElementById("canvas")
      var ctx = canvas.getContext('2d')
      // 要画的圆弧的百分比,总共为100
      var percentage = 77
      // 每一次加的圆弧大小
      var step = .05
      // 进度条的宽度
      var percentageWidth = 20
      // 结束点的弧度
      var endArc = Math.PI * 2 * percentage / 100 - Math.PI / 2
      // 当前进度的弧度,设置默认值,把当前进度放到12点位置(默认是3点位置)
      var currentArc = -Math.PI / 2
      // 用来做循环的对象
      var intervalObj = null
      // 文字大小,当canvas大小设置之后会再重新设置
      var fontSize = 20
      // 要画的弧度条数,结束弧度减去开始弧度,再除以每一次加的弧度,即可得到
      var times = (endArc - currentArc) / step
      // 调用的第三方算法,正好根据要画的弧度条数来分割
      var gradient = new gradientColor('#008000', '#ff0000', times)
      // 当前在画的那条弧的索引,用来取颜色值
      var index = -1
    

    接下来我们来看怎么一步步去画圆弧的

        // 开启一段新路径
        ctx.beginPath()
        // 设置当前的圆弧的颜色
        ctx.strokeStyle = gradient[++index]
        // 设置圆弧的宽度
        ctx.lineWidth = percentageWidth
        // 记住圆弧开始的弧度
        var startArc = currentArc
        // 算出圆弧结束的角度
        currentArc += step
        // 0.05的偏移量,不加的话没有完全盖住上一个弧,看起来有间隔
        // 画文字
        drawText((currentArc + Math.PI / 2 - 0.05) / (Math.PI * 2))
        // 如果当前结束的弧度大于最后结束的弧度,那么取消动画,并且画出最后的这段弧度
        // 否则继续画下一条弧度
        if (currentArc >= endArc) {
          cancelAnimationFrame(intervalObj)
          ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2 - percentageWidth / 2, startArc, endArc)
          ctx.stroke()
          return
        } else {
          ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2 - percentageWidth / 2, startArc.toFixed(2) - 0.05, currentArc.toFixed(2))
          ctx.stroke()
        }
        // 做动画
        intervalObj = requestAnimationFrame(drawCurrentProgress)
    

    3.画文字

    其实,在上一步中,我们已经调用了画文字的方法,但是方法体没有给出,这里主要的思路是,每一次画出当前的百分比,下一次画时,把上一次的文字擦除即可,用到的clearRect和fillText,代码如下

      function drawText(text) {
        // 把文字转换为整数
        text = (text * 100).toFixed(0)
        // 设置字体,其实可以全局设置,没拿出去
        ctx.font = `${fontSize}px serif`
        // 获取文字的宽度,这里加上了百分号
        var textWidth = ctx.measureText(text + '%').width
        // 清除文字,注意这里是根据文字的宽度和文字的大小来计算的,
        // 宽度乘上1.1是为了将擦除区域变得比文字区域大一点
        ctx.clearRect(canvas.width / 2 - textWidth / 2, canvas.height / 2 - fontSize, textWidth * 1.1, fontSize * 2)
        //设置文本的垂直对齐方式
        ctx.textBaseline = 'middle'
        //设置文本的水平对齐方式
        ctx.textAlign = 'center'
        // 填充文字
        ctx.fillText(text + '%', canvas.width / 2, canvas.height / 2)
      }
    

    ok,基本上差不多了
    完整代码

    相关文章

      网友评论

        本文标题:进阶版一步一步去实现一个环形进度条

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