I’m making a simple program using canvas where I have a sun, and there are three planets rotating around it. I managed to make the Sun and the planets. However, when I try to revolve the planets around the Sun, for some reason the planets do not revolve in a perfect circle.
Here’s my code:
const canv = document.getElementById('canvas'); const ctx = canv.getContext('2d'); canv.width = window.innerWidth; canv.height = window.innerHeight; // Get the DPR and size of the canvas var dpr = window.devicePixelRatio; var 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`; var w = canvas.width; var h = canvas.height; var 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'; mwidth= canvas.width/2; mheight= canvas.height/2; var i = 0; function draw() { ctx.save(); // paint bg ctx.fillStyle = 'black'; ctx.fillRect(0, 0, w, h); // set origin to center ctx.translate(w / 2, h / 2); // draw sun circle('yellow', 20); // rotate + move along x ctx.rotate(i / 100); ctx.translate(100, 0); // draw planet circle('green', 10); // rotate + move along x ctx.rotate(i / 100); ctx.translate(150, 0); // draw planet circle('blue', 15); // rotate + move along x ctx.rotate(i / 100); ctx.translate(180, 0); // draw planet circle('red', 10); ctx.restore(); i++; window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw); //setInterval(draw, 1);
body {margin: 0; padding: 0}
<html> <head> <title>Our Universe</title> </head> <body> <canvas id='canvas'>Sorry, your browser does not support this feature.</canvas> </body> </html>
You can see if you run the above snippet that the planets are revolving in a strange manner (they are not revolving in perfect circles.). Can someone explain why and help me correct this?
Advertisement
Answer
If you want them to be perfect circles, there’s nothing like trigonometry. 🙂
To find the point on a circle, you use:
x = radius * cosine(angle); y = radius * sine(angle);
…which gives you a value that is -radius
to radius
for each. You offset those by the center of the circle.
So for your example, you could use your game counter (i
) multiplied by some speed variable and calculate the center point of each of the three orbiting planets, like this:
const canv = document.getElementById("canvas"); const ctx = canv.getContext("2d"); canv.width = window.innerWidth; canv.height = window.innerHeight; // Get the DPR and size of the canvas let dpr = window.devicePixelRatio; let 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`; let w = canvas.width; let h = canvas.height; let mwidth = w / 2; let mheight = h / 2; let circle = function (x, y, color, r) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI, true); ctx.closePath(); ctx.fill(); }; /* Not currently used const earth = new Image(); earth.src = "earth.png"; */ const circles = [ {color: "green", radius: w / 8, size: 10, speed: 0.02, }, {color: "red", radius: w / 6, size: 15, speed: 0.012, }, {color: "blue", radius: w / 4, size: 10, speed: 0.01, }, ]; let i = 0; function draw() { ctx.save(); // paint bg ctx.fillStyle = "black"; ctx.fillRect(0, 0, w, h); // Draw sun circle(mwidth, mheight, "yellow", 20); // Draw circles for (const { speed, radius, color, size } of circles) { const angle = (i * speed) % 360; const x = radius * Math.cos(angle); const y = radius * Math.sin(angle); circle(mwidth + x, mheight + y, color, size); } ctx.restore(); i++; window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw);
body {margin: 0; padding: 0}
<html> <head> <title>Our Universe</title> </head> <body> <canvas id='canvas'>Sorry, your browser does not support this feature.</canvas> </body> </html>
I haven’t used transform
in that, there didn’t seem to be any need, but I’m relatively new to canvas programming so you might want to adjust the above to use that instead of explicit x
/y
coordinates.
Side note: I’m not sure the scaling code in there is correct, the canvas looks slightly distorted to me. But that wasn’t the question. 🙂