先帖代码

<!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...