ZoEM
ZoEM

Reputation: 852

Positioning on canvas with dynamic coordinates

I’m working on an interactive solar system canvas with HTML5 canvas. I want to be able to position the planets at specific coordinates on the canvas when the page has loaded. Right now I’ve got them all lined up on a single horizontal line, so I know how far their respective distances from eachother are. As you can see in the small image.

enter image description here

But here’s my problem, because the x and y coordinates keep changing based on the function that makes them rotate, I have no idea how to exactly position those planets on the canvas so they’re spread from eachother and nothing like how they’re on the image, WHILE still having them positioned so that they don’t get in direct contact with eachother when they’re rotating. I think a bit of math is involved here.

Also: I realise different animation intervals are probably a workaround for this, but I’m having trouble with that. When I create new animation functions for each planet, the planet drawings aren’t nowhere as smooth as one animation would bring. I realise this is a standalone question itself!

Here’s most of the relevant code:

function initCanvas(){
var ctx = document.getElementById('my_canvas').getContext('2d');
var dynamicSunW = 25;
var dynamicSunH = 0;
var dynamicSunX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5);  //dynamicSun is always at dead center of canvas
var dynamicSunY = (ctx.canvas.height * .5) - (dynamicSunH * .5);
var angleOfSun = 0;


var posMercuryX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;  
var posMercuryY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 20;
var gravityMercury = {x: posMercuryX, y: posMercuryY };
var posVenusX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posVenusY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 46;
var gravityVenus = {x: posVenusX, y: posVenusY };
var posEarthX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posEarthY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 80;
var gravityEarth = {x: posEarthX, y: posEarthY};
var posMarsX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posMarsY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 116;
var gravityMars = {x: posMarsX, y: posMarsY };
var posJupiterX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posJupiterY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 157;
var gravityJupiter = {x: posJupiterX, y: posJupiterY };
var posSaturnX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posSaturnY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 208;
var gravitySaturn = {x: posSaturnX, y: posSaturnY };
var posUranusX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posUranusY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 250;
var gravityUranus = {x: posUranusX, y: posUranusY };
var posNeptuneX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posNeptuneY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 283.9;
var gravityNeptune = {x: posNeptuneX, y: posNeptuneY };




    function rotate_point(pointX, pointY, originX, originY, ang) {
            ang =  Math.PI / 180.0;
            return {
                x: Math.cos(ang) * (pointX-originX) - Math.sin(ang) * (pointY-originY) + originX,
                y: Math.sin(ang) * (pointX-originX) + Math.cos(ang) * (pointY-originY) + originY
            };
        }

        var Solarsystem = {
            Neptune: {
                render: function(){
                    ctx.beginPath();
                    gravityNeptune = rotate_point(gravityNeptune.x, gravityNeptune.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityNeptune.x,gravityNeptune.y ,10, 0, 2*Math.PI, true);
                    ctx.fillStyle = "darkblue"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Uranus: {
                render: function(){
                    ctx.beginPath();
                    gravityUranus = rotate_point(gravityUranus.x, gravityUranus.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityUranus.x,gravityUranus.y ,6, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(64,224,208)"; 
                    ctx.closePath();
                    ctx.fill();
                }
            }
            , Saturn: {
                render: function(){
                    ctx.beginPath();
                    gravitySaturn = rotate_point(gravitySaturn.x, gravitySaturn.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravitySaturn.x,gravitySaturn.y ,15, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(186,85,211)"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Jupiter: {
                render: function(){
                    ctx.beginPath();
                    gravityJupiter = rotate_point(gravityJupiter.x, gravityJupiter.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityJupiter.x,gravityJupiter.y ,18, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(255,255,153)"; 
                    ctx.closePath();
                    ctx.fill();


                    }
            }
            , Mars: {
                render: function(){
                    ctx.beginPath();
                    gravityMars = rotate_point(gravityMars.x, gravityMars.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityMars.x,gravityMars.y ,7, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(255,99,71)"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Earth: {
                render: function(){
                    ctx.beginPath();
                    gravityEarth = rotate_point(gravityEarth.x, gravityEarth.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityEarth.x,gravityEarth.y ,8, 0, 2*Math.PI);
                    ctx.fillStyle = "rgba(30,144,255,1)"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Venus: {
                render: function(){
                    ctx.beginPath();
                    gravityVenus = rotate_point(gravityVenus.x, gravityVenus.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityVenus.x,gravityVenus.y ,7, 0, 2*Math.PI);
                    ctx.fillStyle = "rgba(255,165,0,1)"; 
                    ctx.closePath();
                    ctx.fill();
                }
            }
            , Mercury: {
                render: function(){
                ctx.beginPath();
                gravityMercury = rotate_point(gravityMercury.x, gravityMercury.y, dynamicSunX, dynamicSunY, angleOfSun)
                ctx.arc(gravityMercury.x,gravityMercury.y ,5, 0, 2*Math.PI);
                ctx.fillStyle = "rgba(119,136,153,1)";  
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
                }
            }
            , Sun: {
            render: function(){
            ctx.fillStyle = "rgba(255,255,51,1)";  
            ctx.save(); //store ctx so it can  be later reused 
            ctx.shadowColor = 'yellow';
            ctx.shadowBlur = 70;
            ctx.shadowOffsetX = 0;
            ctx.shadowOffsetY = 0;  
            ctx.beginPath();
            ctx.arc(dynamicSunX, dynamicSunY, dynamicSunW, dynamicSunH, Math.PI*2, true);
            ctx.closePath();
            ctx.fill();
            ctx.restore(); //ctx at time of save
                }
            }
        }




    var bg = new Image();
    bg.src = "spacedef.png";
            function Background(){
            this.x = 0, this.y = 0, this.w = bg.width, this.h = bg.height;
            this.render = function(){
                ctx.drawImage(bg, this.x--, 0);
                if(this.x <= -499){
                    this.x = 0;
                }
            }
        } 

        var background = new Background(); 

        function animate(){
            background.render();
            Solarsystem.Neptune.render();
            Solarsystem.Uranus.render();
            Solarsystem.Saturn.render();
            Solarsystem.Jupiter.render();
            Solarsystem.Mars.render();
            Solarsystem.Earth.render();
            Solarsystem.Venus.render();
            Solarsystem.Mercury.render();
            Solarsystem.Sun.render(); 
        }
         var animateInterval = setInterval(animate, 1000/60);  

    }

Upvotes: 0

Views: 149

Answers (1)

markE
markE

Reputation: 105015

Intead of using rotation points that are relative to each other, perhaps rotate all planets around the Sun. Each planet would have its own radius from the Sun so your math reduces to this (for a circular orbit):

var neptune.x=sun.x+neptune.radius*Math.cos(radianAngle);
var neptune.y=sun.y+neptune.radius*Math.sin(radianAngle);

Of course, the planets orbits are actually more elliptical than circular. You can calculate points on an ellipse like this:

// Calc points on Ellipse
function getPointsOnEllipse(cx,cy,a,b){
    var startAngle=-PI/2;
    var lastX=cx-(a*Math.cos(startAngle));
    var lastY=cy+(b*Math.sin(startAngle));
    var points=[];
    // change 1000 to your desired count of waypoints along the ellipse
    for(var i=0;i<1000;i++){
        var angle=startAngle+PI2/1000*i;
        var x=cx-(a*Math.cos(angle));
        var y=cy+(b*Math.sin(angle));
        var dx=x-lastX;
        var dy=y-lastY;
        var length=parseInt(Math.sqrt(dx*dx+dy*dy));
        var eAngle=(Math.atan2(dy,dx)+PI2)%PI2;
        if(length>0){
            points.push({x:x,y:y,angle:eAngle});
            lastX=x;
            lastY=y;
        }
    }
    return(points);
}

Upvotes: 1

Related Questions