You are previewing HTML5 Canvas.

# Chapter 5. Math, Physics, and Animation

Impressing users with animation involves more than knowing how to move objects—you also need to know how to move them in ways that users expect. That requires understanding some common algorithms for math-based movement and physics interactions. Simple movement based on points and vectors provides a foundation, and then it’s time to create objects that bounce off walls and one another with a bit of friction added to the mix. After that, we will step back and talk about movement that goes beyond straight lines: circles, spirals, and complex Bezier curves. We will then cover how adding gravity can affect movement. Finally, we will finish this chapter by discussing easing and how it can have a positive effect on math-based animations.

# Moving in a Straight Line

For the simplest kinds of animations—moving objects in a straight line up and down the canvas—this can take the form of adding a constant value to the `x` or `y` position of an object every time it is drawn.

So, to animate graphics, we will need to create an interval and then call a function that will display our updated graphics on every frame. Each example in this chapter will be built in a similar way. The first step is to set up the necessary variables in our `canvasApp()` function. For this first, basic example of movement, we will create a variable named `speed`. We will apply this value to the `y` position of our object on every call to `drawScreen()`. The `x` and `y` variables set up the initial position of the object (a filled circle) we will move down the canvas:

```var speed = 5;
var y = 10;
var x = 250;```

After we create the variables, we set up an interval to call the `drawScreen()` function every 33 milliseconds. This is the loop we need to update our objects and move them around the canvas:

`setInterval(drawScreen, 33);`

In the `drawScreen()` function, we update the value of `y` by adding to it the value of the `speed` variable:

`y += speed;`

Finally, we draw our circle on the canvas. We position it using the current value of `x` and `y`. Since `y` is updated every time the function is called, the circle effectively moves down the canvas:

```context.fillStyle = "#000000";
context.beginPath();
context.arc(x,y,15,0,Math.PI*2,true);
context.closePath();
context.fill();```

To move the circle up the screen, we would make `speed` a negative number. To move it left or right, we would update the `x` instead of the `y` variable. To move the circle diagonally, we would update both `x` and `y` at the same time.

Example 5-1 shows the complete code needed to create basic movement in a straight line.

Example 5-1. Moving in a straight line

```<!doctype html>
<html lang="en">
<meta charset="UTF-8">
<title>CH5EX1: Moving In A Straight Line</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript">
canvasApp();

}

function canvasSupport () {
return Modernizr.canvas;
}

function canvasApp() {

if (!canvasSupport()) {
return;
}

function  drawScreen () {

context.fillStyle = '#EEEEEE';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
//Box
context.strokeStyle = '#000000';
context.strokeRect(1,  1, theCanvas.width-2, theCanvas.height-2);

// Create ball

y += speed;

context.fillStyle = "#000000";
context.beginPath();
context.arc(x,y,15,0,Math.PI*2,true);
context.closePath();
context.fill();

}

theCanvas = document.getElementById("canvasOne");
context = theCanvas.getContext("2d");

var speed = 5;
var y = 10;
var x = 250;

setInterval(drawScreen, 33);

}

</script>

<body>
<div style="position: absolute; top: 50px; left: 50px;">

<canvas id="canvasOne" width="500" height="500">
Your browser does not support HTML5 Canvas.
</canvas>
</div>

</body>
</html>```

### Note

The basic structure of the HTML for all of the examples in this chapter will follow these rules. In the interest of saving space, we will refrain from discussing this code further, but it will appear in the examples provided.

## Moving Between Two Points: The Distance of a Line

Movement based on constant changes to the `x` or `y` position of an object works well for some applications, but other times you will need to be more precise. One such instance is when you need to move an object from point A to point B at a constant rate of speed.

In mathematics, a common way to find the length of an unknown line is to use the Pythagorean theorem:

 A2 + B2 = C2

In this equation, C is the unknown side of a triangle when A and B are already known. However, we need to translate this equation into something we can use with the points and pixels we have available on the canvas.

This is a good example of using a mathematical equation in your application. In this case, we want to find the distance of a line, given two points. In English, this equation reads like this:

The distance equals the square root of the square of the difference between the x value of the second point minus the x value of the first point, plus the square of the difference between the y value of the second point minus the y value of the first point.

You can see this in Equation 5-1. It’s much easier to understand in this format.

Equation 5-1. Distance equation

In the second example, we need to create some new variables in the `canvasApp()` function. We will still use a `speed` variable, just like in the first example, but this time we set it to `5`, which means it will move `5` pixels on every call to `drawScreen()`:

`var speed = 5;`

We then create a couple dynamic objects—each with an `x` and a `y` property—that will represent the two points we want to move between. For this example, we will move our circle from `20`,`250` to `480`,`250`:

```var p1 = {x:20,y:250};
var p2 = {x:480,y:250};```

Now it is time to re-create the distance equation in Equation 5-1. The first step is to calculate the differences between the second and first `x` and `y` points:

```var dx = p2.x - p1.x;
var dy = p2.y - p1.y;```

To determine the `distance`, we square both the values we just created, add them, and then use the `Math.sqrt()` function to get the square root of the number:

`var distance = Math.sqrt(dx*dx + dy*dy);`

Next, we need to use that calculated `distance` in a way that will allow us to move an object a uniform number of pixels from `p1` to `p2`. The first thing we do is calculate how many `moves` (calls to `drawScreen()`) it will take the object to move at the given value of `speed`. We get this by dividing the `distance` by the `speed`:

`var moves = distance/speed;`

Then we find the distance to move both `x` and `y` on each call to `drawScreen()`. We name these variables `xunits` and `yunits`:

```var xunits = (p2.x - p1.x)/moves;
var yunits = (p2.y - p1.y)/moves;```

Finally, we create a dynamic object named `ball` that holds the `x` and `y` value of `p1`

`var ball = {x:p1.x, y:p1.y};`

…and create the interval to call `drawScreen()` every 33 milliseconds:

`setInterval(drawScreen, 33);`

### Drawing the ball

Let’s draw the ball on the screen. In the `drawScreen()` function, we first check to see whether the `moves` variable is greater than zero. If so, we are still supposed to move the ball across the screen because we have not yet reached `p2`. We decrement moves (`moves--`) and then update the `x` and `y` properties of the ball object by adding the `xunits` to `x` and `yunits` to `y`:

```if (moves > 0 ) {
moves--;
ball.x += xunits;
ball.y += yunits;
}```

Now that our `values` have been updated, we simply draw the ball at the `x` and `y` coordinates specified by the `x` and `y` properties, and we are done…that is, until `drawScreen()` is called 33 milliseconds later:

```context.fillStyle = "#000000";
context.beginPath();
context.arc(ball.x,ball.y,15,0,Math.PI*2,true);
context.closePath();
context.fill();```

Let’s try the example by executing it in a web browser. You can find it in the code distribution as CH5EX2.html, or you can type in Example 5-2. Watch the ball move from one point to another. If you update the x and y values of each point, or change the speed, watch the results. You can do a lot with this very simple example.

### Tracing movement: A path of points

For many of the examples in this chapter, we will create a way to trace an object’s movement on the canvas by drawing points to show its path. We have done this to help illustrate how objects move. However, in the real world, you would need to remove this functionality so that your application would perform to its potential. This is the only place we will discuss this code, so if you see it listed in any of the later examples in this chapter, refer back to this section to refresh your memory on its functionality.

First, we create an array in `canvasApp()` to hold the set of points we will draw on the canvas:

`var points = new Array();`

Next, we load a black 4×4 pixel image, point.png, that we will use to display the points on the canvas:

```var pointImage = new Image();
pointImage.src = "point.png";```

Whenever we calculate a point for an object we will move, we push that point into the `points` array:

`points.push({x:ball.x,y:ball.y});`

On each call to `drawScreen()`, we draw the set of points we have put into the `points` array. Remember, we have to redraw every point each time because the canvas is an immediate-mode display surface that does not retain any information about the images drawn onto it:

```for (var i = 0; i< points.length; i++) {
context.drawImage(pointImage, points[i].x, points[i].y,1,1);
}```

In Figure 5-1, you can see what the ball looks like when moving on a line from one point to another, and also what the `points` path looks like when it is drawn.

### Note

This is the only time in this chapter where we will discuss the `points` path in depth. If you see the points being drawn, you will know how and why we have added that functionality. You should also have enough information to remove the code when necessary.

Example 5-2 is the full code listing for CH5EX2.html.

Example 5-2. Moving on a simple line

```<!doctype html>
<html lang="en">
<meta charset="UTF-8">
<title>CH5EX2: Moving On A Simple Line</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript">
canvasApp();

}

function canvasSupport () {
return Modernizr.canvas;
}

function canvasApp() {

if (!canvasSupport()) {
return;
}

var pointImage = new Image();
pointImage.src = "point.png";

function  drawScreen () {

context.fillStyle = '#EEEEEE';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
//Box
context.strokeStyle = '#000000';
context.strokeRect(1,  1, theCanvas.width-2, theCanvas.height-2);

// Create ball

if (moves > 0 ) {
moves--;
ball.x += xunits;
ball.y += yunits;
}

//Draw points to illustrate path

points.push({x:ball.x,y:ball.y});

for (var i = 0; i< points.length; i++) {
context.drawImage(pointImage, points[i].x, points[i].y,1,1);

}

context.fillStyle = "#000000";
context.beginPath();
context.arc(ball.x,ball.y,15,0,Math.PI*2,true);
context.closePath();
context.fill();

}
var speed = 5;
var p1 = {x:20,y:250};
var p2 = {x:480,y:250};
var dx = p2.x - p1.x;
var dy = p2.y - p1.y;
var distance = Math.sqrt(dx*dx + dy*dy);
var moves = distance/speed;
var xunits = (p2.x - p1.x)/moves;
var yunits = (p2.y - p1.y)/moves;
var ball = {x:p1.x, y:p1.y};
var points = new Array();

theCanvas = document.getElementById("canvasOne");
context = theCanvas.getContext("2d");

setInterval(drawScreen, 33);

}

</script>

<body>
<div style="position: absolute; top: 50px; left: 50px;">

<canvas id="canvasOne" width="500" height="500">
Your browser does not support HTML5 Canvas.
</canvas>
</div>
</body>
</html>```

## Moving on a Vector

Moving between two points is handy, but sometimes you don’t have a point to move to, only a point to start from. In cases like this, it can be very useful to create a `vector` as a means to move your object.

A vector is a quantity in physics that has both magnitude and direction. For our purposes, the magnitude will be the `speed` of the moving object, and the direction will be an `angle` that the object will move upon.

The good news is that moving on a vector is very similar to moving between two points. In `canvasApp()`, we first set our `speed` (magnitude). This is the number of pixels the object will move on every call to `drawScreen()`. We will set this to `5`. We will also set the starting point (`p1`) for the object to `20`,`20`:

```var speed = 5;
var p1 = {x:20,y:20};```

Now, we will set the `angle` (direction) of movement for our object to `45` degrees. In mathematics, a flat, straight line usually represents the 0 angle, which means a vector with an angle of 45 degrees would be down and to the right on the canvas.

With our angle set, we now need to convert it to radians. Radians are a standard unit of angle measurement, and most mathematical calculations require you to convert an angle into radians before you can use it.

So why not just use radians and forget degrees altogether? Because it is much easier to understand movement in degrees when working with vectors and moving objects on a 2D surface. While a circle has 360 degrees, it has just about 6 radians, which are calculated counterclockwise. This might make perfect sense to mathematicians, but to move objects on a computer screen, angles are much easier. So, we will work with angles, but we still need to convert our 45-degree angle into radians. We do that with a standard formula: `radians = angle * Math.PI/ 180`. And in the code:

```var angle = 45;
var radians = angle * Math.PI/ 180;```

Before we can discuss how we calculate the movement of our object along our vector, we need to review a couple trigonometric concepts. These are `cosine` and `sine`, and both relate to the arc created by our `angle` (now converted to `radians`), if it was drawn outward from the center of the circle.

`cosine`

The angle measured counterclockwise from the x-axis (`x`)

`sine`

The vertical coordinate of the arc endpoint (`y`)

You can see how these values relate to a 45-degree angle in Figure 5-2.

This might seem complicated, but there is a very simple way to think about it: cosine usually deals with the `x` value, and sine usually deals with the `y` value. We can use sine and cosine to help us calculate movement along our vector.

To calculate the number of pixels to move our object on each call to `drawScreen()` (`xunits` and `yunits`), we use the `radians` (direction) we calculated and `speed` (magnitude), along with the `Math.cos()` (cosine) and `Math.sin()` (sine) functions of the JavaScript `Math` object:

```var xunits = Math.cos(radians) * speed;
var yunits = Math.sin(radians) * speed;```

In `drawScreen()`, we simply add `xunits` and `yunits` to `ball.x` and `ball.y`. We don’t check to see whether `moves` has been exhausted because we are not moving to a particular point—we are simply moving along the vector, seemingly forever. In the next section, we will explore what we can do if we want the moving object to change direction when it hits something such as a wall:

```ball.x += xunits;
ball.y += yunits;```

Figure 5-3 shows what Example 5-3 looks like when it is executed in a web browser. Recall that the points are drawn for illustration only.

Example 5-3 gives the full code listing.

Example 5-3. Moving on a vector

```<!doctype html>
<html lang="en">
<meta charset="UTF-8">
<title>CH5EX3: Moving On A Vector</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript">
canvasApp();
}

function canvasSupport () {
return Modernizr.canvas;
}

function canvasApp() {

if (!canvasSupport()) {
return;
}

var pointImage = new Image();
pointImage.src = "point.png";

function  drawScreen () {

context.fillStyle = '#EEEEEE';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
//Box
context.strokeStyle = '#000000';
context.strokeRect(1,  1, theCanvas.width-2, theCanvas.height-2);

ball.x += xunits;
ball.y += yunits;

//Draw points to illustrate path

points.push({x:ball.x,y:ball.y});

for (var i = 0; i< points.length; i++) {
context.drawImage(pointImage, points[i].x, points[i].y,1,1);
}

context.fillStyle = "#000000";
context.beginPath();
context.arc(ball.x,ball.y,15,0,Math.PI*2,true);
context.closePath();
context.fill();

}
var speed = 5;
var p1 = {x:20,y:20};
var angle = 45;
var radians = angle * Math.PI/ 180;
var xunits = Math.cos(radians) * speed;
var yunits = Math.sin(radians) * speed;
var ball = {x:p1.x, y:p1.y};
var points = new Array();

theCanvas = document.getElementById("canvasOne");
context = theCanvas.getContext("2d");

setInterval(drawScreen, 33);

}

</script>