Animation and Keyboard Events

This reading covers two separate things: animation and keyboard events.

Animation can be done with the jQuery .animate method, which is one place that jQuery exceeds raw JavaScript. (That's not literally true, since jQuery is implemented in raw JavaScript, but with animate, the added value is enormous.)

Keyboard events are another useful way to react to user input; this time, not by clicking the mouse, but by using the keyboard.

Keyboard Events

There are three keyboard events that you might potentially be interested in:

  1. keydown
  2. keyup
  3. keypress

The first two are events tied to the physical key going up and down (e.g. the shift key). The last is only for real characters, not modifiers like shift or control. The keypress event is officially deprecated in favor of device-independent events, but it's likely to be supported for a long time. (deprecated is jargon in the computer science community meaning that, even though a feature exists, you should not use it.)

We will use keyup.

The event listener is invoked with an event object, and that object will contain a code property that is the number of that key on the keyboard. For more detail, see KeyboardEvent.code

Note that the code for a key is not the same as the code for a character. So, for example, the "a" key has the same code whether the "shift" key is up or down. If you care about "a" versus "A"; you want the key property instead. See KeyboardEvent.key

To add a keyup event handler using jQuery, we can do the following:

$(document).on('keyup', function (eventObj) {
    console.log(eventObj.code);
}

Note. The .code property was added to jQuery in version 3, so when you load jQuery, use something like this:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Doing that ensures that the jQuery event object includes the ".code" property. If you copy the template-jq file, you'll get version 3 of jQuery.

In particular, I've added the following keyup handler to this page, so you can open the JS console, type a few keys, and see the results. Try WASD, since you'll use those keys in the assignment. You can also try the four arrow keys. The event handler prints three properties of the jQuery event object: code, key and which. The last is something that jQuery created to be consistent across all browsers. Open the JS console and try some keys, including shift keys, control keys, arrow keys and regular character keys (a-z).

Note that when you first open the JS console, keystrokes go to the console (understandably), so you need to click on the browser window in order to focus that window and get the event handler to work.

$(document).on('keyup', function (eventObj) {
    eventObj.preventDefault();
    eventObj.stopPropagation();
    console.log('code:', eventObj.code, 
                'key:',eventObj.key, 
                'which:', eventObj.which);
});

You've probably also noticed that the keyup event handler is added to document, rather than to some particular element. That's standard practice.

You can ignore the stopPropagation() method for now; we will talk about it later in the course.

jQuery Animations

jQuery provides an easy way to do animations that is compatible with older browsers, since the animations are done by jQuery. You can read the details here: jQuery animate() method (optional).

The animate method is very easy to use, but first let's see it in action. Try clicking on the following box. You can click it again (and again) to re-run the animation.

Now is the winter of our discontent...

Essentially, the animation effect is to successively (frame by frame) change the height and font-size CSS properties from their initial values (height:50px and font-size:10px) to their final values (height:200px and font-size:20px).

So, let's see how the JQ code does that. Here's the complete code; we'll break it down afterward.

$("#box1")
    .one()
    .click(function () {
        $("#box1")
             .one()
             .css({height: "50px", "font-size": "10px"})
             .animate({height: "200px", "font-size": "20px"},
                      2000);
        });

Now let's break that down. The click handler is the following function:

    function () {
        $("#box1")
             .one()
             .css({height: "50px", "font-size": "10px"})
             .animate({height: "200px", "font-size": "20px"},
                      2000);
        }

Almost all of it is a sequence of two operations on the element #box1, the .css() method and the .animate() method.

The first operation is to reset two CSS property-value pairs to some initial values. This happens instantly. (Not that it takes zero time, but the effect is not stretched over time like an animation is.) The argument to the .css method is a JS object literal that is a collection of CSS property-value pairs.

             .css({height: "50px", "font-size": "10px"})

(The font-size property has to be in quotation marks because it has a hyphen in the name of the property. The quotation marks are optional for height, because it works as a JS identifier, but I could have used them.)

The second operation, namely the .animate() method, is to gradually change those values to their final values. The gradual changes take 2000 milliseconds (2 seconds). That uses the JQ .animate method. The .animate() method's first argument is a JS object literal that contains a collection of target CSS values, just like the .css() method. The second argument says how many milliseconds it should take to achieve that change.

             .animate({height: "200px", "font-size": "20px"},
                      2000);

Note that I could have specified the initial CSS using CSS style rules instead of JQ's .css() method, but I like using the same medium for specifying both the starting and ending values. It also makes it easy to re-run the animation as many times as you want.

Animate and CSS

I want to emphasize that it is not necessary to precede the .animate() method with the .css() method. I did that for the demo above so that you can re-run it as many times as you want, with just a single button. We could instead separate things and have two buttons:

Turned glorious summer...

Here's the HTML for the second demo:

<div id="box2" class="box">Turned glorious summer...</div>
<button id="run2">run animation</button>
<button id="reset2">reset</button>

and the CSS:

.box {
    border: 1px solid blue;
    background-color: #ccccff;
    width: 30%;
    height: 50px;
    font-size: 10px;
}

and the JS:

$("#run2")
    .one()
    .click( () => $("#box2").one().animate({height: "200px", "font-size": "20px"}, 2000));
$("#reset2")
    .one()
    .click( () => $("#box2").one().css({height: "50px", "font-size": "10px"}));

What Can be Animated

Note that we animated height and font-size, both of which are measured by single numbers. Any CSS property that can be measured by a single number ("linear" properties) is easy to animate using jQuery.

Other properties cannot be easily animated. For example, how would you animate a solid line turning into a dotted line? How about Times New Roman turning into Verdana? What about purple turning into green? While it's possible that you can come up with an algorithm (and some people have), those kinds of properties can't be animated in jQuery without additional code.

Modifying a Value

In JavaScript, Python and most modern languages, there is an update assignment operator that allows you to modify a variable up or down by some amount. For example, in JavaScript:

x += 200;  // increase by 200
y -= 100;  // decrease by 100

By analogy, jQuery's animate method allows you to increase or decrease a linear property by some amount. (That gives us a different way to specify the target value, or the amount of change.) The above example increased the width from 50px to 200px, an increase of 150px. Similarly, it increased the font size from 10px to 20px, an increase of 10px. The following code using += is equivalent (there's also a -= operator). Note that the "value" is a string that includes the operator as well as the amount.

$("#box2")
    .one()
    .click(function () {
        $("#box2")
             .one()
             .css({height: "50px", "font-size": "10px"})
             .animate({height: "+=150px", "font-size": "+=10px"},
                      2000);
        });

Here it is in action:

This is box2, where ... Now is the winter of our discontent...

This is a useful trick in several assignments.