PencilCoder

Teacher's Guide: Mouse Events

Overview

This third lesson on user-interface-related events focuses on mouse clicks and moves, the latter of which includes several variants such as mouseup/mousedown and mouseenter/mouseleave. Aside from introducing these new event types, this lesson aims to provide students a deeper overall understanding of events—in particular, that all user-interface (UI) events emanate from, and therefore are are associated with, specific elements of the HTML web page. Students will also learn to harness the event object target property, which identifies information about the page element on which the event emanates. The lesson illustrates how to use jQuery to add event listeners to sets of elements identified using jQuery selectors; it leverages this feature both to build on previous lessons' work with jQuery and to coach students to write more generalized event handlers.

More about the lesson

Keyboard- and mouse-related events take place in the HTML document object model (DOM)—i.e., in the web page. We incoporate event into our scripts by setting up DOM elements to accept (i.e., "listen for") events, and to execute event handlers each time the event fires.

An important aspect of this lesson on mouse-related events is that students are more likely to make more explicit connections between events and the DOM, through sprite-specific calls to event handlers such as turtle.click (attach a listener to the <canvas> element underlying the default turtle) or $(".turtle").click (i.e., attach a listener to all such <canvas> elements). As noted in the lesson, calls to click are equivalent to window.click, which sets up an event listener with the entire html document.

Contrast these calls to click to prior use of the keyboard method, which is likewise an alias, for window.keyboard. Use of that alias was convenient shortcut for the purposes of that lesson, but it obscures the fact that the call to the keyboard event binding function is attaching the listener to the entire html document, rather than a specific element or group of elements in that document.

The idea that events are linked to a specific element or even collection of page elements is intuitive. Slightly more challenging is the need to write callbacks for listeners for these page elements, espcially when working with collections of page elements. For example, begin by considering the task of assigning a click event listener to a single sprite s. If the goal is to make that specific sprite change colors and move in a random direction, a potential solution might look like this:

sClickHandler = () ->
  s.wear random(color)
  s.rt random(360)
  s.fd 100

s.click sClickHandler

This solution is straightforward and effective. However, the definition of the event handler lacks generality—it only works for sprite s. A more generalized solution is to make use of the target property of the event object, as introduced in the lesson. The script then becomes:

anySpriteClickHandler = (e) ->
  t = $(e.target)
  t.wear random(color)
  t.rt random(360)
  t.fd 100

s.click anySpriteClickHander

The key differences in the script are including an explicit argument for the event object, e, and then accessing e.target within the body of the callback. Note that e.target is a plain javascript reference the html page element, not to a jQuery object. As students learned in Calling All $(".turtle")s!, passing the page element reference to the jQuery function (typically coding with its convenient alias, $) yields a jQuery object which, short of not having class property "turtle", is a full-fledged Pencil Code sprite.

This more generalized event handler definition is now also perfectly suited for working with collections of sprites. The following statement assigns the handler to every page element with class turtle, i.e., every sprite:

$(".turtle").click anySpriteClickHandler

Different types of events give rise to different types of event objects. For example, keyboard-related events pass a KeyboardEvent to the event handler, click events pass a PointerEvent, and most other mouse-related events (mousemove, mouseover, etc.) pass a MouseEvent object. Each of these event object types has some features specific to that specific type of event, such as the key and keyCode for keyboard events and screen coordinate properties pageX and pageY for mouse-related events. The Pencil Code variants of the jQuery event binding functions also add center-based coordinate properties x and y to mouse-related event objects.

Though they have their differences, most properties of UI-related events are shared by all event objects. These properties are captured in the Event interface, an object that specifies the minimum features that each event type should have, and which all other event types are based on. One such property of the Event interface is the timeStamp property, first encountered in the Event Objects! lesson. timeStamp provides the number of milliseconds since the program started running. The boolean values shiftKey, altKey, and so on are also properties of Event, as is the target property, which provides a reference to the html element to which the event was originally dispatched. Several additional properties and methods of the Event interface will be discussed later in these notes.

Additional mouse-related events

The lesson highlights the click event and introduces the mousemove event in the activities. Several additional mouse-related events are explored in the Additional Activites of this document. Their use and behavior is similiar to that of click and mousemove events, i.e., set up event listeners using an event binding method of the same name, e.g., turtle.mousemove mouseMoveCB. These events include the following (click the relevant hyperlink for a simple illustration):

mousemove fires with every move of the mouse
mouseenter fires when mouse pointer enters (comes over) the target element
mouseleave fires when mouse pointer leaves (stops being over) the target element
mousedown fires when the mouse button is clicked on the target element
mouseup fires when the click is released over the target element (though it will not fire if the mouse has been moved off the target element prior to release)

Notes to activities

As noted in prior lessons, when working with events it is often a good idea to set speed Infinity. While this raises some other design challenges, such as timing sprite movements and producing smooth animations, it prevents lags between when the event occurs and what you see on the screen. For example, consider this simple program that uses events to instruct the turtle to move forward 25 when clicked and to turn in the direction of mouse clicks on other parts of the scrren. At default speed, the user might build up a queue of multiple movements and turns before the turtle completes its first animation. (In a future lessons, we will turn to forever which will allow us to approach this a bit more effectively. It still involves events, but we will rely on a technique called event polling.)

The instructions for the Hopper program are designed to encourage students to develop good habits. True, because the callback references a single, identified sprite, it is possible to code a solution which does not rely on e.target; moreover, since it is the default turtle, one need not even explicity reference the sprite using dot notation. Don't let students take these shortcuts! If nothing else, movitivate them to write more generalized code in order to facilitate coding the more involved Hoppers activity.

Additional activities

  • Use the mousemove event binding function in a MouseStatus program that prints the current location of the mouse to a label in the center of the screen.
  • Write a TurtleDragger script that allows you to use the mouse to select a sprite and drag it to another location on the screen. You will likely need to use the mousemove, mousedown and mouseup event binding functions.
  • AnnoyingFly: [add HREF] Enhance your MovingEyes program by adding a sprite, wearing the image of a fly, which moves with the curser movement—so the eyes follow the fly. An important part of this challenge is to make the fly's movement look realistic; you will need to come up with an algorithm based on changes in the location of the cursor resulting from subsequent mouse moves.
  • Write a script that turns the default turtle into a Magic Marker: Turn the turtle into a pen that draws varying colors as it moves to new positions around the screen. You will need to devise an algorithm that changes the input values for the rgb (or hsl) function based on the turtle's position on the screen. Use events to make the turtle move with the location of the mouse. Consider using not only mousemove, but also mousedown and mouseup event binding functions, so that the pen only writes when the mouse button is held down. Then draw yourself a nice picture!
  • ColorPicker:
  • SensitiveHopper: copy and modify your Hopper program so that the sprite jumps further the longer the mouse click is held down. Additionally, make the mouse move towards the location of the pointer when the mouse click is released (which can be anywhere on the page, not necessarily over the sprite).
  • MultipleGuess: [ADD HREF] create a multiple choice test, comprised of (say) 5 questions and 5 matching answers. Add the questions and answers to the screen in two columns using appropriately positioned <label> elements. Use mouse-related events to allow the test-taker to drag answers on to the questions. Give real-time feedback on how well they are doing!
  • Whack-a-Turtle: [ADD HREF]
  • HerdingTurtles:
  • MouseMaze: Code a
  • Bezier: [add HREF]

Beyond the lesson

Deepr look at events...

A complete understanding of events requires thinking in terms of the HTML document object model, or DOM. The DOM is a need to think ... Because of event bubbling, click on any element on the page causes allCB

(The event actually starts at the highest level, cascading)??) through the hierarchy, untils it reaches the specific item that was clicked (the target). Then HTML events fire, sequentially from the inside out as the event "propagates"/bubbles up the hierarchy , for every element in the hierarchy, up to HTML.

e.stopPropagation(): We can prevent events from propagating up the HTML DOM by calling the event object's stopPropagation method, e.g., e.stopPropagation() ... . AN example in https://hacker.pencilcode.net/edit/36-MouseEvents/Notes_Speed.... eventPhase tells use where we are in the (capture??? and) propagation process: capture, at_target, bubbling

THE EXAMPLE Notes_Focus (Keyboard events folder?) INCLUDES A LITTLE EXPLORATION OF PROPAGATION; several programs in MouseEvents also contend with this... clickablesprites

MDN Notes about stopPropagation

The majority of browser events bubble, or propagate, from the deepest, innermost element (the event target) in the document where they occur all the way up to the body and the document element.

The third arg is false by default... (is this correct? perhaps only in Pencil Code?)

document.addEventListener('keydown', eventHandlerCallback, false);

preventDefault: simple example of down/up illustrates a use... without, the mouse down (and held down) then starts selecting elements by default (https://hacker.pencilcode.net/edit/36-MouseEvents/MouseEtc/DownUp)

additional properties of event interface (linked from above): [type (name identifying the type of the event), eventPhase (tells where the event... capture, at_target, or bubbling)

This w3schools reference for HTML MouseEvent properties lists the properties of the MouseEvent. Note that this does not line up directly with the jQuery MouseEvent object, as jQuery manipulates this source data in its effort to make the event device independent. However, these are directly accessible in the jQuery event object's originalEvent property. Additionally, Pencil Code adds some additional properties, such as x and y, which are center-based variants of the coordinates provided by the standard jQuery object.

The target property of the event object is always a reference to the element that the event occurred upon. see in https://hacker.pencilcode.net/edit/36-MouseEvents/Notes_DocFlipper2; note when you click on a turtle, the target is canvas but it doesn't seem to fire an event... I think the HTML element doesn't actually fire, but whatever contains it (i.e., BODY). But it basically works out the same b/c if you attach listener to CANVAS it seems to behave as if you added to

And alternative to e.target is this... We will discuss this in a later lesson(?) about context of a function(??)

add a section on coordinates...

clientX and clientY are pretty interesting... it's the coords while over the target element Coordinates: clientX/Y, pageX/Y (VS x,y)

inspecting page elements / more about html

ONe of the difficult things for students at this point is that there is so much access to additional content apart from the main thrust of the lesson. It can be hard for students to know what the elements types are when using jQuery selector. It is intuitive that label generates <label> elements, but less intuitive is that write creates <label> elements. But even with <label> elements, at least in the development view of Pencil Code, it is useful to distinguish between labels created with label and <label> elements that can comprise much of the test panel pane. Thankfully, Pencil Code adds a the class turtlelabel to those created with label, which enables us to easily select the right subset..

Encourage students to explore elements in their Pencil Code environment. They will likely find the script in this PageElementInspector program useful:

click (e)->
  see "- - - - - - - - - - - - - - - - -"
  see "target: "
  see e.target
  see "element type: " + e.target.tagName
  see "class: " + e.target.className
  see "id: " + e.target.id
  see "style: "
  see e.target.style
  see "- - - - - - - - - - - - - - - - -"

Additional mouse-related events

There are many other mouse-related events beyond those described in this document (and many other events overall, as evidenced by even a quick glance at this extensive listing from w3schools). Additional events are beyond the scope of the PencilCoder curriculum.

The primary challenge to using these events is that most are not supported by jQuery, so students would need to use the raw JavaScript addEventListener. The following simple examples (using pure JavaScript and HTML unless noted) are provided for illustration:

Reminder: in the Pencil Code development environment, the HTML will load automatically, but not the scripts. Don't forget to run each program so that the scripts execute!

Touch

Touch events fire when the state of contacts with a touch-sensitive surface (touch screen, track pad) change. Given the modern-world prevalence of touch devices, it is natural for students to be interested in exploring adding touch functionality to their programs. However, working with these events is complicated by a number of factors.

Cross-browser differences in JavaScript's treatment of touch events make using jQuery essential. However, touch features are not included in core jQuery. Instead, they are included in the jQueryMobile API. Complicating matters futher, jQueryMobile touch event use requires some additional coding loop-de-loops that make them tricky to work with in the Pencil Code environment. For additional details, see the jQueryMobile API events documenation.

Additional Resources

MDN web docs provides this gentle introduction to events, illustrated with raw JavaScript and HTML.

What can go wrong

Mistakes with jQuery element-selector syntax is likely to be an ongoing source of student coding bugs. These can be especially confusing because the error can easily be misattrubed to event handlers, rather than to the identification of the element or collection of elements to which that event handler is bound. Be on the lookout for syntactical errors such as invoking $('turtle').click or $('.turtles').click rather than $('.turtle').click.

Technicalities

Technicalities: Alternatives to event binding functions

Applying to many objects

using event listeners (Rather than assigning the event handler property/HTML attribute) lets us associate many events handlers to the same DOM. And if we use on and a named function, we can subsequently use off

But jQuery facilititates adding the same handler to multiple page elements referenced in a single jQuery collection. BEYOND THE LESSON: Then we can use .each method, a convenient function that lets us specif

Event handler properties

THE FOLLOWING IS A CONTINUATION OF A DISCUSSION IN "jQuery vs. JavaScript key event bindings" from Notes to Event Objects, IN WICH onkeydown was discussed. Here, we take it futher, specifically noting that we can access these properties directly in JS....

Here's what's relevent in this context...:

?
onclick         The user clicks an HTML element
onmouseover	The user moves the mouse over an HTML element
onmouseout	The user moves the mouse away from an HTML element

In Pencil Code, and in this curriculum, we typically don't write much in the way of HTML. And when we do, it is typcially just for that content. Thus, not much emphasis has been put on writing "unobtrusive javascript". This recommended approach to incorporating JavaScript in web pages dictates that we should separate the structure and content of a web page (HTML) from the presentation (CSS) and behavior (JavaScript). Unobtrusive javascript is facilitated by modern variants of the JavaScript language.

However, it continues to be possible to add JavaScript to pages in the HTML code. In the case of buttons,

<button onclick="dot(magenta,50);rt(90);">magenta</button>

This onclick attribute establishes the 34nt hanl. This is a simple example, involving only two JavaScript function calls, though we could add as many as we want.

"The earliest method of registering event handlers found on the Web involved event handler HTML attributes (or inline event handlers) like the one shown above — the attribute value is literally the JavaScript code you want to run when the event occurs. The above example invokes a function defined inside a script element on the same page, but you could also insert JavaScript directly inside the attribute, for example:

pre>

"You can find HTML attribute equivalents for many of the event handler properties; however, you shouldn't use these — they are considered bad practice. It might seem easy to use an event handler attribute if you are doing something really quick, but they quickly become unmanageable and inefficient.

For a start, it is not a good idea to mix up your HTML and your JavaScript, as it becomes hard to read. Keeping your JavaScript separate is a good practice, and if it is in a separate file you can apply it to multiple HTML documents.

Even in a single file, inline event handlers are not a good idea. One button is OK, but what if you had 100 buttons? You'd have to add 100 attributes to the file; it would quickly turn into a maintenance nightmare. With JavaScript, you could easily add an event handler function to all the buttons on the page no matter how many there were, using something like this:

Finally, many common server configurations will disallow inline JavaScript, as a security measure.

You should never use the HTML event handler attributes — those are outdated, and using them is bad practice

We can access the onclick attribute in JavaScript as a property of the page element. The code gets a little involved, but in short we can set the handler directly, rather than using a method of page element objects (e.g., addEventListener, in pure JavaScript) or of a jQuery object (click or on).

this script provides a detailed exploration...

The drawback to assigning the event handler directly is that you can only add one per page element, whereas with listeners you can add as many as you'd like.

We