I Can't Even Canvas, But Now You Can!

Posted on Mon, 7/10/2017
11 minutes read

This is also posted on Code Koalas's site.

If you're anything like me a couple years ago, you probably have avoided doing animations in Canvas because it's crazy complicated and you're just a person who can make websites, not a real programmer who can make games and things. But here's the thing: you're wrong. Making animations and games in Canvas is very easy and fun, I'd argue it's easier than writing JavaScript for sites. If you can make a mobile menu, a carousel, or even just an alert() you can make a small animation in Canvas. I've taught this to children and very drunk people who know nothing about coding at Code Koalas First Friday events we host.

First off, what are we building?

You will be building a ball bouncing around the screen, just like the old DVD screen saver. If you have no coding experience this will take about 30 minutes, if you have used JavaScript or other languages before you can probably tackle this in 15 minutes or less.

See the Pen Learning Canvas Teaching 2017 by Josh Fabean (@fabean) on CodePen.

Getting Started

I have created a starter pen with all boilerplate code required to get started. It has lots of comments explaining what everything is if you're not familiar with coding at all.

See the Pen Learning Canvas Teaching 2017 Starter by Josh Fabean (@fabean) on CodePen.

From here if you aren't familiar with programming or JavaScript you'll continue reading as normal and head to the Quick JavaScript Brush up section, but if you think you're good enough to just jump straight into the Time to Code section, go for it.

Quick JavaScript Brush up

As you probably noticed that starter Pen I gave you comes with a lot of code already. At the time of publishing this it's 49 lines of JavaScript and 1 line of HTML. Don't worry, it will all make sense soon enough - or not, but it's okay! You'll still be able to make a ball bounce over the screen even if you don't totally understand how it works.

HTML

(HyperText Markup Language) is the most basic building block of the Web. It describes and defines the content of a webpage.

-- MDN's definition

HTML is in every website you go to everyday. It's what defines what is a big header, a navigation link, an image or a paragraph. It's the backbone of websites. Since it's a markup language and not a programming language it's pretty easy to wrap your head around the basic concepts of this and it's not super important for what we're working on here.

In the starter code you have you'll see you only have one HTML tag.

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

What you have there is a HTML tag of canvas with an id of canvas. The canvas element was added in HTML5 in late 2014 and can be used to draw graphics, you can learn more about canvas on MDN

JavaScript

JavaScript is a cross-platform, object-oriented scripting language. It is a small and lightweight language. Inside a host environment (for example, a web browser), JavaScript can be connected to the objects of its environment to provide programmatic control over them.

--MDN's definition<

Variables

Anytime you want to use the same bit of information multiple times through your program, you'll use a variable. In JavaScript variables are defined with let, var, or const. In our code you'll see right at the top the following lines:

let c;
let ctx;
const fps = 60;

The first two lines we're declaring variables named c and ctx but we're not setting their value to anything. On the third line we are using const to define fps to 60 for 60 frames per second. We're using cost instead of let because this is a constant meaning - we're not ever going to change that value.

Functions

Just like variables are anytime you want to access the same bit of information multiple times, functions are anytime you want to run the same couple lines of code multiple times. Functions are sort of like paragraphs, they contain a lot of different words and sentences but generally do a single cohesive thing when put together.

In JavaScript you create functions with the following syntax

let functionName = (variablesPassedIn) => {
 // code you want to run
}

You can see it's similar to how we define a variable starting with let and the variable/function name. But then we add () => to make it a function and {} wraps all the code that belongs to that function.

In our code we first define the following function:

// if you want to draw lots of circles you'll use this function
let drawCircle = (circle) => {
  ctx.fillStyle = circle.color; // set the color
  ctx.beginPath(); // telling canvas we're about to define a path.
  ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2, true);
  // x&y coordinates, the size, ..?, pi*2 for radius, true? defines we are drawing a cirlce. You can draw all sorts of curves with .arc
  ctx.fill(); // fill defines it's colored in, instead of just an outline or something like that.
}

This function is important to know because it shows what Canvas actually needs to render circles onto the page. In the function drawCircle we first pass in the object of circle. The circle object will need to look like the following:

let myCoolCircle = {
  color: '#FFF',
  x: 100,
  y: 100,
  radius: 20,
};

The circle object has 4 properties we care about for drawing on that screen, color, x, y, and radius. We pass those into the drawCircle function and then that function draws it. The first line of the function is ctx.fillStyle = circle.color which tells the ctx we created earlier in the code that we are setting the current fillStyle to be the color of the circle object, in this example thats #FFF or white. The next line is ctx.beginPath() which simply tells ctx we will be drawing a path which you can learn more about .beginPath on MDN like always. With beginPath you can draw any type of path including a straight line or in our case a circle. The following line ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2, true); tells canvas what we're doing with that path we just started, learn about .arc on MDN. That line says where to start drawing with the circle.x and circle.y then defines how large of a circle we're drawing with the circle.radius. The next parts are the start angle of 0 then the end angle of Math.PI*2.

If Statements

The if statement executes a statement if a specified condition is true. If the condition is false, another statement can be executed.

-- MDN's definition

If statements are one of the main building blocks of programming. This is what allows programs to respond to situations and "think". They're very simple: if something is true we do one thing, if it's not true we do another. The syntax for an if statement is as follows:

if (your condition goes here) {
 // run code on true
}
else {
 // run code on false
}

Inside the () is where we put our conditional statement. A very simple example would be (1 > 2) which of course would be false and run the else, or we can do (1 < 2) which would be true and run the code in the if. We can also have or or and statements in our conditions. A condition with an or looks like (1 > 2 || 3 < 4) that would return true since one of those statements are true even though one is false. A condition with an and looks like (1 < 2 && 4 < 5) that would also return true since both conditions are true.

Time to Code!

Draw the background

The first thing we need to do is draw our background. With canvas each frame you draw over what already existed so if we don't redraw that background every frame over time we'll have a line instead of a ball. We will create our background inside of our render function, it will look like the following:

let background = {
  color: '#000',
  x: 0,
  y: 0,
  width: c.width,
  height: c.height
};

All rectangles have a color, x & y starting coordinates, width & height of the rectangle. A few things worth noting: on canvas x & y start on the top left of your element so 0,0 is the top left of the screen. That height & width we're pulling off of previous code used to set the canvas element to the full width & height of the screen.

Once you have that background defined we just now need to tell our program to draw it on the page by putting the following below it.

drawRect(background);

If everything was done correctly you should now have a black background on your screen (you can replace that color with any HEX value or most color names instead of black if you'd like, you can find a full list of colors available on MDN) and it should look like the following:

See the Pen Learning Canvas Teaching 2017: Background Done by Josh Fabean (@fabean) on CodePen.

Draw the circle

Drawing the circle is very similar to the background, but this time it's a circle instead of a rectangle so we change just a few things. Also since we will be wanting to move this circle we need it's values always available. This means we will need to define ball up on the top of our file next to where c & ctx are defined. It should look like the following:

let ball = {
  color: '#FFF',
  x: 20,
  y: 20,
  radius: 10
}

That's very similar to the rectangle with a couple of difference. We use radius to describe circles instead of height & width, and in Canvas they draw circles from the center so we didn't want to start x & y at 0 or it'd be mostly off screen.

But that doesn't do anything yet, we now need to tell Canvas to render that object onto the page. To do that go down to the render function right below where you put the drawRect(background) and add the line drawCircle(ball). If done right you should get a white ball. If everything worked right you'll have the following:

See the Pen
Learning Canvas Teaching 2017: Circle Done
by Josh Fabean (@fabean)
on CodePen.

Move the circle

Now that you have a circle, making it move is just a couple more lines of code. The first thing I do is update the ball object on the top of the file to define the speed at which we will move it both on the x & y values. To do that your object will now look like this:

let ball = {
  color: '#FFF',
  x: 20,
  y: 20,
  radius: 10,
  speedX: 10,
  speedY: 4
}

You'll notice we just added two lines. Those two lines are speedX & speedY the letters Y & X being capitalized is called camel case and is how people write things in JavaScript to be readable. You can set your values to something else if you'd like, but we are defining how many pixels the ball will move per frame so if you go much higher than 10 it will fly across the screen really fast.

Now that you have defined how it should move, we need to actually make it move. The logic for this will go in our render function. What we'll tell it to do is every frame take what the X & Y values are, and add the speed to them. It will look like the following:

ball.x = ball.x + ball.speedX;
ball.y = ball.y + ball.speedY;

drawCircle(ball);

Now your ball should start moving and eventually fly off the screen like the following: (Very likely it's been off the screen for a long time in this example)

See the Pen
Learning Canvas Teaching 2017: Circle Moves
by Josh Fabean (@fabean)
on CodePen.

Make the circle bounce

Fix flying off right side of screen

Great! The ball moves, but now it disappears because we aren't yet stopping it from flying off of the screen. We will handle this by adding checks before we move the ball to see if it's at a wall, if it is we will reverse the direction it's going. In my example it flies of off the right side of the screen first. To fix that it will look like the following:

if (ball.x > c.width) {
  ball.speedX = - ball.speedX;
}

That will if ball.x is greater than c.width the canvas's width take the ball.speedX value of 10 and make it -10 which reverses it to the left. In action it looks like this:

See the Pen
Learning Canvas Teaching 2017: Bounce Right Side
by Josh Fabean (@fabean)
on CodePen.

Fix flying off bottom of screen

Now it falls off of the bottom of the screen, so how do we fix that? (It might not fall off the bottom based on your values and screen size and dimensions but for me it's the bottom next). We can do almost the same thing as before but this time on the y value of our ball.

if (ball.y > c.height) {
  ball.speedY = - ball.speedY;
}

Now when it hits the bottom it bounces back up like this:

See the Pen
Learning Canvas Teaching 2017: Bounce Bottom
by Josh Fabean (@fabean)
on CodePen.

Finally get it bouncing off all sides of the screen

Now we run into the issue where the same thing happens but for the left & top. We can just modify our already existing if statements to allow them to also check the left & top sides like this:

if (ball.x > c.width || ball.x < 0) {
  ball.speedX = - ball.speedX;
}
if (ball.y > c.height || ball.y < 0) {
  ball.speedY = - ball.speedY;
}

The || means OR so now our statement says, if ball.x is greater than c.width OR ball.x is less than 0 reverse the direction of ball.speedX and the same thing for the y value. When all put together you have a fully bouncing ball!

See the Pen
Learning Canvas Teaching 2017: Bounce All Sides
by Josh Fabean (@fabean)
on CodePen.

Bonus

There are a lot of cool things you can do from here:

  • Change color on bounce
  • Add extra balls when clicked
  • Have ball change size on bounce
  • Add extra balls on bounce (dangerous as this gets out of hand quick and can crash your browser)

I recently gave this talk at Drupal Camp and you can watch the video for step by steps for all of this and some of the fun bonuses.