使用canvas画圆形(弧形)进度条

安全客
• 阅读 9462

效果如下:

使用canvas画圆形(弧形)进度条

可以展示整个圆、半圆以及任意角度弧形(左右对称)的进度条。整体思路如下:

  • 先确定展示的形状,是整个圆、半圆还是一般的弧形

  • 把确定好形状的圆弧均分100等份,计算出每一份所占的弧度

  • 灰色圆弧占100份,红色圆弧最终占的份数由参数确定

  • 设置setInterval定时器,重复执行画图操作

    • 清空画布

    • 先画灰色的圆弧,占100份

    • 再画红色的圆弧:红色圆弧的份数从0开始,每次加1

    • 画红色圆弧末端的红色圆:难点在于根据角度确定红色圆的圆心,这里面涉及到三角函数,在草稿纸上画个图就大致明白了

    • 当红色圆弧的份数达到指定值(传的参数)的时候,清除定时器

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  <title>Canvas</title>
</head>
<body>
  <canvas id="canvas" width="300" height="300"></canvas>

  <script>
    draw(66);
    /**
     * [顺时针方向画图,起始点在左侧]
     * @param  {[number]} percent [所占的进度百分比,比如66%,则传66即可,0 <= percent <= 100]
     * @param  {[number]} sR      [圆弧起始角度,可不传,默认是π/2,Math.PI/2 <= sR < 3/2 * Math.PI]
     */
    function draw(percent, sR) {
      if (percent < 0 || percent > 100) {
        return;
      }
      if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) {
        return;
      }

      var canvas = document.querySelector('#canvas'),
          cxt = canvas.getContext('2d'),
          cWidth = canvas.width,
          cHeight = canvas.height,
          baseColor = '#e1e1e1',
          coverColor = '#fe4d43',
          PI = Math.PI,
          sR = sR || 1/2 * PI; // 默认圆弧的起始点弧度为π/2

      var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 红圈的终点弧度
      var step = (PI + (PI - sR) * 2)/100; // 一个1%对应的弧度大小
      var text = 0; // 显示的数字
      var timer = setInterval(function() {
        cxt.clearRect(0, 0, cWidth, cHeight);
        var endRadian =  sR + text * step;
        // 画灰色圆弧
        drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2);
        // 画红色圆弧
        drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2);

        // 画红色圆头
        // 红色圆头其实就是一个圆,关键的是找到其圆心,涉及到三角函数知识,自己画个图一看就明了
        var angle = 2*PI - endRadian; // 转换成逆时针方向的弧度(三角函数中的)
        xPos = Math.cos(angle) * 80 + cWidth/2; // 红色圆 圆心的x坐标
        yPos = -Math.sin(angle) * 80 + cHeight/2; // 红色圆 圆心的y坐标
        drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2);

        // 数字
        cxt.fillStyle = coverColor;
        cxt.font = '40px PT Sans';
        var textWidth = cxt.measureText(text+'%').width;
        cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15);
        text++;

        if (endRadian.toFixed(2) >= finalRadian.toFixed(2)) {
          clearInterval(timer);
        }
      }, 30);

      function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) {
        cxt.beginPath();
        cxt.lineCap = "round";
        cxt.strokeStyle = color;
        cxt.lineWidth = lineWidth;
        cxt.arc(x, y, r, sRadian, eRadian, false);
        cxt.stroke();
      }
    }
  </script>
</body>
</html>

关于动画部分,可以使用requestAnimationFrame做优化,函数改写如下:

function draw(percent, sR) {
  if (percent < 0 || percent > 100) {
    return;
  }
  if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) {
    return;
  }

  var canvas = document.querySelector('#canvas'),
      cxt = canvas.getContext('2d'),
      cWidth = canvas.width,
      cHeight = canvas.height,
      baseColor = '#e1e1e1',
      coverColor = '#fe4d43',
      PI = Math.PI,
      sR = sR || 1/2 * PI; // 默认圆弧的起始点弧度为π/2

  var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 红圈的终点弧度
  var step = (PI + (PI - sR) * 2)/100; // 一个1%对应的弧度大小
  var text = 0; // 显示的数字

  window.requestAnimationFrame(paint);
  function paint() {
    cxt.clearRect(0, 0, cWidth, cHeight);
    var endRadian =  sR + text * step;
    // 画灰色圆弧
    drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2);
    // 画红色圆弧
    drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2);

    // 画红色圆头
    // 红色圆头其实就是一个圆,关键的是找到其圆心,涉及到三角函数知识,自己画个图一看就明了
    var angle = 2*PI - endRadian; // 转换成逆时针方向的弧度(三角函数中的)
    xPos = Math.cos(angle) * 80 + cWidth/2; // 红色圆 圆心的x坐标
    yPos = -Math.sin(angle) * 80 + cHeight/2; // 红色圆 圆心的y坐标
    drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2);

    // 数字
    cxt.fillStyle = coverColor;
    cxt.font = '40px PT Sans';
    var textWidth = cxt.measureText(text+'%').width;
    cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15);
    text++;

    if (endRadian.toFixed(2) < finalRadian.toFixed(2)) {
      window.requestAnimationFrame(paint);
    }
  }

  function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) {
    cxt.beginPath();
    cxt.lineCap = "round";
    cxt.strokeStyle = color;
    cxt.lineWidth = lineWidth;
    cxt.arc(x, y, r, sRadian, eRadian, false);
    cxt.stroke();
  }
点赞
收藏
评论区
推荐文章
Karen110 Karen110
4年前
一篇文章教会你使用JS+CSS实现一个简单加载进度条的效果
大家好,我是前端进阶者,今天给大家来做个小项目,一起来看看吧一、前言我们经常在网页上,游戏界面加载时会看到加载进度条的效果,我们往往会以为这些加载进度条的效果,很难实现。今天教大家JSCSS结合做简单一个加载进度条的效果。二、项目准备软件:HBuilderX。三、项目实现1\.body创建2个div,外部div添加id"progress"属
Wesley13 Wesley13
4年前
javafx加入特效后无法删除
今天学习Canvas时候发现,如果加入effect效果,那么clearRect方法就删除不了了,不知道这个是不是bug~如果有知道如何解决,希望可以告诉我一下代码如下:        Canvas canvas  new Canvas(WSystem.WIDTH, WSystem.HEIGHT);GraphicsConte
徐小夕 徐小夕
4年前
Canvas入门实战之用javascript面向对象实现一个图形验证码
本文主要介绍用canvas实现图形验证码的一些思路以及如何用javascript面向对象的方式更友好的实现canvas的功能,关于canvas的一些基本使用方法和API我整理了一个思维导图,大家感兴趣的可以参考学习。(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b158fad95
Stella981 Stella981
4年前
Canvas
Canvas04柱状图!输入图片说明(https://static.oschina.net/uploads/img/201707/04223024_wxwr.png"在这里输入图片标题")代码如下:<!DOCTYPEhtml<htmllang"zhCN"<head<metacharset"UTF8"<met
Wesley13 Wesley13
4年前
03.Android崩溃Crash库之ExceptionHandler分析
目录总结00.异常处理几个常用api01.UncaughtExceptionHandler02.Java线程处理异常分析03.Android中线程处理异常分析04.为何使用setDefaultUncaughtExceptionHandler前沿上一篇整体介绍了crash崩溃
Wesley13 Wesley13
4年前
P1162 填涂颜色
题目描述由数字0组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2.例如:6×6的方阵(n6),涂色前和涂色后的方阵如下:00000000111101100
Stella981 Stella981
4年前
Flutter中的绘图(Canvas&CustomPaint)API
本文是Flutter中Canvas和CustomPaintAPI的使用实例。首先看一下我们要实现的效果:!实现效果(https://img2020.cnblogs.com/blog/1595922/202007/1595922202007301524553491226065709.gif)结合动图演示,列出最终目标如下:
Stella981 Stella981
4年前
Android自定义控件之圆形进度条
Android自定义控件之圆形进度条先上图:!填充的(https://static.oschina.net/uploads/img/201703/23151845_nnTV.gif"在这里输入图片标题")!环形的(https://static.oschina.net/uploads/img/201703/23151912_ewAq
Stella981 Stella981
4年前
Chrome扩展程序一键生成网页骨架屏
对于依赖接口渲染的页面,在拿到数据之前页面往往是空白的,为了提示用户当前正在加载中,往往会使用进度条、loading图标或骨架屏的方式。对于前两种方案而言,实现比较简单;本文主要研究骨架屏的应用及实现,并给出一种使用Chrome扩展工具快速生成骨架屏的方案。首先看看效果先放一个动图展示!(https://oscimg.oschina
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Apache Doris 整合 FLINK CDC + Iceberg 构建实时湖仓一体的联邦查询
1概况本文展示如何使用FlinkCDCIcebergDoris构建实时湖仓一体的联邦查询分析,Doris1.1版本提供了Iceberg的支持,本文主要展示Doris和Iceberg怎么使用,大家按照步骤可以一步步完成。完整体验整个搭建操作的过程。2系统
安全客
安全客
Lv1
衣带渐宽终不悔,为伊消得人憔悴。
文章
3
粉丝
0
获赞
0