Stage 1

Overview

In the first stage of the Cityscape Challenge, we will draw the shapes of buildings with different sizes. Because we will be drawing lots of buildings, we will automate the process using functions and variables.

Overviewvisual1
 

Lesson: Drawing In The Coordinate System

Reference

When drawing on canvas it is important to understand how the coordinate system works, specifically that "y" values go down.

Unlike with a normal graph, where the positive "y" values go up, in the canvas positive "y" values go down from the top.

So the point (50, 100) is 50 pixels from the right of the top left corner of the canvas and 100 pixels down from the top left corner.

In the example below, the black square is at (0, 0) so it's top left corner is in the top left corner of the canvas. The blue square is at (50, 100) so it's top left corner is 50 pixels to the right and 100 pixels down.

Try adjusting the coordinates of the two squares and see how they move around the coordinate system.

Quick Reference: Coordinates fillRect()

Important: This is a lesson, not a challenge. It is here just to help you learn. Play around with it to see your code changes affect the result. Scroll down for the first challenge.

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_lesson1'); var context = canvas.getContext('2d'); context.fillRect(0, 0, 50, 50); context.fillStyle = 'blue'; context.fillRect(50, 100, 50, 50);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 1

Challenge1example
Challenge 1 Sample Solution

Draw a rectangle using the code context.fillRect(x, y, width, height) where you replace x with the top left x coordinate, y with the top left y coordinate, width with the width of the rectangle and height with the height of the rectangle.

Draw the rectangle so that it's top left corner is 60px to the right of the top left corner of the canvas and 90px down. The rectangle should be 45px wide (width) and 45px tall (height).

In the end your drawing should look like the example provided to the right.

Quick Reference: Coordinates fillStyle fillRect()

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge1'); var context = canvas.getContext('2d'); // YOUR CODE HERE
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge1

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge1'); var context = canvas.getContext('2d'); context.fillRect(60, 90, 45, 45);
 

Lesson: The Ground

When drawing a cityscape you need to to draw all of the buildings sitting on the ground.

This complicates our drawing because we need to draw each building as a rectangle that starts from the top left corner, but we need to draw it relative to the ground, not the top.

This example shows the ground as a simple line, 240px from the top of the canvas.

Quick Reference: Coordinates fillRect()

Important: This is a lesson, not a challenge. It is here just to help you learn. Play around with it to see your code changes affect the result. Scroll down for the next challenge.

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_lesson2'); var context = canvas.getContext('2d'); context.fillRect(0, 240, canvas.width, 5);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 2

Challenge2example
Challenge 2 Sample Solution

Try drawing the ground yourself. The only important variable in the ground drawing is the height from the top of the canvas.

So uncomment out the ground variable and fill in the correct value to place the ground 260px from the top of the canvas.

In the end your drawing should look like the example provided to the right.

Quick Reference: Coordinates fillStyle fillRect()

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge2'); var context = canvas.getContext('2d'); // Set the ground variable properly. var ground = context.fillRect(0, ground, canvas.width, 5);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge2

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge2'); var context = canvas.getContext('2d'); // Set the ground variable properly. var ground = 260; context.fillRect(0, ground, canvas.width, 5);
 

Lesson: Draw a Building

In our drawing a building will be a rectangle. We use context.fillRect() to draw the rectangle, just as we did above.

In this example, we draw a building that is 160 pixels wide, 240 pixels tall, and positioned so its top left corner is at (100, 50) with it's bottom touching the ground.

Remember: In the context's coordinate system the origin (0, 0) is at the top left corner of the canvas.

Quick Reference: Coordinates fillRect()

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_lesson3'); var context = canvas.getContext('2d'); // THE GROUND context.fillRect(0, 290, canvas.width, 3); // THE BUILDING context.fillRect(100, 290 - 240, 160, 240);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 3

Challenge3example
Challenge 3 Sample Solution

Draw a building (a rectangle) that is 320 pixels wide and 160 pixels tall. Make sure the bottom of the building rests on the ground which is 240 pixels from the top. The building should also be 40 pixels from the left, so the bottom left corner of the building is covering the x at (40, 240) and the top right corner is covering the other x, but not covering the red x's.

Remember the you need to draw from the top left corner, not from the ground. You'll need to calculate the top of the building.

In the end your building should look like the example provided to the right.

Quick Reference: Coordinates fillStyle fillRect()

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge3'); var context = canvas.getContext('2d'); // YOUR CODE HERE
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge3

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge3'); var context = canvas.getContext('2d'); var ground = 240; context.fillRect(40, ground - 160, 320, 160);
 

Lesson: Draw a Colored Building

Our buildings will be different colors to show shadows and depth.

In this example, we will draw a building that is blue and one that is red.

The context.fillStyle property allows us to change the color of the building.

There are a number of ways to define the color, as shown in the fillStyle lesson.

Quick Reference: Coordinates fillRect() fillStyle

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_lesson4'); var context = canvas.getContext('2d'); var ground = 280; context.fillStyle = 'blue'; context.fillRect(50, ground - 160, 90, 160); context.fillStyle = '#FF0000'; context.fillRect(200, ground - 90, 160, 90);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 4

Challenge4example
Challenge 4 Sample Solution

Draw a gray building that is 90 pixels wide and 210 pixels tall.

The building's bottom left corner should be at (60, 280).

Most importantly, the building should be gray (#999999).

In the end your building should look like the example provided to the right.

Quick Reference: Coordinates fillStyle fillRect()

Previous Challenge: View your code from Stage 1 Challenge 3 to use on this challenge.

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 3
Stage 1 Challenge 3
Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge4'); var context = canvas.getContext('2d'); // YOUR CODE HERE
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge4

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge4'); var context = canvas.getContext('2d'); var ground = 280; context.fillStyle = '#999999'; context.fillRect(60, ground - 210, 90, 210);
 

Lesson: Use Variables to Size and Position a Building

We can use variables to automatically size and position a building.

In this example, we draw a green building (color #228B22) that is twice as tall as it is wide, and sitting on the ground at (60, 280).

To change the size of the building, all we do is store a different value in the variable w. The program automatically calculates the height of the building (assigning it to the variable h) and the y-coordinate of the top of the building (assigning it to the variable y). These variables are then used to draw the building.

Quick Reference: Variables Coordinates fillStyle fillRect()

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_example5'); var context = canvas.getContext('2d'); var w = 80; var h = 2 * w; var y = 280 - h; context.fillStyle = '#228B22'; context.fillRect(60, y, w, h);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 5

Challenge5example
Challenge 5 Sample Solution

This time use a variable to calculate the x and y position of the building and the width and height ( more info about variables ). Setting a variable looks like this:

var x = 9;

Using these variables draw a gray (#666666) building that is positioned on the ground at (60, 240) and is 80 pixels tall and 200 pixels wide.

In the end your building should look like the example provided to the right.

Quick Reference: Variables Coordinates fillStyle fillRect()

Previous Challenge: View your code from Stage 1 Challenge 4 to use on this challenge.

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 4
Stage 1 Challenge 4
Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge5'); var context = canvas.getContext('2d'); // SET THE VARIABLES PROPERLY var ground = var width = var height = var x = var y = // CODE TO SET THE BUILDING COLOR (#666666) HERE context.fillRect(x, y, width, height);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge5

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge5'); var context = canvas.getContext('2d'); var ground = 240; var width = 200; var height = 80; var x = 60; var y = ground - height; context.fillStyle = '#666666'; context.fillRect(x, y, width, height);
 

Challenge 6

Challenge6visual1
Challenge6example
Challenge 6 Sample Solution

For our cityscape, we don't want think about buildings in terms of pixels. We want to size buildings based on the number of floors they have and the number of office units on each floor, and then write the program so it calculates the number of pixels for us.

Each office unit is 16 pixels wide and 16 pixels tall. The outer walls, roof, and floor of the building are each 4 pixels thick.

Write a program to calculate the size and position of the building for you. The variable units stores the number of office units on each floor. The variable floors stores the number of floors in the building.

Then draw a gray (color #999999) building with 10 floors and 8 office units on each floor sitting on the ground at (120, 280).

The function, drawOffices(x, y, w, h) will draw the offices of the building if you define w, h, x, and y correctly, where (x, y) are the coordinates of the top left corner of your building, and w and h are the width and height of your building.

In the end your drawing should look like the example on the right.

Quick Reference: Variables Coordinates fillStyle fillRect()

Previous Challenge: View your code from Stage 1 Challenge 5 to use on this challenge.

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 5
Stage 1 Challenge 5
Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge6'); var context = canvas.getContext('2d'); var ground = 280; var units = 8; var floors = 10; // CALCULATE THE WIDTH "w" HERE var w = // CALCULATE THE HEIGHT "h" HERE var h = // YOUR CODE TO CALCULATE X AND Y OF THE BUILDING HERE var x = var y = // YOUR CODE TO SET THE COLOR OF THE BUILDING (#999999) HERE context.fillRect(x, y, w, h);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge6

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge6'); var context = canvas.getContext('2d'); var ground = 280; var units = 8; var floors = 10; var w = (units * 16) + (2 * 4); var h = (floors * 16) + (2 * 4); var x = 120; var y = ground - h; context.fillStyle = '#999999'; context.fillRect(x, y, w, h);
 

Lesson: Use a Function to Draw a Building

Drawing a single building takes quite a few steps. We have to calculate the width and height of the building, and the y-coordinate of the top of the building. Then we have to set the building color and draw the rectangle. Once we start drawing in windows, the list of steps will get much longer.

To draw our cityscape, we have to draw dozens of buildings. Typing in all that code for each building is going to be a lot of work.

If there is a chunk of code that you are going to use over and over again, putting that code into a function can make your life much easier. Then, to run the code, all you have to do is call the function by typing one line.

In this example, we create a function that will draw a French flag. Because we might want to draw a French flag in lots of different places, we make the x- and y-coordinates of the flag variables. When we call drawFrenchFlag(30, 100), the 30 is assigned to the variable x and the 100 is assigned to the variable y inside of the function. Now we can easily draw as many French flags as we want!

Quick Reference: fillRect() fillStyle Coordinates Variables Functions

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_example7'); var context = canvas.getContext('2d'); function drawFrenchFlag(x, y) { context.fillStyle = '#0055A4'; context.fillRect(x, y, 20, 40); context.fillStyle = '#FFFFFF'; context.fillRect(x + 20, y, 20, 40); context.fillStyle = '#EF4135'; context.fillRect(x + 40, y, 20, 40); } drawFrenchFlag(30, 100); drawFrenchFlag(150, 50); drawFrenchFlag(300, 180);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 7

Challenge7example
Challenge 7 Sample Solution

Write a function to draw the building from Challenge 6. The function will be passed four values that it will assign to the following four variables (called parameters). The first parameter, leftX, is the x-coordinate of the left side of the building. The second parameter, groundY, is the y-coordinate of the base of the building. The third parameter, units, is the number of office units on a floor. The fourth parameter, floors, is the number of floors in the building.

Then use the function to draw two buildings. The first building will have 12 floors and 8 office units per floor, and it will be sitting on the ground at (50, 300). The second building will have 18 floors and 6 office units per floor, and it will be sitting on the ground at (200, 300).

Just like with Challenge 6, both buildings should be gray (color #999999) and each office should be 16 x 16 width 4 pixels of padding around the whole building.

Quick Reference: fillStyle fillRect() Coordinates Variables Functions

Previous Challenge: View your code from Stage 1 Challenge 6 to use on this challenge.

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 6
Stage 1 Challenge 6
Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge7'); var context = canvas.getContext('2d'); function drawBuilding(leftX, groundY, units, floors) { // YOUR CODE FOR DRAWING A GENERAL BUILDING HERE } // YOUR CODE FOR DRAWING THE TWO SPECIFIC BUILDINGS HERE
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge7

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge7'); var context = canvas.getContext('2d'); function drawBuilding(leftX, groundY, units, floors) { var width = (units * 16) + (4 * 2); var height = (floors * 16) + (4 * 2); context.fillRect(leftX, groundY - height, width, height); } context.fillStyle = '#999999'; drawBuilding(50, 300, 8, 12); drawBuilding(200, 300, 6, 18);
 

Lesson: Use translate() to Position the Building

Now we are going to clean up our functions a little bit.

A well-written function is like a polite robot who comes over to your house to do a job, and then leaves everything exactly as it found it. But if you look at the function used to draw a French flag in the previous example, it wasn't so tidy. It changed the context.fillStyle to '#EF4135' and never changed it back.

To make our function more tidy, we are going to call context.save() at the start of the function and context.restore() at the end of the function. Calling context.save() saves the state of the context (including the current context.fillStyle), and context.restore() restores the context to the last time you saved it.

The other change we are going to make to our function is to use context.translate(). Notice how we had to do some calculations with x and y to figure out the positions of the white and red rectangles in the French flag? Imagine you had to do the same calculations for a hundred windows in a building. By using context.translate(), we can eliminate a lot of that math.

Calling context.translate() moves the origin of the context. If we move the origin of the context to the top left corner of the flag, then we can draw the rectangles in the flag as though the flag is positioned at (0, 0). The math is much easier. However, when using context.translate(), it's even more important to save and then restore the context. If you think changing the context.fillStyle is rude, changing the origin of the context and not changing it back is much ruder!

(As an exercise, try to predict what would happen if you took out the context.save() and context.restore() from the function. You'll have to reset the example and then refresh the entire page to get everything back to normal.)

Quick Reference: fillStyle fillRect() Coordinates Functions save() / restore() translate()

Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_example8'); var context = canvas.getContext('2d'); function drawFrenchFlag(x, y) { context.save(); context.translate(x, y); context.fillStyle = '#0055A4'; context.fillRect(0, 0, 20, 40); context.fillStyle = '#FFFFFF'; context.fillRect(20, 0, 20, 40); context.fillStyle = '#EF4135'; context.fillRect(40, 0, 20, 40); context.restore(); } drawFrenchFlag(30, 100); drawFrenchFlag(150, 50); drawFrenchFlag(300, 180);
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)

Challenge 8

Challenge8example
Challenge 8 Sample Solution

This time, write the drawBuilding() function, but using context.save(), context.translate(), and context.retore() provided in the function. You'll need to adjust your code from Challenge 7 accordingly.

Then use the drawBuilding function to draw one building with 12 office units per floor and 6 floors sitting on the ground at (40, 300) and another building with 10 office units per floor and 15 floors at (280, 300).

Both buildings should be gray (color #999999) and each office should be 16 x 16 width 4 pixels of padding around the whole building.

Just remember if you call translate but don't restore the state of the context then the next translation will be relative to the first translation and your drawing may be off the canvas!

Quick Reference: fillStyle fillRect() Coordinates Functions save() / restore() translate()

Previous Challenge: View your code from Stage 1 Challenge 7 to use on this challenge.

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 7
Stage 1 Challenge 7
Editor (write code below)
var canvas = document.getElementById('granular_basic_cityscape_stage1_challenge8'); var context = canvas.getContext('2d'); function drawBuilding(leftX, groundY, units, floors) { context.save(); var width = (units * 16) + (4 * 2); var height = (floors * 16) + (4 * 2); // CODE TO TRANSLATE POSITION HERE // CODE FOR DRAWING A BUILDING HERE context.restore(); } // YOUR CODE FOR DRAWING THE TWO BUILDINGS HERE
Message Log
This is a lesson, not a challenge, the code runs automatically.

But change it! Play with it! Click "Run" to see your changes.

Run
Run and Focus Canvas
Reset
Canvas (your drawing will display here)
Challenge8

A Solution: Here's the code I wrote to complete this challenge. View One Possible Solution

var canvas = document.getElementById('flappy_square_stage1_challenge8'); var context = canvas.getContext('2d'); function drawBuilding(leftX, groundY, units, floors) { context.save(); var width = (units * 16) + (4 * 2); var height = (floors * 16) + (4 * 2); context.translate(leftX, groundY - height); context.fillRect(0, 0, width, height); context.restore(); } context.fillStyle = '#999999'; drawBuilding(40, 300, 12, 6); drawBuilding(280, 300, 10, 15);

Ready for the next lesson?

Next up, the "Stage: 2" lesson >