JavaScript Canvas 绘制动态时钟详解
本文详细介绍如何使用 HTML5 Canvas 和 JavaScript 绘制一个动态时钟。内容涵盖表盘、刻度及分针、时针、秒针的几何位置计算,重点解析利用正余弦函数确定坐标的方法,并提供完整的实现代码与关键算法解析。
对于 Canvas 语法基础尚不牢固的读者,建议先查阅相关基础教程;具备一定基础的读者可直接继续阅读后续内容。
时钟图形元素构成
构建一个时钟图形,主要需要绘制以下元素:代表时、分、秒的三根指针,作为表盘的圆形轮廓,以及分布在圆周上的 60 个刻度标记(短线或圆点)。
上述需求分析逻辑清晰,无明显遗漏。
接下来细化设计细节:圆周总角度为 360°,均分为 60 个刻度,相邻刻度间隔为 6°。分针与秒针的刻度偏移规则一致,而时针对应 12 个小时刻度,其角度偏移应为前两者的 5 倍,即 30°。此外,考虑到实际钟表指针长度不同,需分别控制三根指针的长度以实现视觉上的逼真感。
基于上述分析,开始具体编码实现。
表盘与指针基础绘制
首先确定圆心坐标并绘制基础圆形表盘:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(X坐标, Y坐标, 半径, 0, 2 * Math.PI, false);
ctx.strokeStyle = 随便填颜色;
ctx.stroke();
ctx.closePath();刻度坐标计算原理
随后添加时间刻度,但面临一个技术难点:虽然已知圆形轮廓及每个刻度对应的 6° 角,但如何准确计算并定位圆周上各刻度的具体坐标?
无需担忧,只要掌握基础的三角函数知识即可解决。通过计算正余弦值,即可获取对应的 X 和 Y 坐标(注意:脚本中正余弦函数用于计算弧度而非直接角度)。具体实现步骤如下:
//计算圆上每个点的坐标
///[a]角度[i]刻度[ox]圆心X坐标[oy]圆心Y坐标[or]圆半径
function angle(a, i, ox, oy, or) {
var hudu = (2 * Math.PI / 360) * a * i;//求出弧度
var x = ox + Math.sin(hudu) * or;//计算出x轴坐标for正弦
var y = oy - Math.cos(hudu) * or;//计算出y轴坐标for余弦
return x + '_' + y;
}依据上述坐标计算方法,即可顺利绘制出刻度:
//打上文字(仅小时)
for (var i = 0; i < 12; i++) {
var textXY = angle(30, i + 1, ox, oy, or - 10);//小时刻度坐标
ctx.fillText(i + 1, textXY.split('_')[0], textXY.split('_')[1]);
ctx.textAlign = 'center';//水平居中
ctx.textBaseline = 'middle';//垂直居中
}
//打上分秒钟刻度
for (var i = 0; i < 60; i++) {
var oXY = angle(6, i + 1, ox, oy, or);//分、秒刻度坐标
ctx.beginPath();
ctx.arc(oXY.split('_')[0], oXY.split('_')[1], (i + 1) % 5 == 0 ? 2 : 1, 0, 2 * Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.closePath();
}指针联动与长度处理
为了提升时钟的逼真度,代码中加入了联动逻辑:秒针的运动影响分针位置,分针的运动影响时针位置(具体逻辑见最终代码)。
针对三根指针长度不同的问题,经过多次尝试,发现最简便的方法是分别绘制三个不同半径的圆形轨迹,因为各指针的角度计算方式保持一致。
最终实现的时钟效果如下:

由于平台不支持直接上传 HTML 文件,此处将完整代码粘贴如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>小马的canvas练手作品-时钟</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="myCanvas" width="1000" height="1000">您的浏览器不支持此标签</canvas>
<script type="text/javascript">
setInterval('drawClock(150, 150, 100, 50, 70, 90,"pink","black","red","green")', 1000);
//画钟表
//[ox]圆心X坐标[oy]圆心Y坐标[or]钟表半径[hr]时针半径[mr]分针半径[sr]秒针半径[oc]钟表外环颜色[hc]时针颜色[mc]分针颜色[sc]秒针颜色
function drawClock(ox, oy, or, hr, mr, sr, oc, hc, mc, sc) {
//时钟底盘
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(ox - or, oy - or, or * 2, or * 2);//清空上一次绘制
ctx.beginPath();
ctx.arc(ox, oy, or, 0, 2 * Math.PI, false);
ctx.strokeStyle = oc;
ctx.stroke();
ctx.closePath();
//获取当前时间
var NowTime = new Date();
var h = NowTime.getHours();
var m = NowTime.getMinutes();
var s = NowTime.getSeconds();
var y = NowTime.getFullYear();
var mo = NowTime.getMonth() + 1;
var d = NowTime.getDate();
ctx.fillText(mo + '月' + d + '日', ox, oy - or / 2, 50);//显示月日
//打上时间刻度
for (var i = 0; i < 12; i++) {
var textXY = angle(30, i + 1, ox, oy, or - 10);//小时刻度坐标
ctx.fillText(i + 1, textXY.split('_')[0], textXY.split('_')[1]);
ctx.textAlign = 'center';//水平居中
ctx.textBaseline = 'middle';//垂直居中
}
//打上分钟刻度
for (var i = 0; i < 60; i++) {
var oXY = angle(6, i + 1, ox, oy, or);//分、秒刻度坐标
ctx.beginPath();
ctx.arc(oXY.split('_')[0], oXY.split('_')[1], (i + 1) % 5 == 0 ? 2 : 1, 0, 2 * Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.closePath();
}
h = h + m / 60;//分钟影响时针偏移
var hoursXY = angle(30, h > 12 ? h - 12 : h, ox, oy, hr);//时针终点XY坐标
drawLine(ctx, hc, ox, oy, hoursXY.split('_')[0], hoursXY.split('_')[1]);
m = m + s / 60;//秒钟影响分针偏移
var minuteXY = angle(6, m, ox, oy, mr);//分针终点XY坐标
drawLine(ctx, mc, ox, oy, minuteXY.split('_')[0], minuteXY.split('_')[1]);
var secondXY = angle(6, s, ox, oy, sr);//秒针终点XY坐标
drawLine(ctx, sc, ox, oy, secondXY.split('_')[0], secondXY.split('_')[1]);
}
//计算圆上每个点的坐标
///[a]角度[i]刻度[ox]圆心X坐标[oy]圆心Y坐标[or]圆半径
function angle(a, i, ox, oy, or) {
var hudu = (2 * Math.PI / 360) * a * i;//求出弧度
var x = ox + Math.sin(hudu) * or;//计算出x轴坐标for正弦
var y = oy - Math.cos(hudu) * or;//计算出y轴坐标for余弦
return x + '_' + y;
}
//画线方法
///[ob]绘画对象[ox]圆心X坐标[oy]圆心Y坐标[px]目标X坐标[py]目标Y坐标
function drawLine(ob, color, ox, oy, px, py) {
ob.beginPath();
ob.strokeStyle = color;
ob.moveTo(ox, oy);
ob.lineTo(px, py);
ob.stroke();
ob.closePath();
}<br data-filtered="filtered">
</script>
</body>
</html>至此,关于在 Canvas 元素内使用 JavaScript 绘制时钟的文章介绍完毕。希望本文内容能对读者有所帮助,欢迎继续支持本站。
sigma.js 怎么实现节点点击、拖拽与悬停提示交互
2026-11-05 15:03:27
Matter.js 与 PixiJS/Three.js 集成:分离物理计算与渲染
2026-11-05 13:43:48
主流JS弹幕库选型指南:Danmaku.js等库的功能与体积对比
2026-11-05 09:28:19
JavaScript点击事件监听与交互效果实例
2026-11-05 09:10:19
自定义JS颜色选择器UI样式与交互细节
2026-11-05 09:09:06
