Skip to content
Advertisement

Circles in canvas not revolving properly in proper circle

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. 🙂

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement