Canvas行星无法沿正圆公转问题求助及代码排查
问题原因
- 上下文变换累积错误:当前代码中,绘制完第一颗行星后未重置Canvas上下文状态,后续行星的旋转和平移操作基于前一颗行星的位置执行,导致每颗行星围绕前一颗行星而非太阳公转,轨迹偏离正圆。
- 变量名不一致:同时使用
canv和canvas指代Canvas元素,canvas未定义会导致尺寸设置逻辑出错。 - 画布尺寸绘制错误:填充背景时使用了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
相关产品推荐
相关产品推荐

