背景介绍
由于产品和UI的整活,要求仪表盘要精确还原而市面上没找到现成的,所以用我初浅的canvas技术绘制了一下仪表盘(PS:讨厌造轮子,但是没合适的轮子,留一份轮子在这,万一后面还有这种需求,改改代码自己工作上还能用)
代码实现
/**
* 绘制仪表盘的函数
* params: changeType - 仪表盘数值变化类型,对应相应的labels
*/
function drawGauge(changeType = 0) {
// 获取画布元素和绘图上下文
const canvas = document.getElementById("gauge"); //画布为宽400,高200的canvas元素,要改宽高需要保证宽高比2:1,因为是半圆
const ctx = canvas.getContext("2d");
// 计算仪表盘的中心坐标和半径
const centerX = canvas.width / 2; // 中心X坐标
const centerY = canvas.height; // 中心Y坐标
const radius = 150; // 仪表盘半径(没提出去,修改时需要比高小)
// 定义仪表盘的起始和结束弧度
const startAngle = Math.PI; // 起始弧度 (180度)
const endAngle = 0; // 结束弧度 (0度)
// 计算各段之间的角度步长
const step = (startAngle - endAngle) / 5; // 将仪表盘分成5段
// 绘制背景弧线
ctx.beginPath(); // 开始新路径
ctx.arc(
centerX, // 圆心X坐标
centerY, // 圆心Y坐标
radius - 30, // 圆的半径 (稍微小于总半径)
startAngle, // 起始弧度
startAngle + step * (changeType + 0.5) // 结束弧度
);
ctx.lineWidth = 3; // 设置线宽
ctx.strokeStyle = "#e0e0e0"; // 设置线条颜色 (浅灰色)
ctx.stroke(); // 绘制弧线
// 绘制各段
const labels = ["无", "较小", "一般", "较大", "很大"]; // 各段的标签
// 循环绘制每个段落
for (let i = 0; i < labels.length; i++) {
ctx.beginPath(); // 开始新路径
ctx.arc(
centerX, // 圆心X坐标
centerY, // 圆心Y坐标
radius, // 圆的半径 (完整半径)
startAngle + step * i, // 各段的开始角度
startAngle + step * (i + 1) - 0.01 // 各段的结束角度 (稍微减去0.01以保证有分割线)
);
ctx.lineWidth = 50; // 设置线宽
ctx.strokeStyle = i === changeType ? "#007bff" : "#e0e0e0"; // 当前段的颜色设为蓝色,其他为灰色
ctx.stroke(); // 绘制弧线
ctx.save(); // 保存当前状态
// 绘制标签
ctx.fillStyle = i === changeType ? "#fff" : "#000"; // 当前段标签颜色为白色,其他为黑色
ctx.font = "14px Arial"; // 设置字体大小和类型
const labelX =
centerX + Math.cos(startAngle + step * (i + 0.5)) * radius; // 标签X坐标
const labelY =
centerY + Math.sin(startAngle + step * (i + 0.5)) * radius + 5; // 标签Y坐标 (+5是为了稍微偏移)
ctx.translate(labelX, labelY); // 移动画布原点到标签中心
ctx.rotate(-Math.PI / 2 + step * (i + 0.5)); // 旋转画布至合适角度
ctx.fillText(labels[i], -ctx.measureText(labels[i]).width / 2, 0); // 绘制标签文字(居中绘制)
ctx.restore(); // 恢复到之前保存的状态
}
// 绘制指针
const pointerAngle = startAngle + step * (changeType + 0.5); // 计算指针的角度
const pointerLength = radius - 20; // 指针的长度
ctx.beginPath(); // 开始新路径
ctx.moveTo(centerX, centerY); // 移动到中心点
ctx.lineTo(
centerX + Math.cos(pointerAngle) * pointerLength, // 指针终点X坐标
centerY + Math.sin(pointerAngle) * pointerLength // 指针终点Y坐标
);
ctx.lineWidth = 1; // 指针线宽
ctx.strokeStyle = "#ff0000"; // 指针颜色 (红色)
ctx.stroke(); // 绘制指针
// 用白色线盖住超长的指针
const _pointerLength = radius - 30; // 盖住的指针长度
ctx.beginPath(); // 开始新路径
ctx.moveTo(centerX, centerY); // 移动到中心点
ctx.lineTo(
centerX + Math.cos(pointerAngle) * _pointerLength, // 盖住的指针终点X坐标
centerY + Math.sin(pointerAngle) * _pointerLength // 盖住的指针终点Y坐标
);
ctx.lineWidth = 10; // 线宽
ctx.strokeStyle = "#fff"; // 线条颜色 (白色)
ctx.stroke(); // 绘制盖住的指针
// 绘制指针的圆点
ctx.beginPath(); // 开始新路径
ctx.arc(
centerX + Math.cos(pointerAngle) * _pointerLength, // 圆点X坐标
centerY + Math.sin(pointerAngle) * _pointerLength, // 圆点Y坐标
2, // 圆点半径
0, // 起始弧度
2 * Math.PI // 结束弧度 (完整圆)
);
ctx.fillStyle = "#ff0000"; // 圆点颜色 (红色)
ctx.fill(); // 填充圆点
}
效果如下:
方法记录
| 方法名 | 用法 | 文档链接 |
|---|---|---|
| beginPath | 直接调用即可,为canvas绘制新路径 | developer.mozilla.org/zh-CN/docs/… |
| arc | 绘制一个圆弧(圆心X轴位置, 圆心y轴位置, 半径, 开始弧度, 结束弧度, 是否为顺时针方向绘制) | developer.mozilla.org/zh-CN/docs/… |
| stroke | 绘制边框图像,边框颜色使用strokeStyle设置边框宽度使用lineWidth设置,可以理解为border | developer.mozilla.org/zh-CN/docs/… |
| fill | 绘制填充图形,颜色使用fillStyle设置 | developer.mozilla.org/zh-CN/docs/… |
| save | 能保存当次绘制路径的图像,即当次beginPath下面绘制的东西会保存一份 | developer.mozilla.org/zh-CN/docs/… |
| restore | 能恢复当次保存绘制路径的图 | developer.mozilla.org/zh-CN/docs/… |
| translate | 平移画布(画布X轴位置, 画布y轴位置) | developer.mozilla.org/zh-CN/docs/… |
| rotate | 旋转画布(画布X轴位置, 画布y轴位置) | developer.mozilla.org/zh-CN/docs/… |
| fillText | 绘制文本(文本内容,文本X轴位置,文本Y轴位置) | developer.mozilla.org/zh-CN/docs/… |
| moveTo | 绘制线(起始点X轴位置,起始点Y轴位置) | developer.mozilla.org/zh-CN/docs/… |
| lineTo | 绘制线(画布X轴位置, 画布y轴位置),不直接渲染canvas需要使用stroke()或者fill() | developer.mozilla.org/zh-CN/docs/… |