怎样用JavaScript创建仪表盘
仪表盘是数据可视化场景中非常常见的组件,常用于展示进度、占比、评分等数值类信息,直观的视觉效果能让用户快速理解数据含义。使用原生JavaScript结合Canvas画布,就能实现一个基础的可交互仪表盘,不需要依赖第三方图表库,灵活度更高。
实现思路梳理
要实现一个仪表盘,核心逻辑可以分为以下几个步骤:
- 创建Canvas画布作为绘制容器,设置好画布尺寸和样式
- 绘制仪表盘的外层圆弧、刻度线、刻度文字等静态元素
- 根据传入的数值,绘制对应比例的彩色进度圆弧
- 添加指针元素,让指针指向当前数值对应的角度位置
- 提供更新数值的接口,支持动态修改仪表盘展示的数据
完整代码实现
下面是完整的原生JavaScript仪表盘实现代码,代码中包含详细注释说明每一步的作用:
// 仪表盘构造函数,接收容器id和配置参数
function Dashboard(containerId, options = {}) {
// 获取容器元素
this.container = document.getElementById(containerId);
if (!this.container) {
throw new Error('未找到对应的容器元素');
}
// 默认配置
this.config = {
width: options.width || 300, // 画布宽度
height: options.height || 200, // 画布高度
minValue: options.minValue || 0, // 最小值
maxValue: options.maxValue || 100, // 最大值
currentValue: options.currentValue || 0, // 当前值
startAngle: options.startAngle || 135, // 起始角度(度)
endAngle: options.endAngle || 405, // 结束角度(度)
bgColor: options.bgColor || '#f5f5f5', // 背景色
progressColor: options.progressColor || '#36a2eb', // 进度色
textColor: options.textColor || '#333', // 文字颜色
lineWidth: options.lineWidth || 20, // 圆弧线宽
};
// 初始化画布
this.initCanvas();
// 绘制初始仪表盘
this.draw();
}
// 初始化Canvas画布
Dashboard.prototype.initCanvas = function() {
// 创建canvas元素
this.canvas = document.createElement('canvas');
this.canvas.width = this.config.width;
this.canvas.height = this.config.height;
this.canvas.style.display = 'block';
this.canvas.style.margin = '0 auto';
// 清空容器并添加画布
this.container.innerHTML = '';
this.container.appendChild(this.canvas);
// 获取绘图上下文
this.ctx = this.canvas.getContext('2d');
};
// 角度转弧度
Dashboard.prototype.angleToRadian = function(angle) {
return (angle * Math.PI) / 180;
};
// 绘制仪表盘静态背景
Dashboard.prototype.drawBg = function() {
const ctx = this.ctx;
const centerX = this.config.width / 2;
const centerY = this.config.height * 0.6;
const radius = Math.min(this.config.width, this.config.height) * 0.4;
const startAngle = this.angleToRadian(this.config.startAngle);
const endAngle = this.angleToRadian(this.config.endAngle);
// 绘制背景圆弧
ctx.beginPath();
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.lineWidth = this.config.lineWidth;
ctx.strokeStyle = this.config.bgColor;
ctx.lineCap = 'round';
ctx.stroke();
// 绘制刻度线和刻度文字
const totalAngle = this.config.endAngle - this.config.startAngle;
const step = totalAngle / 10; // 10个刻度
for (let i = 0; i <= 10; i++) {
const angle = this.config.startAngle + step * i;
const radian = this.angleToRadian(angle);
// 计算刻度线起点和终点
const innerX = centerX + (radius - this.config.lineWidth / 2 - 5) * Math.cos(radian);
const innerY = centerY + (radius - this.config.lineWidth / 2 - 5) * Math.sin(radian);
const outerX = centerX + (radius - this.config.lineWidth / 2 + 10) * Math.cos(radian);
const outerY = centerY + (radius - this.config.lineWidth / 2 + 10) * Math.sin(radian);
// 绘制刻度线
ctx.beginPath();
ctx.moveTo(innerX, innerY);
ctx.lineTo(outerX, outerY);
ctx.lineWidth = 2;
ctx.strokeStyle = this.config.textColor;
ctx.stroke();
// 绘制刻度文字
const textX = centerX + (radius - this.config.lineWidth / 2 - 25) * Math.cos(radian);
const textY = centerY + (radius - this.config.lineWidth / 2 - 25) * Math.sin(radian);
ctx.font = '12px Arial';
ctx.fillStyle = this.config.textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const textValue = this.config.minValue + (this.config.maxValue - this.config.minValue) * (i / 10);
ctx.fillText(Math.round(textValue), textX, textY);
}
};
// 绘制进度圆弧
Dashboard.prototype.drawProgress = function() {
const ctx = this.ctx;
const centerX = this.config.width / 2;
const centerY = this.config.height * 0.6;
const radius = Math.min(this.config.width, this.config.height) * 0.4;
const startAngle = this.angleToRadian(this.config.startAngle);
// 计算当前值对应的结束角度
const valuePercent = (this.config.currentValue - this.config.minValue) / (this.config.maxValue - this.config.minValue);
const clampedPercent = Math.max(0, Math.min(1, valuePercent)); // 限制比例在0-1之间
const progressAngle = this.config.startAngle + (this.config.endAngle - this.config.startAngle) * clampedPercent;
const endAngle = this.angleToRadian(progressAngle);
// 绘制进度圆弧
ctx.beginPath();
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.lineWidth = this.config.lineWidth;
ctx.strokeStyle = this.config.progressColor;
ctx.lineCap = 'round';
ctx.stroke();
};
// 绘制指针和当前数值
Dashboard.prototype.drawPointer = function() {
const ctx = this.ctx;
const centerX = this.config.width / 2;
const centerY = this.config.height * 0.6;
const radius = Math.min(this.config.width, this.config.height) * 0.4;
// 计算指针角度
const valuePercent = (this.config.currentValue - this.config.minValue) / (this.config.maxValue - this.config.minValue);
const clampedPercent = Math.max(0, Math.min(1, valuePercent));
const pointerAngle = this.config.startAngle + (this.config.endAngle - this.config.startAngle) * clampedPercent;
const radian = this.angleToRadian(pointerAngle);
// 绘制指针
const pointerLength = radius - this.config.lineWidth / 2 - 15;
const pointerX = centerX + pointerLength * Math.cos(radian);
const pointerY = centerY + pointerLength * Math.sin(radian);
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(pointerX, pointerY);
ctx.lineWidth = 3;
ctx.strokeStyle = '#ff6b6b';
ctx.lineCap = 'round';
ctx.stroke();
// 绘制指针中心点
ctx.beginPath();
ctx.arc(centerX, centerY, 5, 0, Math.PI * 2);
ctx.fillStyle = '#ff6b6b';
ctx.fill();
// 绘制当前数值
ctx.font = '24px Arial';
ctx.fillStyle = this.config.textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.config.currentValue, centerX, centerY - 30);
};
// 绘制整个仪表盘
Dashboard.prototype.draw = function() {
// 清空画布
this.ctx.clearRect(0, 0, this.config.width, this.config.height);
// 依次绘制各元素
this.drawBg();
this.drawProgress();
this.drawPointer();
};
// 更新仪表盘数值的方法
Dashboard.prototype.updateValue = function(newValue) {
this.config.currentValue = newValue;
this.draw();
};
// 使用示例
// 页面加载完成后初始化仪表盘
window.onload = function() {
// 创建仪表盘实例
const myDashboard = new Dashboard('dashboard-container', {
width: 400,
height: 250,
minValue: 0,
maxValue: 100,
currentValue: 30,
progressColor: '#4bc0c0'
});
// 模拟动态更新数值,每2秒增加10,到100后重置为0
setInterval(function() {
let newValue = myDashboard.config.currentValue + 10;
if (newValue > 100) {
newValue = 0;
}
myDashboard.updateValue(newValue);
}, 2000);
};上面的代码实现了一个完整的仪表盘类,使用时只需要在HTML中准备一个id为dashboard-container的容器即可,不需要额外引入其他资源。代码中通过构造函数接收配置参数,支持自定义尺寸、数值范围、颜色等属性,还提供了updateValue方法用于动态更新展示的数值。
使用说明
如果要使用这个仪表盘,只需要在HTML页面中添加如下容器代码,然后引入上面的JavaScript代码即可:
<div id="dashboard-container" style="width: 400px; height: 250px;"></div>
如果需要调整仪表盘的样式或者数值范围,可以在初始化Dashboard实例时传入对应的配置参数,比如修改maxValue为200就能将最大值调整为200,修改progressColor就能更换进度条的颜色。
扩展方向
这个基础仪表盘还可以根据需求做很多扩展,比如添加数值变化的动画过渡效果、支持点击事件修改数值、增加多个颜色区间的进度展示(比如低于30%显示红色,30%-70%显示黄色,70%以上显示绿色)、适配移动端触摸交互等,核心的绘制逻辑都是通用的,只需要在现有基础上补充对应的功能代码即可。
JavaScript仪表盘Canvas绘制数据可视化动态进度条前端组件 本作品最后修改时间:2026-05-23 23:06:08