CS 120, Fall 2012, Lab 11:
JQuery Animation (and Arrays)

In this lab, you will work on several animated web pages. This time, we're not using canvas graphics to draw the animation. Instead, we will use JavaScript to animate html elements on the page.

To begin the lab, start a new project named lab11 in Aptana Studio. Copy the contents of the directory /classes/cs120/lab11-files into your lab11 project, including the folder named snow. You will work on the files jquery-flip.html, jumpy-text.html, and let-it-snow.html. The third file is inside the folder named snow.

I have also included five completed examples that we looked at in class: click_me.html, math_courses.html, cs_courses.html, Animate.html, and AnimateWithArrays.html. You will not work on these files. They are included because it would be a good idea for you to look at and understand the scripts that they define. The last two, in particular, serve as a model for the third exercise of the lab.

Because of the test next Wednesday, this lab is not due until Monday, November 19. By that time, it should be complete and available in your Aptana Studio 3 Workspace. However, you need to understand everything on this lab before you take the test.

Introducting JQuery

This section reviews some information about JQuery that you will need for the lab. You will use JQuery in the exercises in the next two sections.

JQuery is a JavaScript library; that is, it defines some functions and utilities that you can use. To use JQuery on a web page, it has to be imported into that page with a script element such as

<script type="text/javascript" src="jquery-1.8.2.min.js"></script>

The version number, 1.8.2, will depend on what version of JQuery you are using; 1.8.2 is the latest version at this time. The <script> tag assumes that the jquery file is in the same directory as the web page. It is also possible to use a relative URL to the file in a different directory, and this can be more efficient if you are using JQuery in a number of pages throughout your site.

To use JQuery, you want to write another <script> on the page. Often, this script will use an initialization function, function init(), that contains code that needs to be executed after the complete page is ready. Typically, you would use this method to add event-handling functions to elements on the page and to adjust CSS properties or other attributes of elements. To make this function actually execute at the appropriate time, you could use <body onload="init()">. However, JQuery provides another way to get the init function executed: Just add the one-line command $(init); to the script; this is a funny JQuery idiom for saying "execute the function init when the complete document is ready." In addition to init, the script will contain variables and function definitions, as usual. For example, here is a complete script that will make any paragraph on the page move 50 pixels to the right when the paragraph is clicked with the mouse:

<script type="text/javascript">

   function init() {
      $("p").css("position","relative");
      $("p").click(jumpright);
   }
   
   $(init); // arrange for init() to be called!!
   
   function jumpright() { // event handling function.
      $(this).animate( { left: 50 } ); 
   }
</script>

Here is a table of some of the commands that you can use in your scripts, as long as JQuery has been imported into the page. Remember that the select in all these functions can be just about any CSS selector; this is one of the most powerful ideas in JQuery.

General Form Examples and Notes
$(select).css(property,value); $("#div3").css("display","none"); -- hides the element with id="div3".
$(select).click(function); $("p.clickable").click(doClickOnPar); -- installs event handler for mouse click; function doClickOnPar is called when user clicks any <p> with class="clickable"
$(select).mouseover(function); $("#btn1").mouseover(mouseOverButton); -- installs mouseover event handler on element with id="btn1"; function mouseOverButton is called when user moves mouse over it
$(select).fadeOut(time,nextFunction)
[parameters are optional]
$("#div3").fadeOut(1000,phase2); -- hide element with id="div3" by fading it to nothing over a period of 1000 milliseconds then call the function phase2.
$(select).fadeIn(time,nextFunction)
[parameters are optional]
$("#div3").fadeIn(1000,phase2); -- show element with id="div3" by fading it in over a period of 1000 milliseconds then call the function phase2.
$(select).slideUp(time,nextFunction)
[parameters are optional]
$("#div3").slideUp(1000,phase2); -- hide element with id="div3" by sliding it up over a period of 1000 milliseconds then call the function phase2.
$(select).slideDown(time,nextFunction)
[parameters are optional]
$("#div3").slideDown(1000,phase2); -- show element with id="div3" by sliding it down over a period of 1000 milliseconds then call the function phase2.
$(select).animate(properties,time,next);
[time and next are optional]
$("#img1").animate( { width: 100, height: 75 }, 1000 ); -- change the width and height of element with id="#img1" from their current values to 100,75 over a period of 100 milliseconds

Exercise 1: Animated Coin Flip

In Lab 6, you wrote a short JavaScript program for flipping a coin. In this exercise, you will create an animated version using JQuery. Open the file jquery-flip.html for editing. Note that it already imports the jquery library. You will have to write the script that comes after the line that imports the jquery library.

In your script, you should write the function that will be called when the "Flip It!" button is clicked. In addition, you must arrange for that function to be called when the button is clicked. You can do that the old way (using for example <button onclick="flipCoin()"), or the new JQuery way (using for example $("#btn").click(flipCoin) in an init function). Either way is fine. If you have any doubts that you've done it right, put an alert in your function, and check that the alert appears when the button is clicked. If your JavaScript doesn't appear to be working, remember to check the Firefox Web Developer Console to see if any error has been reported. (Reload the page if necessary to see the most recent errors.)

Next, you have to write the event-handling function and implement the coin flip. The process takes place in several phases. The sequence of phases can be implemented by using the "nextFunction" parameter in JQuery's animation functions. Remember that that optional parameter is the name of a function, and that the named function is to be called when the animation is finished. The idea of specifying a function to be called at a later time is one of the most important ideas in this lab, and you should make sure that you understand it. Here are the three phases for a simple coin flip.

  1. The first function, which is called when the button is clicked, should start the animation that fades out the current image. Also, the "Flip It!" button should be disabled.
  2. In the second-phase function, decide whether the flip is heads or tails, and set the src of the img element to be the url of the appropriate image file. Then, start the animation that fades in the image.
  3. The third phase is simply to re-enable the button

If you are more ambitious, you could add extra phases so that the current image will fade out, the question-mark image will fade in and then fade out again, and finally the image of the coin fades back in at the end.

Exercise 2: Jumpy Text

For the second JQuery exercise, you will make each of the words on a page jump out of the way when the mouse is moved over it. Open the file jumpy-text.html. This web page contains a headline and a paragraph. Each word on the page has been placed into a <span> element with class="word", so you can easily write a JQuery/CSS selector that selects all the words on the page: $(".word"). (Note: I did not type in all the tags -- I used a program to surround each word with <span class="word"> and </span>.)

In this exercise, you will be animating the location of elements. Recall that for this to work, you need to set the CSS position property of the elements to "relative". Here, you want to set the CSS position of every <span> with class="word". You can do this in either of two ways: By adding a rule to the <style> section of the page, or by using JQuery's $(...).css function. Either way is fine. If you choose the JQuery way, do it in an init function.

You also have to install an event handler on every <span> element with class="word". The event handler is a function, and you want it to be called when the user moves the mouse over the element. The only way to install the handlers easily is to use JQuery's $(...).mouseover function. Again, you should do this in the init function.

Finally, you have to write the function that will be called in response to mouseover event. As a first example, try using this function:

function mouseOverWord() {
      $(this).css("top","200px");
}

This will make the word jump to a location 200 pixels below its usual location when the mouse moves over it. (Try it!)

This example uses an important feature of JavaScript: the special variable named this. Here is the issue: The same event-handling function is attached to many elements, in fact to each word on the page. The question is, when the mouse moves over a word and the function is called, how does the function know which word it was? It has to know that, since only that word is supposed to be moved. The answer is this; this is a special variable that tells the event-handler which particular element caused the event. When used in a JQuery event handler, you can use this as a variable, and you can use $(this) as a JQuery selector, similar to $("#btn"). In this case, calling $(this).css("top","200px") modifies the particular word that the mouse was over by setting the value of the "top" property to "200px".

But what we really want here is to run an animation that makes the text move away from the mouse and then back. To do that, you have to use $(...).animate. The first parameter to this function is an object that specifies the CSS properties that you want to animate and the values that they should have at the end of the animation. The values are specified in pixels (unless you give the value as a string with a "%" or with a unit of measurement). To write the object, you can use object notation, with {...}. (It looks a lot like a CSS rule, but the items are separated with commas instead of semicolons.) Some examples of objects that might be used with $(...).animate:

{ top: 200 }

{ width: 300, height: 300 }

{ top: 0, left: 0 }

{ font-size: "200%" }

Try modifying the mouseOverWord function to use

$(this).animate( { top: 200 } );

and check out how it makes the page behave. The words end up in the same place as before, but now you can see them move.

To complete the exercise, you still have to do a few things. First, you have to animate both top and left. Second, after the words move to their new position, you want them to move back to the original position (with top and left both equal to zero). That means that you need to run another animation when the first animation completes. And third, instead of the new position being given by constant values, you want to use randomly generated values so that each word will pick a different amount to jump by. For the random values, you can use the following formula or something similar. This formula gives a random integer in the range -50 to 50:

Math.floor( 101 * Math.random() ) - 50

I encourage you to finish the exercise in a series of steps and try out the result at each step. You can get a variety of interesting effects!

Exercise 3: Introducing Arrays!

In class, we looked at two versions of an animation one without arrays and one with arrays. We discussed how the non-array version can be converted to use arrays of ten values in place of individual values. For the first lab exercise, you will do the same type of conversion with another animation. You will want to consult the source code of the sample page for help with doing the conversion.

Note that this exercise does not use JQuery!

You will work with the file let-it-snow.html, which is inside the folder named snow. (It's actually a copy of this very page, with the JQuery example script removed.) This web page shows an animation of a single snowflake falling down the page. You will convert it to show eight snowflakes instead of one snowflake. To do this, you will have to convert several variables from being single values to being arrays of eight values each. The variables are defined at the start of the <script>:

var imageElement;  // Refers to a snowflake image.
var x;  // x-coord of the upper left corner of the snowflake.
var y;  // y-coord of the upper left corner of the snowflake.
var movingLeft;  // Does x-coord increase or decrease in each frame?
var speed; // Added to the y-coord in each frame to make snowflake fall.

You need to change every reference to these variables, such as x or movingLeft, into array references, such as x[i] or movingLeft[i]. You will also have to introduce a for loops (or another kind of counting loop) at a couple of points in the program.

The variable imageElement currently refers to an <img> element with id="snow0". This variable is a little harder to handle than the others. The array version should hold references to eight different image elements with 8 different id's. The elements are already present on the web page, but you have to put references to them into the array. One way to do this is by using the array literal notation:

   imageElements = [
       document.getElementById("snow0"),
       document.getElementById("snow1"),
       document.getElementById("snow2"),
       document.getElementById("snow3"),
       document.getElementById("snow4"),
       document.getElementById("snow5"),
       document.getElementById("snow6"),
       document.getElementById("snow7")
   ];

You also have to deal with names such as imageElement.style.top. You do this in the usual way, by replacing imageElement with an array reference imageElement[i]. This looks a little funny in the long name, but it is correct: imageElement[i].style.top