什么是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