CS 120, Fall 2011, Lab 5:
JavaScript: Canvas and Events

This lab introduces the <canvas> element, a recent addition to HTML that allows JavaScript to draw pictures on a web page. Exercise 1 asks you to draw such a picture. You can expect this lab to work in reasonably recent versions of Firefox, Chrome, and Safari. It should work in Internet Explorer 9, but not in earlier versions.

The lab also returns to the topic of events. In Lab 2, you saw how a button generates an event when the user clicks it and how JavaScript code in the button's onclick attribute can respond to such an event. In this lab, you will encounter mouse, keyboard, and timer events. Exercises 2, 3, and 4 ask you to respond to these events by drawing on a canvas. Completed versions of these exercises were demonstrated in class on Wednesday.

The directory /classes/cs120/lab5-files contains four HTML files that will serve as starting points for the exercises. To begin the lab, you should start a new Aptana web project named lab5, and you should copy the files from /classes/cs120/lab5-files into that project. These files contain a great deal of code that you will not understand at this point. For this lab, you will only have to fill in the definitions of some functions and add a few variables. You will not have to understand the JavaScript code that sets up the canvas graphics and the event handling.

The main point of the lab is to help you start understanding variables, assignment statements, functions, parameters, objects, and events. These are some of the basic building blocks of programming. You are certainly not expected to understand them completely at this time, but you will work with them in the context of drawing pictures, where you can easily see the results.

The lab is due next Thursday, at the beginning of next week's lab period. The four exercises are at the end of this web page.

Graphics and The Canvas Element

A <canvas> element on an HTML page represents a rectangular area on which you can draw using JavaScript commands. Each of the files that you will work on today contains a <canvas> element something like this:

<canvas id="canvas" width="600" height="600" style="background-color:black">

(The height is different in some of the files.) You could adjust the size and background color of the canvas by modifying this element. The JavaScript on the page has a variable, canvas, that refers to this element, and it has a variable graphics that is used to draw on the canvas. They are given values by saying:

canvas = document.getElementById("canvas");
graphics = canvas.getContext("2d");

These variables both refer to "objects." Recall that an object is a collection of variables and functions. The canvas object, for example, contains variables canvas.width and canvas.height whose values are the size of the canvas, and it contains the function canvas.getContext(). The graphics object contains variables and functions related to drawing on the canvas. (Note that canvas and graphics are already all set up and ready to go in the files that you will work on in the lab.)

Canvas graphics works with paths, shapes, strokes, and fills. You can "stroke" a path or the outline of a closed shape such as a rectangle or circle. You can a "fill" a closed shape. You can also work with text: The outlines of the characters are considered to be closed shapes, which you can either stroke or fill them.

A "graphics context", such as the one referred to by the variable named graphics in our examples, contains information relevant to stroking and filling. It has variables graphics.strokeStyle and graphics.fillStyle which hold the color that will be used for strokes and for fills, respectively. The values of these variables are CSS-style colors. For example, the assignments statements

graphics.strokeStyle = "red";
graphics.fillStyle = "#FFFFCC"

mean that subsequent stroke operations on the canvas will draw in red, and subsequent fill operations will draw in light yellow (#FFFFCC). Note that the stroke color and the fill color are completely separate values! Setting the stroke color has no effect on the fill color, and vice versa. Other variables include graphics.lineWidth and graphics.font. The line width specifies the size of a stoke. For example, the assignment statement

graphics.lineWidth = 5;

means that subsequent strokes will be five pixels wide. The graphics.font variable sets the font that will be used when drawing text. Its value is a CSS-style font specification, which can include the font style (such as italic), the font weight (such as bold), the font size (such as 50px or 250%) and the font family (such as serif, sans-serif, or an actual font name). Some examples would be

graphics.font = "20px sans-serif";
graphics.font = "bold 250% serif";
graphics.font = "italic bold 60px monospace";

Setting the values of all these variables doesn't draw anything or change anything that has already been drawn. It just sets the value that will be used for future drawing operations, until the value is changed again. To actually draw something on the canvas, you need to call a drawing function, such as graphics.fillRect(). Many drawing functions have parameters that specify the "coordinates" to be used in the drawing operation. The canvas is made up of rows of columns of "pixels". The width of the canvas gives the number of columns of pixels. The height of the canvas gives the number of rows. A point in the canvas is specified by coordinates (x,y) where x is the number of pixels over from the left edge of the canvas and y is the number of pixels down from the top edge of the canvas. The upper left corner of the canvas has coordinates (0,0). The x-coordinate increases to the right, and the y-coordinate increases downwards. (It's OK to draw figures that lie completely or partly outside the canvas -- you will just see the part the intersects the canvas.) So, here are some of the drawing functions that you can use. Keep in mind that when you use these functions, the actual parameters that you put in the parentheses can be numbers, variables, or even complicated expressions that compute a value.

A graphics context object also contains functions for creating, stroking, and filling "paths", which can be quite complicated. Rather than explain all that, I have written some functions of my own to handle basic cases. These functions are defined in FirstDrawing.html, and you can use them in that file. For example, I have defined a function fillCircle(x,y,r) that fills in the circle with center at (x,y) and radius r. Note that this function stands on its own, not as part of the graphics context; there is no such thing as graphics.fillCircle(x,y,r)! Here are the extra drawing functions that I have provided:

Responding to Basic Events: Mouse, Keyboard, Timer

One of the major characteristics of client-side programming for the web is that it is largely event-driven. That is, the programming consists largely of saying what will happen when certain events occur. As a programmer, you don't know when or in what order the events will occur, so you can't write a step-by-step script for how the web site will be used. You have to write code that can respond to events when they happen. Most of these events are triggered by actions taken by the user, but one important type -- timer events -- are generated internally.

In general, there are two parts to writing event-handling code: You have to write a function that says what should happen when the event occurs. And you have to arrange for that function to be called in response to the event. In today's exercises, the second part is done for you. All that you have to do is fill in the definitions of the functions that say how to respond to the events.

(For certain types of events, including button-click events, things are easier: You just put the event-handling code into an attribute of an element, such as the onclick attribute of a <button> element. However, this is an "old-fashioned" kind of event programming that only works for a limited number of kinds of events. For example, mouse clicks on a canvas don't work this way.)

An event-handling function is not meant to be called by you. It is meant to be called by the web browser when a relevant event occurs. When the web browser calls an event-handling function, it sends it some information about the event. This information comes in as parameters for the function. For example, a function that handles mouse events usually needs to know the point where the mouse was clicked. A function that responds when the user presses a key on the keyboard needs to know which key was pressed. For example, you will work on a function for handling mouse-clicks on a canvas:

function mouseClickOnCanvas(x,y) {
   .
   .
   .
}

You will fill in the inside of this function to say what happens when the mouse is clicked on the canvas. In your code, you can use x and y to refer to the point where the mouse was pressed. The actual values of x and y will come from the web browser when it calls your function. (Actually, in this case, I have already manipulated the values a bit before your function gets called, to make things easier for you.)

Timer events are particularly interesting. JavaScript code can set a kind of "alarm" to go of after some specified period of time, and it can specify the function that should be called when the alarm goes off. This is done using a function called setTimeout. The last exercise of the lab uses setTimeout to run an animation. You don't have to understand how it works. You just have to write the function that says what should happen each time the alarm goes off.

Exercises

Exercise 1. For the first exercise, work in the file FirstDrawing.html. Do your work entirely inside the definition of the function draw(). Erase all the drawing commands inside that function, and replace them with commands for drawing your own picture. Try to draw a picture of something real, such as a snowman, a house, a sailboat, or a spaceship. (It will, of course, be a very cartoonish picture.) Use at least a dozen drawing commands, and use several colors. You should draw at least one string in your picture. You might want to use graphics.fillRect to draw sky and ground in different colors. This is the major exercise for the lab, and you should spend some time on it. It will count for 10 points.

Exercise 2. For the second exercise, work in the file Mouse.html. This file contains two function definitions, mouseMoveOnCanvas() and mouseClickOnCanvas(). Currently, they contain no commands. You should fill in the two function definitions to do certain drawing on the canvas. The file also contains a definition for randomColor(), which is ready for you to use. The mouseClickOnCanvas() function should simply clear the entire canvas, using either graphics.clearRect or graphics.fillRect. The mouseMouseOnCanvas() function has parameters x and y that tell you where the mouse is; it should draw some figure in a random color at the point (x,y). For example, draw a small filled-in square, or the outline of a square, or a word. This figure will be drawn over-and-over as the user moves the mouse over the canvas. You will only have to add a few lines of code to the file. This exercise counts for 2 points.

Exercise 3. For the third exercise, work in the file ArrowKeys.html. This file is set up to respond to key presses on the up-, down-, left-, and right-arrow keys, as well as on the space key. There are five functions that are called when these keys are pressed. The file also defines two variables, squareLeft and squareTop, which are meant to show the location of a small, 20-by-20-pixel, red square. The square is already drawn in its in its original position when the page is first opened. Your job is to make the arrow keys move the square, leaving a trail as it goes. Each of the arrow keys should move the location of the square up, down, left, or right -- by adjusting the value of squareLeft or squareTop -- and should then draw the square in its new location. The result will be that the square moves, but leaves a trail as it goes. For full credit, you should make the trail a different color from the moving square; to do that, you have to draw the square in its old position in a different color, then change the value of squareLeft or squareTop, then draw the square in red in its new position. Pressing the space bar should clear the picture and move the square back to its original position at the center of the canvas. This exercise counts for 4 points

Exercise 4. For the fourth exercise, work in the file Animate.html. This exercise deals with animation. It has buttons to start and stop the animation and to clear the canvas; these buttons are already implemented, and you do not have to understand how they work. When the animation is running, the function doFrame() is called over and over. There is also a mouseClickOnCanvas() function that is called when the user clicks the canvas. Currently, these two functions just make changes to a message that is displayed on the web page. You can try using the page to see how how it works, but you should delete that code before beginning work on the exercise. Your job is to fill in the definitions of the two functions, doFrame() and mouseClickOnCanvas() to create the animation that was demonstrated in class on Wednesday. You will also have to add a few variables to the script to hold some data that you need for the animation. The animation draws a series of circles growing outwards from a center point. One circle is added each time doFrame() is called. After each frame, the size of the circle increases by 2 (leaving a one-pixel gap between successive circles). The mouseClickOnCanvas() function moves the center of the circles to the point (x,y) where the user clicked the mouse, and it resets the radius of the circles to 1. It can also set graphics.strokeStyle to be a random color, although making all the circles white also produces nice results. You will have to add variables to the script to represent the center of the circles and the length of the radius. This exercise counts for 4 points.