HTML/Javascript Canvas时钟数字轨道动画运行1秒后卡顿问题
Canvas 时钟数字旋转卡顿问题的解决方案
你的代码出现卡顿的核心原因是Canvas变换状态管理不当,以及重复的变换操作导致计算负载持续累积。手动通过反向translate/rotate恢复状态的方式,会因为浮点数精度丢失让变换矩阵逐渐偏移,加上循环内多次变换操作,最终导致绘制性能越来越差。
修复方案
使用Canvas内置的save()和restore()方法管理状态,同时简化数字绘制的位置计算逻辑,避免不必要的变换操作:
修复后的完整代码
<canvas id="clock" width="400px" height="400px"></canvas>
const clk = document.getElementById("clock").getContext("2d"); clk.font = "20px Arial"; clk.strokeStyle = "black"; clk.textAlign = "center"; clk.textBaseline = "middle"; // 让文字垂直居中,提升视觉效果 let rotationCounter = 0; function drawNumbers() { // 清空画布 clk.clearRect(0, 0, 400, 400); // 绘制时钟底色 clk.fillStyle = "lightgrey"; clk.beginPath(); // 必须调用beginPath,避免之前的路径累积 clk.arc(200, 200, 180, 0, Math.PI * 2); clk.fill(); clk.fillStyle = "black"; // 绘制12个数字 for (let i = 1; i < 13; i++) { // 计算当前数字的旋转角度(包含整体偏移) const angle = ((i * 30) + rotationCounter) * Math.PI / 180; // 通过三角函数直接计算数字的位置 const x = 200 + Math.cos(angle) * 150; const y = 200 + Math.sin(angle) * 150; // 保存当前状态,避免旋转影响其他绘制 clk.save(); // 移动到数字位置,旋转文字使其始终正向 clk.translate(x, y); clk.rotate(angle + Math.PI / 2); // 修正文字朝向,让数字始终正立 clk.fillText(i.toString(), 0, 0); // 恢复状态 clk.restore(); } rotationCounter += 1; if (rotationCounter < 720) { window.requestAnimationFrame(drawNumbers); } } window.requestAnimationFrame(drawNumbers);
关键改动说明
- 使用
save()/restore()管理状态:每次绘制单个数字时保存状态,绘制完成后恢复,彻底避免手动反向变换的精度问题,代码逻辑也更清晰。 - 用三角函数计算位置:直接通过
cos/sin计算数字的坐标,替代循环内多次rotate/translate操作,减少GPU的变换计算负载。 - 添加
beginPath():绘制时钟底色前调用beginPath(),避免之前的绘制路径累积导致重复填充,提升性能。 - 设置
textBaseline:让文字垂直居中,优化视觉效果。
为什么原代码会卡顿
- 手动反向变换会因为浮点数精度丢失,导致Canvas的变换矩阵逐渐偏移,每次绘制都要基于偏移后的状态计算,累积后计算量越来越大。
- 循环内多次
rotate/translate操作,每次都会修改变换矩阵,增加了GPU的计算负担,随着帧数增加,卡顿会持续加剧。
内容的提问来源于stack exchange,提问作者Piano Guy
相关产品推荐
相关产品推荐

