user1806369
user1806369

Reputation: 21

Making a circle that moves

Been trying to get something to work in HTML and I haven't been able to nail it down quite yet. Basically, I want to create a canvas and then make a circle inside the canvas that moves from edge of the canvas to edge of the canvas. Any suggestions?

EDIT:

Folks wanted what I have so far, so here it is:

<html> 
<head> 
<script type="text/javascript">   
function draw () {
    var canvas = document.getElementById('circle');
    if (canvas.getContext) {
      var context = canvas.getContext('2d');

      context.fillStyle = "rgb(150,29,28)";
      var startPoint = (Math.PI/180)*0;
      var endPoint = (Math.PI/180)*360;
      context.beginPath(); 
      context.arc(200,200,150,startPoint,endPoint,true);    
      context.fill();
   context.closePath(); 
      }
    }   
} 
</script>
</head>
<body onload="init();"> 
<canvas id="canvas" width="500" height="500"></canvas><br>

</body> 
</html>

I'm not really sure how to get a circle onto the canvas (and I'm still shakey on the implementation thereof) as well as how to make it, y'know, move. I have examples of how to rotate something, but not really how to move it. Sorry for the inexperience guys, trying to learn HTML on my own, but the book I've got doesn't seem really descriptive on this aspect, even though it's a supposed to be teaching me HTML.

Upvotes: 2

Views: 9226

Answers (2)

Delta
Delta

Reputation: 4328

So up to now you have a code where you're able to draw a circle at a certain position onto the canvas surface, very well, now in order to make it look like it's moving you'll have to keep drawing it again and again with it's position slightly changed to give a smooth motion effect to it, it's a standard to draw things 60 times per second (I think that's because 60 frames per second is the most that the human eye can notice, or whatever). And of course, each time you draw it on another position, it's going to be necessary to clear the older drawing.

Let's change your code just a bit in order to make it animation-friendly:

<script type="text/javascript">   
function init()
{
   canvas = document.getElementById('canvas');
   if(canvas.getContext)
      context = canvas.getContext('2d');
   else return;

   setInterval(draw, 1000 / 60); // 60 times per second
}

function draw()
{
   context.clearRect(0, 0, canvas.width, canvas.height);
   context.fillStyle = "rgb(150,29,28)";
   // var startPoint = (Math.PI/180)*0; Kinda redundant, it's just 0
   // var endPoint = (Math.PI/180)*360; Again, it's just PI times 2
   context.beginPath(); 
   context.arc(200, 200, 150, 0, Math.PI * 2, true);    
   context.fill();
   context.closePath(); 
} 
</script>
</head>
<body onload="init();"> 
<canvas id="canvas" width="500" height="500"></canvas><br>

Now there are lots of funny ways to make an object move towards a fixed point, but the simplest is, of course, moving along a straight line. To do so you'll need

  • A vector containing the object's current position
  • A vector containing the object's target position

Let's change your code so we have those at hand

var canvas, context,
    position = {x: 200, y: 200},
    target = {x: 400, y: 400};

function init()
{
    ...
}

function draw()
{
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = "rgb(150,29,28)";
    context.beginPath(); 
    context.arc(position.x, position.y, 150, 0, Math.PI * 2, true);    
    context.fill();
    context.closePath(); 
}

Good! This way whenever you change one of the values in the position object, the position of your circle is going to be affected.

If you subtract the current position from the target position you'll get another vector which points straight to the target position coming from the current position right? So get that vector and just normalize it, turning it's length to 1, the result will actually be the (cosine, sine) of the angle from the target to the object's position. What that means is if you add that normalized vector to the object's current position, the object will move towards the target position 1 unit at a time.

Normlizing a vector is simply dividing it's components by it's length.

function normalize(v)
{
    var length = Math.sqrt(v.x * v.x + v.y * v.y);
    return {x: v.x / length, y: v.y / length};
}

var step = normalize({x: target.x - position.x, y: target.y - position.y});

Ok, now all we need to do is keep adding the step vector to the object's current position until it reaches the target position.

function normalize(v)
{
    var length = Math.sqrt(v.x * v.x + v.y * v.y);
    return {x: v.x / length, y: v.y / length};
}

var canvas, context,
    position = {x: 200, y: 200},
    target = {x: 400, y: 400},
    step = normalize({x: target.x - position.x, y: target.y - position.y});

function init()
{
   canvas = document.getElementById('canvas');
   if(canvas.getContext)
      context = canvas.getContext('2d');
   else return;

   setInterval(draw, 1000 / 60);
}

function draw()
{
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = "rgb(150,29,28)";
    context.beginPath(); 
    context.arc(position.x, position.y, 150, 0, Math.PI * 2, true);    
    context.fill();
    context.closePath(); 

    position.x += step.x;
    position.y += step.y;
}

And there you have it. Of course it's pretty basic code, you'll have to add a codition to check whether or not the object has arrived to the target otherwise it will just keep going past the target. If it's moving too slow, just scale the step vector by an arbitrary speed factor. Also in a real world app you'd have lot's of objects and not only just a circle so you'd have to make it entirely object-oriented since every object would have it's position, target position, color etc etc etc. A library to work with vectors would come in handy. This is one I wrote for myself some time ago: http://pastebin.com/Hdxg8dxn

Upvotes: 5

enhzflep
enhzflep

Reputation: 13089

Here you go, give this a crack -

<!DOCTYPE html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
function newTxt(txt){return document.createTextNode(txt);}
function toggleClass(element, newStr)
{
    index=element.className.indexOf(newStr);
    if ( index == -1)
        element.className += ' '+newStr;
    else
    {
        if (index != 0)
            newStr = ' '+newStr;
        element.className = element.className.replace(newStr, '');
    }
}
function forEachNode(nodeList, func)
{
    var i, n = nodeList.length;
    for (i=0; i<n; i++)
    {
        func(nodeList[i], i, nodeList);
    }
}

window.addEventListener('load', mInit, false);

var canvas, hdc;
var posx=50, posy=0, radius=50;

function circle(hdc, x, y, radius)
{
    hdc.beginPath();
    hdc.arc(x, y, radius, 0, 2*Math.PI);
    hdc.stroke();
//arc(x,y,r,start,stop)
}

function mInit()
{
    canvas = byId('tgtCanvas');
    hdc = canvas.getContext('2d');

    //circle(hdc, posx, posy, 50);
    setInterval(animateStep, 50);
}

var velX = 2;
function animateStep()
{
    posx += velX;
    if (posx+radius > canvas.width)
        velX *= -1;
    else if (posx-radius < 0)
        velX *= -1;

    hdc.clearRect(0,0,canvas.width,canvas.height);
    circle(hdc, posx, posy, radius);
}

</script>
<style>
</style>
</head>
<body>

    <canvas id='tgtCanvas' width='256' height='256'></canvas>

</body>
</html>

Upvotes: 1

Related Questions