HTML怎么做canvas时钟_HTML canvas时钟表盘绘制教程【方法】
Canvas时钟核心是坐标系定位、角度计算和重绘优化
Canvas时钟核心是坐标系定位、角度计算和重绘优化;需DOM加载后获取ctx、平移原点至中心、配对文本对齐、按实际空间取半径、理解指针角度偏移原理、用requestAnimationFrame递归调用并sa ve/restore状态。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
说到底,Canvas时钟的实现,关键不在于“画个圆”,而在于“坐标系怎么摆、角度怎么算、重绘怎么不糊”——这三者但凡错一个,指针就飘、数字就歪、动画就卡。
canvas.getContext('2d') 必须在 DOM 加载后调用
一个常见的坑是,脚本如果放在里直接执行,document.getElementById('clock')很可能返回null。这样一来,后续所有对ctx的调用都会静默失败,控制台甚至不会报错,排查起来相当头疼。
- 确保JS脚本放在
标签之前,或者用DOMContentLoaded事件包裹起来。 - 检查
canvas元素是否真的设置了id="clock",以及宽高是否明确指定(默认是300×150,不设的话很容易被CSS压扁)。 - 多加一句
console.log(ctx)来确认其不是null,这比盲目猜测要高效得多。
表盘绘制前必须 translate 到中心,否则刻度全偏
Canvas的默认坐标系原点在左上角。如果不做平移,就得硬着头皮计算每个点的centerX + cos(angle) * r,代码冗长且极易出错。正确做法是使用ctx.translate(centerX, centerY),将原点平移到画布中心。之后,所有坐标计算都以(0, 0)为圆心,弧度方向直接对应旋转方向,逻辑瞬间清晰。
- 平移之后,
ctx.arc(0, 0, radius, 0, Math.PI * 2)才能真正画出一个以中心为圆点的正圆。 - 标注数字时,
ctx.textAlign = 'center'和ctx.textBaseline = 'middle'必须成对使用,否则12点位置的“12”会紧紧贴着边缘,而不是居中显示。 - 别忘了,平移后计算半径
radius要基于实际可用空间。推荐使用Math.min(canvas.width, canvas.height) / 2 * 0.9,留出一点边距,防止内容被意外裁切。
秒针/分针/时针的角度公式不能硬背,得理解偏移来源
这里容易混淆。秒针的角度并非只和seconds有关,因为Canvas的0弧度起始方向是向右(3点钟方向),而我们的时钟起始方向是向上(12点钟方向),所以需要减去Math.PI / 2来校正。时针的计算更精细,它不仅取决于小时数,还要叠加分钟和秒带来的微小偏移,否则在1:59时,时针还会固执地指向1,而不是缓缓移向2。
立即学习“前端免费学习笔记(深入)”;
- 秒针弧度:
(seconds / 60) * Math.PI * 2 - Math.PI / 2 - 分针弧度:
((minutes + seconds / 60) / 60) * Math.PI * 2 - Math.PI / 2 - 时针弧度:
((hours % 12 + minutes / 60 + seconds / 3600) / 12) * Math.PI * 2 - Math.PI / 2 - 每次绘制指针前,务必调用
ctx.sa ve()保存画布状态,画完后立即ctx.restore()恢复。否则,旋转状态会污染下一根指针的绘制。
requestAnimationFrame 比 setInterval 更稳,但必须递归调用
使用setInterval(drawClock, 1000)来控制重绘,会导致秒针跳动、动画掉帧。尤其是在页面切换到后台再切回来时,时间差可能累积到数秒。而requestAnimationFrame与屏幕刷新率同步,并且会自动在页面不可见时暂停,性能更优。
- 正确的写法必须是递归调用:
function drawClock() { /* 绘制逻辑 */ requestAnimationFrame(drawClock); } - 注意,静态的表盘(刻度、数字)只需要在初始化时绘制一次即可,不要在每次
drawClock里都重复调用drawClockFace()。 - 清除画布时,使用
ctx.clearRect(0, 0, canvas.width, canvas.height),参数一个都不能漏,否则会清不干净,导致指针产生拖影。
实际上,最难调试的往往是高清屏(window.devicePixelRatio > 1)下的模糊问题。Canvas的像素没有缩放,但CSS渲染时放大了,导致整个表盘边缘出现毛边。这需要单独处理Canvas元素的width/height属性与CSS样式尺寸的匹配关系。虽然这不属于基础的绘制逻辑,但在项目上线前,大概率是需要补上这一课的。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
Less如何提升CSS维护性_使用参数化Mixin实现灵活组件
Less参数化Mixin:如何写出既灵活又可控的样式代码? Less参数化Mixin怎么写才不重复造轮子 开门见山,参数化Mixin的核心目标不是炫技,而是解决一个实际问题:把那些“可能会变”的样式值抽离出来。这样一来,样式规则只需定义一次,修改时就能全局生效,维护效率自然就上去了。关键在于,你得准
Vue 中的 Patch 过程是怎么工作的?从 VNode 到真实 DOM 的转化全指南
Vue 中的 Patch 过程是怎么工作的?从 VNode 到真实 DOM 的转化全指南 Patch 的核心目标:高效更新 DOM 简单来说,Vue 的 Patch 过程干的就是一件“聪明事”:它拿着新旧两份虚拟节点(VNode)清单,只去更新真实 DOM 里真正变了的那部分,而不是不管三七二十一,
CSS如何实现移动端加载占位骨架屏_利用CSS渐变色与动画效果
CSS如何实现移动端加载占位骨架屏:利用渐变色与动画效果 先明确一个核心概念:一个真正好用的骨架屏,本质上不是图片,而是用CSS背景渐变“画”出来的容器轮廓。关键在于,如何让background-image精准覆盖真实内容区域,同时巧妙地利用透明间隙来模拟文字或头像的留白。这听起来简单,但实际操作时
CSS如何实现侧边栏推拽切换_利用CSS动画平滑过渡布局
侧边栏推拽用 transform: translateX() 更流畅,避免 left margin-left 触发重排;初始隐藏用 translateX(-100%),配合 ease-out 或自定义 cubic-bezier 过渡更自然;移动端需谨慎 preventDefault() 并启用 -w
Ionic 7 中在 Tab 内实现页面内导航的完整教程
Ionic 7 中在 Tab 内实现页面内导航的完整教程 本文详解如何在 Ionic 7(Vanilla JS)中为单个 Tab 配置独立的嵌套路由系统,解决 ion-router 在 ion-tab 内无法正常跳转的问题,并提供可运行的结构化实现方案。 如果你正在用 Ionic 7 的纯 Ja v
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

