先帖代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>环形进度条</title>
</head>

<body>
  <div style="width:300px; height:300px; margin:20px auto">
    <canvas id="cycCanvas" width="300" height="300">
      <p>您的浏览器不支持canvas</p>
    </canvas>
  </div>
  <div style="width:300px; height:300px; margin:20px auto">
    <canvas id="cycCanvas1" width="300" height="300">
      <p>您的浏览器不支持canvas</p>
    </canvas>
  </div>
</body>
<script type="text/javascript">

  /**
   * 画圆
   * @param {number} cx x坐标
   * @param {number} cy y坐标
   * @param {number} r  半径
   * @param {number} lineWidth  线宽度
   * @return null
   */
  function circle(ctx, cx, cy, r, lineWidth) {
    if (!ctx) return
    ctx.beginPath();
    ctx.lineWidth = lineWidth;
    ctx.strokeStyle = '#eee';
    ctx.arc(cx, cy, r, 0, (Math.PI * 2), true);
    ctx.stroke();
  }

  /**
    * 画弧线
    * @param {number} cx x坐标
    * @param {number} cy y坐标
    * @param {number} r  半径
    * @param {number} lineWidth  线宽度
    * @param {number} startAngle 开始角度 按照360算
    * @param {number} endAngle 结束角度 按照360算
    * @return null
    */
  function sector(ctx, cx, cy, r, lineWidth, startAngle = 0, endAngle = 360) {
    if (!ctx) return
    ctx.beginPath();
    ctx.lineWidth = lineWidth;

    // 渐变色
    let linGrad = ctx.createLinearGradient(
      cx - r - lineWidth, cy, cx + r + lineWidth, cy
    );
    linGrad.addColorStop(0.0, '#ffcc99');
    linGrad.addColorStop(0.5, '#99ff66');
    linGrad.addColorStop(1.0, '#66ccff');
    ctx.strokeStyle = linGrad;

    // 单色
    // ctx.strokeStyle = 'red';

    //圆弧两端的样式
    ctx.lineCap = 'round';

    //圆弧
    const _startAng = Math.PI * ((startAngle - 90) / 180)
    const _endAng = Math.PI * ((endAngle - 90) / 180)
    ctx.arc(
      cx, cy, r,
      _startAng,
      _endAng,
      false
    );
    ctx.stroke();
  }

  /**
    * 刷新进度条
    * @param {number} cx x坐标
    * @param {number} cy y坐标
    * @param {number} r  半径
    * @param {number} lineWidth  线宽度
    * @param {number} process 完成进度
    * @return null
    */
  function freshProgress(ctx, cx, cy, r, lineWidth, process) {

    if (!ctx) return

    //清除canvas内容
    ctx.clearRect(0, 0, cx * 2, cy * 2);

    //中间的字
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillStyle = '#999';
    ctx.fillText(parseFloat(process).toFixed(0) + '%', cx, cy);

    //圆形
    circle(ctx, cx, cy, r, lineWidth);

    //圆弧
    sector(ctx, cx, cy, r, lineWidth, 0, process * 3.6);
  }

  /**
    * 绘制进度条 有动画的
    * @param {string} id canvas 组件的id
    * @param {number} progress 进度 最大100 是一圈
    * @param {number} time 执行时间 单位秒 p.s. 好像算的有点不对 大概
    */
  function drawProgress(id, progress, time = 1) {
    const canvas = document.getElementById(id), // canvas进度条
      circleX = canvas.width / 2,  //中心x坐标
      circleY = canvas.height / 2,  //中心y坐标
      radius = 100, //圆环半径
      lineWidth = 20, //圆形线条的宽度
      delay = time / progress * 1000; // 延迟时间

    const ctx = canvas.getContext("2d");
    let nowProgress = 0;  //显示进度
    let circleLoading = window.setInterval(function () {
      if (nowProgress > progress) {
        clearInterval(circleLoading);
      } else {
        freshProgress(ctx, circleX, circleY, radius, lineWidth, nowProgress);
        nowProgress += 1.0;
      }

    }, delay);

  }
  /**
    * 刷新百分比
    * @param {number} cx x坐标
    * @param {number} cy y坐标
    * @param {number} r  半径
    * @param {number} lineWidth  线宽度
    * @param {array} data 数据的 number 数组
    * @param {number} process 完成进度
    * @return null
    */
  function freshPrecentage(ctx, cx, cy, r, lineWidth, data, process) {
    if (!ctx) return
    //清除canvas内容
    ctx.clearRect(0, 0, cx * 2, cy * 2);
    if (data.length) {
      const sum = data.reduce((prev, next) => prev + next)
      const space = data.length > 1 ? (data.length) * 15 : 0;
      let _startAng = 0
      const resmap = data.map(element => {
        const item = { startAngle: _startAng, endAngle: _startAng + element / sum * (360 - space), element, sum }
        if (process >= _startAng) {
          const endArg = Math.min(item.endAngle, process)
          sector(ctx, cx, cy, r, lineWidth, item.startAngle, endArg);
        }
        _startAng = item.endAngle + 15
        return item
      });
    }
  }

  /**
    * 绘制百分比 有动画的
    * @param {string} id canvas 组件的id
    * @param {array} data 数据的 number 数组
    * @param {number} time 执行时间 单位秒 p.s. 好像算的有点不对 大概
    */
  function drawPercentage(id, data = [], time = 1) {
    const canvas = document.getElementById(id), // canvas进度条
      circleX = canvas.width / 2,  //中心x坐标
      circleY = canvas.height / 2,  //中心y坐标
      radius = 100, //圆环半径
      lineWidth = 20, //圆形线条的宽度
      delay = time * 10;
    const ctx = canvas.getContext("2d");
    console.log(delay)
    let nowProgress = 0;  //显示进度
    let circleLoading = window.setInterval(function () {
      if (nowProgress > 100) {
        clearInterval(circleLoading);
      } else {
        freshPrecentage(ctx, circleX, circleY, radius, lineWidth, data, nowProgress * 3.6)
        nowProgress += 1.0;
      }

    }, delay);

  }

  //调用
  drawProgress('cycCanvas', 80);
  drawPercentage('cycCanvas1', [1, 2, 3, 4]);

</script>

</html>

效果展示
https://momokara-1251707696.c...


momokara
9 声望0 粉丝

屌丝小厂咸鱼程序狗