Canvas实现进度条

什么是canvas

Canvas 中文名叫 “画布”,是 HTML5 新增的一个标签。
Canvas 允许开发者通过 JS在这个标签上绘制各种图案。
Canvas 拥有多种绘制路径、矩形、圆形、字符以及图片的方法。
Canvas 在某些情况下可以 “代替” 图片。
Canvas 可用于动画、游戏、数据可视化、图片编辑器、实时视频处理等领域。

画条直线练练手

1 创建canvas标签,设置宽高。
2 获取画布(canvas)
3 从canvas标签取到绘图工具
4 绘制图形

<!DOCTYPE html>
<html lang="en">
    <!-- <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head> -->
    <body>
        <!-- canvas标签 -->
        <canvas id="canvas" width="200" height="200" style="background:#f0f0f0; margin:50px"></canvas>
    </body>
    <script>
        // 获取元素
        const canvas = document.getElementById("canvas")
        const ctx = canvas.getContext("2d")
        //绘制图形
        ctx.moveTo(100, 100) // 起点坐标 (x, y)
        ctx.lineTo(200, 100) // 终点坐标 (x, y)
        ctx.stroke() // 将起点和终点连接起来
    </script>
</html>

效果如下


企业微信截图_16782641896105.png

实现进度条

需求: 多种状态围成一个圆 动态显示当前在状态在圆中的进度

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <canvas id="canvas" width="400" height="340" style="margin: 100px 200px;background-color: #f0f0f0;">
  </canvas>
</body>
<script>
  // 模拟动态数据
  const operationData = [
    { "label": '未质控', "flowName": "质控", "isLight": true },
    { "label": '待审核', "flowName": "审核", "isLight": false },
    { "label": '待整改', "flowName": "整改", "isLight": false },
    { "label": '已整改', "flowName": "已改", "isLight": false },
    { "label": '已通过', "flowName": "通过", "isLight": false },
    { "label": '完成质控', "flowName": "完成", "isLight": false },
  ];
 // 当前数据状态 (可根据当前进度状态更新原数组)
  const stepsInfo = [
    { "label": '未质控', "flowName": "质控", "isLight": true },
    { "label": '待审核', "flowName": "审核", "isLight": true },
    { "label": '待整改', "flowName": "整改", "isLight": true },
    { "label": '已整改', "flowName": "已改", "isLight": true },
    { "label": '已通过', "flowName": "通过", "isLight": true },
    { "label": '完成质控', "flowName": "完成", "isLight": false },
  ];
  // 获取 canvas元素
  const canvas = document.getElementById("canvas")
  canvas.width = 400;
  canvas.height = 340;
  const ctx = canvas.getContext("2d")

  const length = operationData.length;
  const cirRad = (2 * Math.PI / 4) / (2 * Math.PI / length); 
  // const cirRad = (2 * Math.PI / 4);
  // 把当前画布的正中心作为圆心
  // 有两种方式 (当前方式为1)
  // 1圆心设为(0,0)通过ctx.translate(xr, yr); 设置圆心
  // 2直接把(xr,yr)作为圆心
  const xr = canvas.width / 2;
  const yr = canvas.height / 2;
  const r = 200;
  ctx.translate(xr, yr);  //方式1
  ctx.lineWidth = 8;  //设置圆环的宽度
  ctx.beginPath();
  ctx.strokeStyle = '#BFE7FF'; // 设置画笔的颜色
  // 绘制圆形,坐标0,0,半径200,整圆(0-360度),false表示顺时针
  ctx.arc(0, 0, r - 100, 
  -(cirRad * (2 * Math.PI / length)),
  (2 * Math.PI)/(length-cirRad) , false);
  //(2 * Math.PI / length) * (length - 1- cirRad );  // 结束位置自己设置
  ctx.stroke();

  //绘制完成进度条
  const stepedLength = stepsInfo.filter((item) => item.isLight).length;
  const endAngle =(2 * Math.PI / length) * (stepedLength - 1 - cirRad) // 完成进度弧度值
  ctx.beginPath();
  ctx.arc(0, 0, r - 100, -(cirRad * (2 * Math.PI / length)), endAngle, false);
  ctx.strokeStyle = '#3664D9';
  ctx.stroke();

  // 绘制内心圆
  ctx.lineWidth = 20;
  ctx.beginPath();
  ctx.strokeStyle = '#f5f5f0';// 设置画笔的颜色
  ctx.arc(0, 0, r - 180, 0, 2 * Math.PI, false);
  ctx.closePath();
  ctx.stroke();
  // // 绘制中心圆
  ctx.beginPath();
  ctx.lineWidth = 30;
  ctx.arc(0, 0, r - 160, 0, 2 * Math.PI, false);
  ctx.fillStyle = '#f0f2f5';
  ctx.fill();
  ctx.font = '14px Arial';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'bottom';
  ctx.fillStyle = '#000000';
  // 绘制文字
  const textStr = '信息流';
  const textStrLength = 4;
  lineHeight = 12;
  ctx.fillText(textStr, 0, lineHeight);
  ctx.closePath();
  ctx.stroke();
  stepsInfo.forEach((item, index) => {
      // 弧度
      // 圆点开始坐标 rad, 阶段 - 初始坐标系数
      const rad = (2 * Math.PI / length) * (index-cirRad);
      const stepX = (r - 50) * Math.cos(rad);
      const stepY = (r - 70) * Math.sin(rad);
      ctx.beginPath();
      ctx.fillStyle = '#293750';
      ctx.closePath();
      ctx.fillText(`${item.flowName}`, stepX - 0.5, stepY + 0.5);
      // 实心圆
      const cirx = (r - 100) * Math.cos(rad);
      const ciry = (r - 100) * Math.sin(rad);
      // 绘制边缘灰色半透明小圆点
      ctx.beginPath();
      ctx.fillStyle = '#FFFFFF';
      ctx.arc(cirx, ciry, 10, 0, 2 * Math.PI, false);
      ctx.fill();
      // 绘制蓝色小圆点
      ctx.beginPath();
      ctx.font = '12px Arial';
      ctx.textBaseline = 'middle';
      ctx.fillStyle = item.isLight ? '#2DC76D' : '#BFE7FF';
      ctx.arc(cirx, ciry, 7, 0, 2 * Math.PI, false);
      ctx.fill();
      ctx.fillStyle = '#FFFFFF';
      ctx.fillText(item.isLight ? '✓' : '', cirx, ciry);
    });
</script>
</html>

效果如下

进度.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容