One of the great things about the web and browser technology is that it's so accessible. Anyone can pick it up and start playing because any computer with a browser is ready to go — and that makes it a great platform for learning and prototyping. In this post I'd like to show you how we can use some JavaScript and a bit of simple mathematics to draw a square (don't worry, it'll be an exciting square).

First, we're going to need somewhere to draw. We'll use the HTML5 `<canvas>`

element — it goes in your markup just like any other.

`<canvas id="canvas"></canvas>`

To start drawing, we'll fetch canvas `Element`

and get a `2d`

drawing context. This just means we'll get one particular API that's used for simple 2D drawing. You could fetch a `webgl`

context if you wanted to use WebGL features.

```
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
```

Here `ctx`

is an instance of CanvasRenderingContext2D, which exposes to us a handy collection of methods to actually do something with our canvas. We'll mostly work with this `ctx`

object now, let's start by drawing a rectangle.

`ctx.fillRect(0, 0, 100, 100);`

You should end up with something similar to this:

Easy, huh?! You'll notice that mine is red. That's because I set the `fillStyle`

property like this: `ctx.fillStyle = '#ff0000';`

.

`fillRect`

is great but it's not very flexible. What if you wanted to rotate your square? The `fillRect`

function has no angle argument so we're going to need to find a better way — luckily the `CanvasRenderingContext2D`

gives us exactly that in the form of *paths*. The path methods let us trace out complex shapes, and then

```
ctx.beginPath(); // This starts a new path
ctx.moveTo(0, 0); // Move to our starting location, without actually tracing anything yet
ctx.lineTo(0, 100); // Left side
ctx.lineTo(100, 100); // Bottom side
ctx.lineTo(100, 0); // Right side
ctx.lineTo(0, 0); // Top side
ctx.fill();
ctx.stroke();
```

And you should get something like this:

You might notice that the lines here are a little blurry, this is because of an effect called *antialiasing* and can be solved.

Now would be a good time to play with the `moveTo`

and `lineTo`

arguments `x`

and `y`

. You'll notice that the origin `(0,0)`

is in the top left. As we increase `x`

, we move the point right. As we increase `y`

, we move the point **down**, not up — so it's not quite a traditional Cartesian coordinate plane.

Now we'll make a series of improvements — first, lets wrap this code up into a function so we can easily draw multiple squares. Better yet, we'll give the position of *the centre* of our square as an argument (using the centre will make everything much easier, as you will see soon).

```
function drawSquare(x, y) {
ctx.beginPath();
ctx.moveTo(x - 50, y - 50); // v0
ctx.lineTo(x - 50, y + 50); // v1
ctx.lineTo(x + 50, y + 50); // v2
ctx.lineTo(x + 50, y - 50); // v3
ctx.lineTo(x - 50, y - 50); // v0
ctx.fillStyle = 'red';
ctx.fill();
ctx.stroke();
}
drawSquare(50, 50);
```

What we're doing here is drawing four edges between four vertices — `v0`

, `v1`

, `v2`

, and `v3`

. We'll examine `v0`

first. The calculations `x - 50`

and `y - 50`

are simple but let's break them down to understand what is going on — it'll be easier if we rearrange the equations to `-50 + x`

and `-50 + y`

. The first components form a pair, `[-50, -50]`

. This is a vector, and it defines the position of `v0`

relative to the origin of our square (*i.e., up and left a bit*). These are known as *local coordinates*. The `x`

and `y`

variables form a vector too, `[x, y]`

, and this describes the translation of local coordinates to *world coordinates*. So, it's all just vector addition!

Given a local coordinate `vl`

and a position in world space `p`

, the equation for `vw`

is `vw = vl + p`

. With this in mind, let's improve our code a little.

```
var square = [
[-10, -10],
[-10, 10],
[10, 10],
[10, -10],
];
function draw(coords, pos, colour) {
var world_coords = [];
for (var i in coords) {
world_coords[i] = [
coords[i][0] + pos[0],
coords[i][1] + pos[1]
];
}
world_coords.push(world_coords[0]);
ctx.beginPath();
ctx.moveTo(world_coords[0][0], world_coords[0][1]);
for (i = 0; i < world_coords.length; i++) {
ctx.lineTo(world_coords[i][0], world_coords[i][1]);
}
ctx.fillStyle = colour;
ctx.fill();
ctx.stroke();
}
draw(square, [50, 50], 'green');
```

This new square is a little smaller, so let's make it bigger. We can do that with *scalar multiplication*. Let's pick a scale factor `s`

and add it to our equation above. Where does it go? Order is important here since the scaling will always happen around `[0, 0]`

. So our equation must be `vm = s * vl + p`

. If you applied the scalar multiplication after translating to world coordinates, the square would scalar relative to the top left corner of the canvas. Add a scale factor to your `draw`

function, and change the first `for`

loop to look more like this:

```
for (var i in coords) {
coords[i] = [
scale * coords[i][0] + pos[0],
scale * coords[i][1] + pos[1]
];
}
```

And you should be able to do something like this:

Great! So we've got scaling and translation, the last hurdle is *rotation*. For this we'll use a *rotation matrix*, specifically one for rotating a 2D point counter-clockwise around the origin. You can find it here. It looks something like this:

```
var angle = 45;
var matrix = [
[Math.cos(angle), - Math.sin(angle)],
[Math.sin(angle), Math.cos(angle)]]
];
```

Remember, this matrix operates around the origin — so the order we apply it is important. If our new matrix is `r`

, then our equation becomes `vm = s * (r * vl) + p`

. Since we're only dealing with two dimensions here, we'll expand the matrix multiplication out into two equations for the new point.

```
var a = x * Math.cos(angle) - y * Math.sin(angle)
var b = x * Math.sin(angle) + y * Math.cos(angle)
```

And our `draw`

function becomes:

```
for (var i in coords) {
var x = coords[i][0];
var y = coords[i][1];
world_coords[i] = [
scale * (x * Math.cos(angle) - y * Math.sin(angle)) + pos[0],
scale * (x * Math.sin(angle) + y * Math.cos(angle)) + pos[1]
];
}
```

The `angle`

variable here is in radians, so a value of `2 * Math.PI`

equates to a full rotation. Now you should have something like this:

Excellent! Play with the value a little, do you notice anything in particular? Remember we used a rotation matrix "for rotating a 2D point counter-clockwise around the origin", but our square rotates clockwise! This is because our `y`

axis is flipped, as you increase `y`

points move *down* and not up. This means our rotation matrix is operating slightly differently, but it still has the same effect.

One last thing we'll discuss is animation — which is a lot easier than you might think. We'll create a `frame`

function that we can call multiple times. Before you draw anything clear the canvas with `ctx.clearRect()`

.

```
var rotation = 0;
function frame() {
ctx.clearRect(0, 0, 150, 300);
draw(square, [50, 50], 1, rotation, 'green');
rotation += 0.03;
window.requestAnimationFrame(frame);
}
frame();
```

And you should get this!

And we're done. That's one exciting square, just as promised. Hopefully by now the message will be clear — **it's all just mathematics**. The canvas is just a vessel for our message, and because it's so accessible and has a fast feedback loop, you can play with the numbers to get a deeper understanding of what is going on.

The ideas here can be applied in many ways, some of which I hope to explore in future posts.

- Tracking game state on a server
- Three dimensions!
- Ray tracing

- What happens if you comment out our
`clearRect`

call? - Use
`fillRect`

and`fillStyle`

with some transparency. Surprise blur! - Try to make different primitive shapes.
- Draw rectanges, using their height and width as arguments.
- Move the world origin to the centre of the canvas (
*hint: use*)`canvas.width`

and`canvas.height`

- Flip the canvas
`y`

axis so up is the direction we expect - Draw a tank.
- Drive the tank!
- Fire tank shells!