Stage 1

Overview

Overviewvisual1

In the first stage of the Cityscape Challenge, we 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.

 

Draw a Building

A building is a filled in rectangle. We use the context.fillStyle property to set the color of the rectangle and the context.fillRect() method to draw the rectangle.

We start by setting the context.fillStyle property to the color '#1E90FF':

context.fillStyle = '#1E90FF';

Then, we use the context.fillRect() method to draw the rectangle with the fill color:

context.fillRect(100, 50, 160, 240);

To draw a rectangle, we pass the context.fillRect() method four values. The first two values are the x- and y-coordinates of the top left corner of the rectangle. We are drawing this rectangle at the coordinates (100, 50).

The context's coordinate system is slightly different than the coordinate system we use in math. The origin (0, 0) is in the top left corner of the canvas, not the bottom left corner. The x-coordinate still measures distance to the right of the origin, but the y-coordinate measures distance down, not up. Therefore, the top left corner of our rectangle is 100 pixels to the right and 50 pixels down from the origin.

The second two values are the width and height of the rectangle. This rectangle is 160 pixels wide and 240 pixels tall.

Try changing the first two values passed into the context.fillRect() method to move the rectangle around the canvas. Change the second two values to resize the rectangle.

To learn more about the coordinate system, drawing rectangles, and defining fill colors, visit the Coordinates, fillRect(), and fillStyle lessons.

Quick Reference: Coordinates fillRect() fillStyle

Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_example1'); var context = canvas.getContext('2d'); context.fillStyle = '#1E90FF'; context.fillRect(100, 50, 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 1

Challenge1visual1
What your drawing should look like

Use the context.fillRect() method to draw a building (rectangle) that is 320 pixels wide and 160 pixels tall so the top left corner of the building is positioned at (40, 80).

Figure out the y-coordinate of the bottom of the building. Then, use the drawGround() function to draw a line representing the ground beneath the building. For example, if the y-coordinate of the bottom of the building is 120, use:

drawGround(120);

Make sure to draw the ground after drawing the building.

If you need help drawing the building or positioning the ground, visit the Coordinates and fillRect() lessons.

Quick Reference: Coordinates fillRect()

Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_challenge1'); var context = canvas.getContext('2d'); context.fillStyle = 'Black'; // DRAW THE BUILDING HERE // DRAW THE LINE FOR THE GROUND HERE function drawGround(y) { context.save(); context.fillStyle = 'Black'; context.fillRect(0, y, canvas.width, 2); context.restore(); }
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
 

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 positioned at (60, 40).

To change the size of the building, all we do is assign a different value to the variable w. The program automatically calculates the height of the building and assigns it to the variable h.

var w = 80; // Change this value to resize the building
var h = 2 * w; // The height is automatically two times the width

We use the values stored in the variables to draw the building:

context.fillStyle = '#228B22';
context.fillRect(60, 40, w, h);

Change the value stored in the variable w to see what happens. To learn more about variables, visit the Variables lesson.

Quick Reference: Coordinates Variables fillRect() fillStyle

Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_example2'); var context = canvas.getContext('2d'); var w = 80; // Change this value to resize the building var h = 2 * w; // The height is automatically two times the width context.fillStyle = '#228B22'; context.fillRect(60, 40, 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 2

Challenge2visual1
What your drawing should look like

Assign values to the variables x, y, w, and h in the program below to draw a gray (color '#999999') building with its top left corner positioned at (100, 40) and a width of 150 and height of 240.

Then, figure out the y-coordinate of the bottom of the building. Use the drawGround() function to draw a line representing the ground. Draw the ground after drawing the building. Can you calculate the ground's y-coordinate using the variables in the program?

If you need help using variables, visit the Variables lesson.

Quick Reference: Coordinates Variables fillRect() fillStyle

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

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 1
Stage 1 Challenge 1
Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_challenge2'); var context = canvas.getContext('2d'); var x = 0; var y = 0; // The building's top left corner is at (100, 40) var w = 100; var h = 100; // The building is 150 pixels wide and 240 pixels tall // SET THE COLOR OF THE BUILDING TO #999999 HERE // DRAW THE BUILDING HERE USING THE VARIABLES x, y, w, h drawGround(100); // Position and draw the ground here function drawGround(y) { context.save(); context.fillStyle = 'Black'; context.fillRect(0, y, canvas.width, 2); context.restore(); }
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
 

Challenge 3

Challenge3visual1
Challenge3visual2
What your drawing should look like

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.

The number of office units on each floor is assigned to the variable units and the number of floors in the building is assigned to the variable floors. Use the values stored in those variables to calculate the width and height of the building.

Then, draw a gray (color '#999999') building with 10 floors and 8 office units on each floor with its top left corner positioned at (120, 80).

Use the function drawOffices() to draw the offices in the building by passing it the values stored in the variables x, y, w, and h.

Finally, figure out the y-coordinate of the bottom of the building and then use the drawGround() function to draw a line representing the ground. Draw the ground after drawing the building.

If you need help using variables, visit the Variables lesson.

Quick Reference: Coordinates Variables fillRect() fillStyle

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

Code Missing: You have not yet entered any code in to the previous challenge: Stage 1 Challenge 2
Stage 1 Challenge 2
Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_challenge3'); var context = canvas.getContext('2d'); var x = 120; var y = 80; var units = 8; var floors = 10; var w = 0; // Use the variable units to calculate the width of the building var h = 0; // Use the variable floors to calculate the height of the building // SET THE COLOR OF THE BUILDING TO #999999 HERE // DRAW THE BUILDING HERE USING THE VARIABLES x, y, w, h drawOffices(x, y, w, h); // Draw the offices drawGround(100); // Position and draw the ground here function drawOffices(x, y, w, h) { var u = Math.floor((w - 4) / 16); var f = Math.floor((h - 4) / 16); context.save(); context.translate(x + 4, y + 4); context.strokeWidth = 1; context.strokeStyle = '#000000'; for (var i = 0; i < f; i++) { for (var j = 0; j < u; j++) context.strokeRect(16 * j, 16 * i, 16, 16); } context.restore(); } function drawGround(y) { context.save(); context.fillStyle = 'Black'; context.fillRect(0, y, canvas.width, 2); context.restore(); }
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
 

Use a Function to Draw a Building

Drawing a single building takes a few steps. First, we have to calculate the width and height 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 parameters. When we call drawFrenchFlag(30, 100), the 30 is automatically assigned to the parameter x and the 100 to the parameter y inside the function. Now we can easily draw as many French flags as we want!

To learn more about functions, visit the Functions lesson.

Quick Reference: Coordinates Variables Functions fillRect() fillStyle

Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_example3'); 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 4

Challenge4visual1
What your drawing should look like

Create a drawBuilding() function to draw buildings like the one from Challenge 3. The function is passed four values that it will assign to the following four parameters. The first two parameters,xand y, are the coordinates of the top left corner of the building; the third parameter, units, is the number of office units per floor; and the fourth parameter, floors, is the number of floors in the building.

Inside the drawBuilding() function, use the parameters to calculate the width and height of the building, set the context.fillStyle property to the color '#999999', and use the context.fillRect() method to draw the building.

Once the drawBuilding() function has been defined, use it to draw two buildings. The first building has 8 office units per floor and 10 floors, and it is positioned at (60, 20). The second building has 6 office units per floor and 16 floors, and it is positioned at (210, 20).

If you need help using functions, visit the Functions lesson.

Quick Reference: Coordinates Variables Functions fillRect() fillStyle

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('basic_cityscape_stage1_challenge4'); var context = canvas.getContext('2d'); function drawBuilding(x, y, units, floors) { var w = 0; // Use the parameter units to calculate the width of the building var h = 0; // Use the parameter floors to calculate the height of the building // SET THE COLOR OF THE BUILDING TO #999999 HERE // DRAW THE BUILDING HERE USING THE PARAMETERS x, y AND THE VARIABLES w, h } // DRAW ONE BUILDING WITH 8 UNITS AND 10 FLOORS AT (60, 20) HERE // DRAW A SECOND BUILDING WITH 6 UNITS AND 16 FLOORS AT (210, 20) 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
 

Anchor the Building to the Ground

You may have noticed that the two buildings in Challenge 3 are lined up along their top edges, not their bottom edges. In general, buildings are lined up along their bottom edges where they sit on the ground.

In this example, we create the fillCenteredRectangle() function, which automatically positions a rectangle by its top center point. This function has four parameters: centerX, topY, w, and h.

function fillCenteredRectangle(centerX, topY, w, h) {

  // code block

}

Inside the function, we use the parameters to calculate the coordinates of the rectangle's top left corner and draw the rectangle:

function fillCenteredRectangle(centerX, topY, w, h) {
  var x = centerX - w / 2;
  var y = topY;

  context.fillRect(x, y, w, h);
}

Since centerX is the x-coordinate of the center of the rectangle, we need to subtract half the rectangle's width to get the x-coordinate of the rectangle's top left corner. Since topY is the y-coordinate of the top of the rectangle, which is what we want, we assign it to the variable y.

Now we can easily draw a group of rectangles and line them up by their top center points. To learn more about positioning rectangles using variables, visit the Coordinates, Variables, and fillRect() lessons.

Quick Reference: Coordinates Variables Functions fillRect()

Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_example4'); var context = canvas.getContext('2d'); var centerX = 180; // The x-coordinate of the center of the rectangles drawCenterLine(); context.fillStyle = 'DeepPink'; fillCenteredRectangle(centerX, 20, 200, 80); // Centered at centerX fillCenteredRectangle(centerX, 120, 320, 100); // Centered at centerX fillCenteredRectangle(centerX, 240, 240, 60); // Centered at centerX function fillCenteredRectangle(centerX, topY, w, h) { var x = centerX - w / 2; var y = topY; context.fillRect(x, y, w, h); } function drawCenterLine() { context.save(); context.fillStyle = 'Black'; context.fillRect(centerX - 1, 0, 2, canvas.height); context.restore(); }
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

Challenge5visual1
What your drawing should look like

Update the drawBuilding() function from Challenge 4 so its parameters are now: leftX, groundY, w, and h.

Inside the function, calculate the coordinates of the top left corner of the building's rectangle. Then, set the context.fillStyle to the color '#999999' and use the context.fillRect() method to draw the rectangle.

Once the drawBuilding() function has been updated, use it to draw two buildings. The first building has 12 office units per floor and 8 floors, and it is sitting on the ground at (20, 280). The second building has 9 office units per floor and 15 floors, and it sitting on the ground at (230, 280).

The drawGround() function is used to draw the ground at y = 280. Draw the buildings before the ground is drawn.

If you need help positioning rectangles using variables, visit the Coordinates, Variables, and fillRect() lessons.

Quick Reference: Coordinates Variables Functions 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('basic_cityscape_stage1_challenge5'); var context = canvas.getContext('2d'); function drawBuilding(leftX, groundY, units, floors) { var w = 0; // Calculate the width of the building var h = 0; // Calculate the height of the building var x = 0; // Calculate the x-coordinate of the building's top left corner var y = 0; // Calculate the y-coordinate of the building's top left corner // SET THE COLOR OF THE BUILDING TO #999999 HERE // DRAW THE BUILDING HERE USING THE VARIABLES x, y, w, h } // DRAW ONE BUILDING WITH 12 UNITS AND 8 FLOORS SITTING AT (20, 280) HERE // DRAW A SECOND BUILDING WITH 9 UNITS AND 15 FLOORS SITTING AT (230, 280) HERE drawGround(280); // Draws the ground at y = 280 function drawGround(y) { context.save(); context.fillStyle = 'Black'; context.fillRect(0, y, canvas.width, 2); context.restore(); }
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
 

Use translate() to Position the Building

Now we are going to clean up the drawBuilding() function 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 property to the color '#EF4135' and never changed it back.

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

The other change is to use the context.translate() method. Notice how we had to do calculations with x and y to figure out the positions of the white and red rectangles in the French flag? Imagine we had to do the same for dozens of windows in a building. We can eliminate a lot of that math by using the context.translate() method.

The context.translate() method moves the origin of the coordinate system. If we move the origin 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 the context.translate() method, it is even more important to save and then restore the drawing state. If changing the context.fillStyle property is rude, moving the origin of the coordinate system and not moving it back is much ruder!

Try to predict what would happen if we left out the context.save() and context.restore() method calls in the function. To learn more about saving and restoring the drawing state and translating the origin of the coordinate system, visit the save() / restore() and translate() lessons.

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

Editor (write code below)
var canvas = document.getElementById('basic_cityscape_stage1_example5'); var context = canvas.getContext('2d'); function drawFrenchFlag(x, y) { context.save(); // Save the drawing state before making any changes context.translate(x, y); // Move the origin of the coordinate system to the top left corner of the flag context.fillStyle = '#0055A4'; context.fillRect(0, 0, 20, 40); // The blue rectangle is drawn at (0, 0) context.fillStyle = '#FFFFFF'; context.fillRect(20, 0, 20, 40); // The white rectangle is drawn at (20, 0) context.fillStyle = '#EF4135'; context.fillRect(40, 0, 20, 40); // The red rectangle is drawn at (40, 0) context.restore(); // Restore the drawing state to the way it was when we saved it } 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 6

Challenge6visual1
What your drawing should look like

Tidy up the drawBuilding() function from Challenge 5 in the same way by calling the context.save() and context.restore() methods at the start and end of the function, respectively. Then, use the context.translate() method to move the origin to (x, y) and draw the rectangle at (0, 0).

Once the drawBuilding() function is tidy, draw one building with 10 office units per floor and 16 floors sitting on the ground at (20, 290) and another building with 12 office units per floor and 10 floors sitting on the ground at (200, 290).

The drawGround() function is used to draw the ground at y = 290. Draw the buildings before the ground is drawn.

If you need help saving and restoring the drawing state and translating the origin of the coordinate system, visit the save() / restore() and translate() lessons.

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

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('basic_cityscape_stage1_challenge6'); var context = canvas.getContext('2d'); function drawBuilding(leftX, groundY, units, floors) { var w = 0; // Calculate the width of the building var h = 0; // Calculate the height of the building var x = 0; // Calculate the x-coordinate of the building's top left corner var y = 0; // Calculate the y-coordinate of the building's top left corner // SAVE THE DRAWING STATE HERE // MOVE THE ORIGIN TO THE TOP LEFT CORNER OF THE BUILDING HERE // SET THE COLOR OF THE BUILDING TO #999999 HERE // DRAW THE BUILDING AT (0, 0) HERE USING THE VARIABLES w, h // RESTORE THE LAST SAVED DRAWING STATE HERE } // DRAW ONE BUILDING WITH 10 UNITS AND 16 FLOORS SITTING AT (20, 290) HERE // DRAW A SECOND BUILDING WITH 12 UNITS AND 10 FLOORS SITTING AT (200, 290) HERE drawGround(290); // Draws the ground at y = 290 function drawGround(y) { context.save(); context.fillStyle = 'Black'; context.fillRect(0, y, canvas.width, 2); context.restore(); }
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

Ready for the next lesson?

Next up, the "Stage: 2" lesson >