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

Canvas行星无法沿正圆公转问题求助及代码排查

问题原因

  1. 上下文变换累积错误:当前代码中,绘制完第一颗行星后未重置Canvas上下文状态,后续行星的旋转和平移操作基于前一颗行星的位置执行,导致每颗行星围绕前一颗行星而非太阳公转,轨迹偏离正圆。
  2. 变量名不一致:同时使用canv和canvas指代Canvas元素,canvas未定义会导致尺寸设置逻辑出错。
  3. 画布尺寸绘制错误:填充背景时使用了Canvas的实际像素尺寸(已乘以设备像素比DPR),但上下文已按DPR缩放,导致背景填充范围超出可视区域。

修正方案

针对上述问题,调整后的完整代码如下:

<html>
<head>
<title>Our Universe</title>
<style>
body {margin: 0; padding: 0}
</style>
</head>
<body> 
<canvas id='canvas'>Sorry, your browser does not support this feature.</canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Get the DPR and size of the canvas
const dpr = window.devicePixelRatio;
const rect = canvas.getBoundingClientRect();
// Set the "actual" size of the canvas
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
// Scale the context to ensure correct drawing operations
ctx.scale(dpr, dpr);
// Set the "drawn" size of the canvas
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;

const w = rect.width;
const h = rect.height;

const circle = function(color, r) {
    ctx.fillStyle = color;
    ctx.beginPath();
    ctx.arc(0, 0, r, 0, 2 * Math.PI, true);
    ctx.closePath();
    ctx.fill();
}

const earth = new Image();
earth.src = 'earth.png';

let i = 0;
function draw() {
  ctx.save();

    // Paint background with CSS pixel dimensions
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, w, h);

    // Set origin to center (sun's position)
    ctx.translate(w / 2, h / 2);

    // Draw sun
    circle('yellow', 20);

    // Draw first planet (green) - orbit around sun
    ctx.save();
    ctx.rotate(i / 100); // Rotation speed
    ctx.translate(100, 0); // Orbit radius
    circle('green', 10);
    ctx.restore(); // Reset to sun's origin

    // Draw second planet (blue) - orbit around sun
    ctx.save();
    ctx.rotate(i / 150); // Slower rotation speed
    ctx.translate(150, 0); // Larger orbit radius
    circle('blue', 15);
    ctx.restore();

    // Draw third planet (red) - orbit around sun
    ctx.save();
    ctx.rotate(i / 200); // Even slower rotation
    ctx.translate(180, 0);
    circle('red', 10);
    ctx.restore();

  ctx.restore();

  i++;
  window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);
</script>
</body>  
</html>

关键修正点说明

  • 统一变量名:将canv改为canvas,确保所有Canvas元素引用的变量名一致。
  • 独立行星变换:每颗行星绘制前调用ctx.save()保存太阳原点的上下文状态,绘制完成后调用ctx.restore()恢复,保证每颗行星的旋转和平移都基于太阳中心执行,实现正圆轨道。
  • 背景填充尺寸修正:使用rect.width和rect.height(CSS像素尺寸)作为背景填充宽高,匹配缩放后的上下文,确保背景完全覆盖Canvas。
  • 差异化旋转速度:为不同行星设置不同旋转系数(如i/100、i/150),模拟真实太阳系中行星的不同公转周期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:35:56