You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Canvas中动画圆无法完美填充的问题排查与原因问询

解决Canvas圆形收缩动画无法完全填充的问题

问题原因分析

  1. 浮点数精度误差:JavaScript浮点数采用二进制存储,每次对startPoint和endPoint执行±Math.PI/speed操作时,无法精确命中目标值0.75*Math.PI和2.75*Math.PI,导致循环提前终止,动画未完成最后一步填充。
  2. 循环判断逻辑缺陷:原条件startPoint >= 0.75*Math.PI && endPoint <= 2.75*Math.PI只要其中一个值不满足就停止动画,精度误差会让其中一个值提前越过阈值,跳过完整填充的绘制。
  3. 未清除画布:每次绘制前未清除画布,会残留之前的绘制痕迹,影响最终视觉效果。

修复方案

核心修改点

  • 在动画循环的最后一帧,强制将startPoint和endPoint设置为精确目标值,确保绘制完整圆形。
  • 每次绘制前清除画布,避免残留痕迹。
  • 调整循环判断逻辑,允许最后一步强制完成绘制。

修改后的完整代码

HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <title>Document</title>
</head>
<body>
  <canvas id="circle" height="450px" width="450px"></canvas>
  <script src="script.js"></script>
</body>
</html>

CSS

#circle {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

JavaScript

const canvas = document.getElementById("circle");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.lineWidth = 7;

const speed = 40;
const targetStart = 0.75 * Math.PI;
const targetEnd = 2.75 * Math.PI;

const drawCircle = (
  x,
  y,
  r,
  startPoint = 0,
  endPoint = 2 * Math.PI,
  fill = true
) => {
  ctx.beginPath();
  ctx.arc(x, y, r, startPoint, endPoint);
  if (fill) ctx.fill();
  ctx.stroke();
};

let endPoint = 1.75 * Math.PI;
let startPoint = 1.75 * Math.PI;

function animateCircle() {
  // 清除画布,避免残留绘制痕迹
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  let shouldContinue = true;
  // 用极小阈值判断是否接近目标值,最后一帧强制设置为精确值
  if (startPoint <= targetStart + 0.001 && endPoint >= targetEnd - 0.001) {
    startPoint = targetStart;
    endPoint = targetEnd;
    shouldContinue = false;
  }
  
  drawCircle(280, 210, 20, startPoint, endPoint);
  
  if (shouldContinue) {
    endPoint += Math.PI / speed;
    startPoint -= Math.PI / speed;
    requestAnimationFrame(animateCircle);
  }
}
requestAnimationFrame(animateCircle);

额外说明

  • 引入0.001的误差阈值,避免因浮点数精度问题错过最后一帧的完整绘制。
  • ctx.clearRect操作确保每次绘制都是干净状态,消除半圆弧残留的视觉干扰。

内容的提问来源于stack exchange,提问作者RedApple

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:50:03