Lab 8: Canvasses

Programming the Web: An Introduction

shortcut to main problems

Goals


General instructions


Console exercises

Open the JavaScript console in your Web browser (Command-Option-I). Using the browser’s JavaScript console, try these examples, in order, one at a time:

> const LEAVE_ME_ALONE = 2020;
> LEAVE_ME_ALONE
> LEAVE_ME_ALONE = 1999;

> let pair = [9, 22];
> pair[0]
> pair[1]
> pair[0] = pair[0] * 2;
> pair

Consider this little HTML canvas:

> let cvs = document.getElementById('canvas');
> cvs.width
> cvs.height = 125;
> cvs.style.backgroundColor = 'rgb(0, 200, 0)';

> let ctx = cvs.getContext('2d');
> ctx.fillStyle = 'red';
> ctx.fillRect(150, 25, 60, 30);

> ctx.clearRect(0, 0, cvs.width, cvs.height);

> ctx.beginPath();
> ctx.lineWidth = 4;
> ctx.strokeStyle = 'blue';
> ctx.moveTo(0, 0);
> ctx.lineTo(90, 10);
> ctx.lineTo(20, 30);
> ctx.stroke();

> Math.PI
> ctx.beginPath();
> ctx.fillStyle = 'yellow';
> ctx.arc(200, 40, 16, 0, Math.PI);   // use radians not degrees
> ctx.fill();

Click on this button:

> let b = document.getElementById('magic-button');
> b.disabled = true;

Click the button again.

> b.disabled = false;

Click it once again.


Main exercises

For the rest of the lab, you need to download and unzip this archive. It consists of the usual three kinds of files. You will work entirely in lab8.js, but will also want to look over lab8.html and lab8.css. You should test your work by loading (and reloading when necessary) lab8.html in your browser. (You may still find it helpful to tests parts of your work in the console.) You are encouraged to try my solution to see the tasks assigned below in action.

  1. Read over the code in lab8.js to see what global variables (and constants) have already been defined and to see what functions have been provided for you.

  2. Modify the initialize function so that when the page is loaded, the background of the canvas is set to a color of your choice. Modify the values of the constants ROWS, COLUMNS, BLOCK_HEIGHT, and BLOCK_WIDTH so that blocks are neither too small nor too large and that the overall canvas height is roughly 600 pixels wide by 400 pixels high. Test the appearance of an individual block in the top-left and bottom-right corners of your canvas using the console like this:

     > drawBlock(0, 0, 'red');
     > drawBlock(COLUMNS-1, ROWS-1, 'yellow');

    Drawing a face

  3. Complete drawSquare(x, y, length, color) so that it draws a filled square of the specified color and side length (in pixels) that is centered around canvas coordinates (x, y). That means its top-left coordinate should be half of length smaller than the given center point. Use .fillStyle and .fillRect. Test by clicking the “draw face” button which should draw a blue square in the center of the canvas.

  4. Complete drawCircle(x, y, radius, color) so that it draws a filled circle of the specified color and radius centered at canvas coordinates (x, y). Test by clicking the “draw face” button which should now also draw a purple circle to the left and above the blue square.

  5. Add code to drawFace() so that when the “draw face” button is clicked, it draws a smiling face, using another circle and a few lines, something like:


    Making it rain

  6. Complete createDrops() so that the global variable gDrops is assigned to be an array of length DROP_COUNT where each element is a pair - itself an array of length 2 of - of integers, corresponding to a random x-y point on the canvas. Use makeRandomArray (provided for you at the bottom of lab8.js) and gCanvas.height, etc. Test by clicking on the blue rain button - it should, at this point, paint a small blue circle on the canvas for each point in the gDrops array.

  7. Add code to moveRain() so that each time it is called, the y-component (second element of the two-element pair array - so access that using [1]) of the points in the gDrops array are incremented (increased by 1) so that when the drops are drawn on the canvas they appear slightly lower. Make sure the function clears the canvas before repainting it! Repeatedly clicking the “blue rain” button should give the appearance of the blue circles falling toward the bottom of the canvas. You can reload the page or click the “reset” button to reset the array of random drops.

  8. Add code to animateRain() so that it “loops” (using setTimeout) to continually call itself every FRAME_DELAY milliseconds, but only if the gRaining variable is true. This allows the reset button to stop the animation loop. Modify moveRain() so that drops that would otherwise disappear off the bottom of the canvas reappear at the top of the canvas. (Hint: in the loop, check if the y-coordinate of the drop is greater than the height of the canvas and if so, reset it to 0.)

  9. Complete disableButtons() so that it disables all the buttons on the page except the reset button. Use the enableButtons() function as a template. In the loop, you can check if the .id property of a given button is equal to the 'reset-button' to avoid disabling reset.


    256 shades of green

  10. Complete drawGreens() so that it uses the numbers in gGreens (which has already been assigned to be an array of length COLUMNS consisting of random integers ranging from 0 to 256) to paint a chain of blocks in the middle row such that the color of each block should be a shade of green based on the value of the number in the array. Use drawBlock (provided for you) to draw a block at a conceptual row and column number (i.e., not using pixel coordinates). Test by clicking (repeatedly) on the green row button.

  11. Study the supplied bubbleArray function. Then add code to animateGreens so that it repeatedly (using a setTimeout) calls bubbleArray to modify gGreens until bubbleArray returns false; each time it should call drawGreens() to repaint the row. The code should only execute if gBubbling is true. Once the implicit timer loops stops (i.e., once bubbleArray returns false), it should set gBubbling to be false and enable all the buttons on the page (by calling enableButtons). The timer should repeat every BUBBLE_DELAY milliseconds.

    Here is how bubbleArray(a) works, assuming a is an array of numbers, it considers, from the start to the end of the array, each pair of consecutive numbers in the array and if the value at the lower index is greater than the value at the next index, then the two values are exchanged in the array. This concept is called “bubbling” - as in the larger values will bubble toward the end of the array. This can be visualized on a small array like so:

     44   77   22   99   33   15
       ---
     44   77   22   99   33   15
            ---
     44   22   77   99   33   15
                 ---
     44   22   77   99   33   15
                 ---
     44   22   77   99   33   15
                      ---
     44   22   77   33   99   15
                           ---
     44   22   77   33   15   99

    You can test your code by clicking on the “green row” button. You should see each row of the green grid change (every second if you leave BUBBLE_DELAY at 1000) where the brighter greens appear, more and more, at the right side of the row.


    gravity drop

  12. Complete animateBall so that if gBallFalling is true, it uses a timer loop to continually call itself every FRAME_DELAY milliseconds until the “ball” has hit the bottom of the canvas. The ball is represented by the an x-y coordinate pair (2-element array) called gBall. The ball has a speed, gBallSpeed which indicates how much the y-component of the ball should increase (move down) each time it is redrawn. And, here, we attempt to simulate “gravity” - each time the function is called the speed should increase (i.e., the ball should accelerate) by a fixed amount (BALL_ACCELERATION). Test by clicking the “gravity drop” button.