2: Getting up to speed

The last chapter threw you headlong into a large number of new technologies. I’m glad you made it out alright!

This is the part of the book where we introduce a bunch of characters, but we don’t know much about them yet. Don’t worry, you will eventually! Remember what you can, and come back to this chapter if you need to.

In this chapter we’re going to zero in on the pac-man component, going over different parts of the code until it’s (mostly) no longer mysterious.

Components

In app/compents/pac-man.js, you’ll see the following code:

1 Ember.Component.extend({
2   ...
3 })

This means that PacMan is an Ember Component- it inherits all the properties of an Ember Component, while adding its own. An Ember Component is basically a container that is sealed from the outside world, except for if you poke a few holes into it. Most real-world programs will need to poke a couple holes, but we’re not poking any holes right now, so all we need to care about is in app/components/pac-man.js and app/templates/components/pac-man.hbs (and style/app.css).

As someone writing an intro book, this is incredibly convenient. You may have heard about the Ember Router and how revolutionary and vital it is… well, we’re going to write an entire game in Ember and never touch it. Same with Initializers, Controllers, Services, and innumerable other Ember features that are necessary in many apps but are also confusing to newcomers. We get to take advantage of the parts that are useful and leave the more confusing things for the second book.

If you want to learn more about components, here is a series of videos about them.

Of course, components don’t always consist of just a javascript file- they can have an associated handlebars (they can also consist of just a handlebars file, although that doesn’t happen in this tutorial).

Handlebars

A handlebars file is kind of like an html file, but you can do some limited programming in it. You can input variables, use if statements, and more (but not much more). Each template is associated with an Ember class, and that is where it gets the variables it uses.

Later we’ll use more of these features, but for right now all we’re going to do is create the html5 Canvas (using just plain old html).

1 <!-- in app/templates/components/pac-man.hbs -->
2 <canvas id="myCanvas" width="800" height="600"></canvas>

Canvas

Canvas is well named- it’s like a painter’s canvas. You can paint on it… then you can paint on it again, partially painting over what you had previously drawn. And then, just like a real painter’s canvas1, you can create a bunch of robots that splatter paint over the canvas in precise intervals in order to create the illusion of motion.

This canvas defaults to pure white, but we’ve decided to tan it up a little using css.

Css

app/styles/app.css is where we’re going to store the styling information. While css is a powerful tool, in this book we’re basically just going to use it to turn things pretty colors, so there’s no previous knowledge needed (and, likely, no knowledge to be gained). You can just copy and paste any css we present directly into app/styles/app.css.

Here’s what you copy-pasted in the last chapter:

1 #myCanvas {
2   background-color: #EDC9AF;
3 }

It turns the canvas a nice tan color.

CSS means ‘Cascading Style Sheets’, and is way more important in a regular web app than it is in pac-man. If you’re interested in learning more, click here for some great introductory courses (subscription required).

Canvas context and drawing

Of course, we don’t just want that tan color… we want a circle!

That’s where the following code comes into play

 1 let canvas = document.getElementById("myCanvas");
 2 let ctx = canvas.getContext("2d");
 3 
 4 ...
 5 
 6 ctx.fillStyle = '#000';
 7 ctx.beginPath();
 8 ctx.arc(x, y, radius, 0, Math.PI * 2, false);
 9 ctx.closePath();
10 ctx.fill();

The first line grabs the canvas, then the second line gets the 2d context, which we’ll call ctx for short.

The last five lines are drawing the circle onto the 2d context of the canvas. You don’t need to understand them. But you do need to know what let is.

Let

let is extremely well named. Take this example:

1 let chapterNumber = 2;

Read it out loud: ‘Let chapterNumber equal two’. That’s pretty much what it does. chapterNumber is now a variable equal to two. Another way to think of this is “assigning values to variables”, where 2 is the value and chapterNumber is the variable.

If you’ve programmed in javascript before, you’ll know about var. let is similar, but has slightly different scoping properties, which are generally less confusing. If you haven’t programmed in javascript before, you can safely ignore that last sentence.

So right before we draw our circle we have a bunch of let statements, and then we use those variables in the drawing.

1 let x = 50;
2 let y = 100;
3 let radius = 20;
4 ctx.arc(x, y, radius, 0, Math.PI * 2, false);

is equivalent to

1 ctx.arc(50, 100, 20, 0, Math.PI * 2, false);

We name the variables because it’s easier to read. We may also want to extract them later (say, next chapter).

let is a feature of ES2015 which isn’t supported in all browsers… why are we using it? Because we’re using Babel, an ES2015+ transpiler. That means Babel takes your code that’s written to the ES2015 (or ES2016, ES2017, etc.) and turns it into code that (almost) all browsers can read (sorry, IE7 users).

“But wait,” you ask, “how do I install Babel?”

It’s already installed. You started using it the moment you generated the project. This is (part of the) magic of ember-cli.

didInsertElement

didInsertElement is your way of telling the Ember component “hey, after you’re done putting this component on the screen, I want you to do this.”

“Putting this component on the screen” usually means “displaying whatever is in the handlebars file”. In this case, the HTML5 Canvas.

Here’s our full code:

1 didInsertElement: function() {
2   this.drawCircle();
3 },

So what it’s saying is “whenever you’re done putting this component on the screen, draw a circle”.

You may be wondering what’s up with all the function() and the curly braces {} mean… well, those are parts of defining and using functions.

Functions

Functions are a great way to reuse code. We define it once, and then we never have to write that code again.

Here is us drawing a circle:

1 this.drawCircle();

Here is us drawing two circles:

1 this.drawCircle();
2 this.drawCircle();

It’s easy, because we defined the drawCircle function. We’ll get into the funny marks later.

Here’s the basic format of defining a function:

1 functionName: function() {
2   ...
3 }

There’s another slightly better way of defining functions that’s new in ES2015. We’re going to wait to introduce that technique, because introducing it now would make introducing hashes in the next chapter more confusing.

Here is us defining the drawCircle function:

 1 drawCircle: function() {
 2   let canvas = document.getElementById("myCanvas");
 3   let ctx = canvas.getContext("2d");
 4   let x = 50;
 5   let y = 100;
 6   let radius = 20;
 7 
 8   ctx.fillStyle = '#000';
 9   ctx.beginPath();
10   ctx.arc(x, y, radius, 0, Math.PI * 2, false);
11   ctx.closePath();
12   ctx.fill();
13 },

Everything in between { and } gets run when we call drawCircle.

We’re defining the drawCircle function on the component. One way to think of it is to say that the component now knows how to draw a circle. Another more fancy way to think of it is ‘the function drawCircle is assigned to the component scope’.

Scope can be a scary word, but here’s a basic way to think about it. If you’re in your living room, and you say “I would like to sit on the couch”, you don’t have to specify which of the millions of couches you’re sitting on. You’re in the living room scope, so when you’re trying to think of couches, the one in the living room comes to mind first. It’s the same reason that if you talk to someone in the United States about “the civil war”, they’ll immediately think of the American Civil War, not the Spanish Civil War, the American Revolution, or Marvel Comic’s Civil War (tm). That’s because they’re scoped to the United States2.

Let’s go back to where we were drawing circles and talk about those funny marks:

1 this.drawCircle();

this, in this case, means ‘the component scope’. Hey, that’s where we stored the drawCircle function. How lucky!

this.drawCircle, without the (), would return the code for the function. When we add the () it ‘calls’ the function, which means it runs the code in the function. And that code draws the circle.

didInsertElement is a special type of function called a ‘hook’. Don’t worry about it for now, just noticed that we define it using the same patterns that we used to define drawCircle

import/export

One last thing is the import and export functionality. This is the ES2015 module system at work!

So what import says is “I’m gonna need some code. Give me the code.”

1 import Ember from 'ember';

This says “Go to the place (library) known as ‘ember’, take the default thing there, and call it ‘Ember’”.

Then we have the following line:

1 export default Ember.Component.extend({
2   ...
3 })

This says “Whenever someone asks for something from this file (and doesn’t specify any particular thing), give them the Component we’re defining.”

If we wanted to get PacMan in another file, we’d need to say:

1 import PacMan from 'pac-man/components/pac-man';

So we go into the pac-man library (our project), go into the components folder, and get the component named pac-man.

There’s other ways to use imports and exports, but we won’t need them in this book.

Click here for more about ES2015 modules

Feeling good yet?

We’ve learned a lot of new concepts in this chapter- Components, Handlebars, Functions, Let, Canvas, CSS, and ES2015 Modules. The rest of the book will build on these concepts (while introducing new ones, albeit at a slower pace).

Now, back to our story.