Chapter 10

Handling Touch Interactions and Events

WHAT YOU WILL LEARN IN THIS CHAPTER:

  • How to respond to basic touch events
  • How to respond to orientation event changes
  • How to customize key events

An essential part of any web application is the ability to respond to events triggered by the user or by a condition that occurs on the client: the clicking of a button, the pressing of a key, the scrolling of a window. Although the user interacts with an HTML element, the entire document, or the browser window, JavaScript serves as the watchful eye behind the scenes that monitors all of this activity taking place and fires off events as they occur.

With its touch interface, iPhone and iPad devices are all about direct interactivity with the user. As a result, it is not surprising that any IOS web app you create can handle the variety of gestures — finger taps, flicks, swipes, and pinches — that a user naturally performs as they interact with your app on their mobile device.

THREE TYPES OF TOUCH EVENTS

There are three primary types of touch-related events to consider when developing an IOS web app:

  • Mouse emulation events: Events in which a one- or two-finger action simulates a mouse.
  • Touch events: Events that dispatch when one or more fingers touch the screen. You can trap touch events and work with multiple finger touches that occur at different points on the screen at the same time.
  • Gesture events: Gesture events are combinations of touch events that also support scaling and rotation information.

The mouse emulation events are the ones that you’ll likely be working with for most typical interactions inside your web app. I begin with exploring the mouse emulation events and then later move on to talking about the multitouch and gesture events.

MOUSE-EMULATION EVENTS

When working with touch interactions and events for IOS devices, keep in mind that several of the gestures that a user performs are designed to emulate mouse events. At the same time, I need to make one thing very clear: The finger is not the same as a mouse. As a result, the traditional event model that web developers are so used to working with on desktop computers does not always apply as you may expect in this new context. The new ground rules are described in the following sections.

Many Events Handled by Default

By default, many of the events are handled automatically by IOS and Safari on IOS. As a result, you do not need to write any code to handle the basic touch interactions of the user. Flick-scrolling, zoom pinching and unpinching, and one-finger panning (or scrolling) are those sorts of user inputs that come free, so to speak. You can, however, trap for many of these events with touch or gesture events.

Conditional Events

The way in which Safari events are handled depends on two key variables:

  • Number of fingers: Different events fire depending upon whether a one-finger or two-finger gesture is performed. Tables 10-1 and 10-2 list the common IOS one- and two-finger gestures and the ability to trap these events.

    TABLE 10-1: One-Finger Gestures

    GESTURE EVENT(S) FIRED DESCRIPTION
    Panning onscroll fired when gesture ends No events triggered until user stops panning motion.
    Touch and hold None Some native iPhone apps support this gesture. For example, touch and hold on an image displays a Save dialog.
    Double-tap None
    Tap Clickable element: mouseover, mousemove, mousedown, mouseup, click
    Non-clickable element: None
    If mouseover or mousemove changes page content then the remaining events in the sequence are canceled.

    TABLE 10-2: Two-Finger Gestures

    GESTURE EVENT(S) FIRED DESCRIPTION
    Pinch/unpinch zoom None The gesture used to zoom and unzoom on a web page or image.
    Two-finger panning Scrollable element: mouseevent
    Non-scrollable element: None
    If it’s a non-scrollable element, then the event is treated as a page-level scroll (which fires an onscroll when the gesture stops).
  • Event target: Events are also handled differently depending upon the HTML element being selected. In particular, the event flow varies depending on whether the target element is clickable or scrollable. A clickable target is one that supports standard mouse events (for example, mousemove, mousedown, mouseup, click), whereas a scrollable target is one equipped to deal with overflow, scrollbars, and so on. (However, as I’ll discuss later in the chapter, you can make any element clickable by registering an event handler for it.)

Mouse Events: Think “Click,” Not “Move”

The general rule of thumb for iPhone event handling is that no events trigger until the user’s finger leaves the touch screen. As a result, the normal flow of mouse events is radically altered over the traditional browser event model because mouse events now depend on the actual selection (or clicking) of an element, not simply when a finger passes over it. Said differently, the focus or selection of an element is what matters, not the movement of the mouse.

Take the example of a page that consists of two links, Link A and Link B. Suppose a user glides his finger from Link A, passes over top the Link B, and then clicks on Link B. Here’s how the events are handled:

  • The mouseover, mousemove, mousedown event handlers of B are fired only after a mouseup event occurs (but before mouseup is triggered). As a result, from a practical standpoint, these preliminary mouse events are rendered useless.
  • Because you can’t perform a mousedown and mouseup without a click, they all refer to the same event.
  • The mouseout event of A is fired only after the user clicks on B, not when the finger moved off A itself.
  • The CSS pseudo-style :hover is applied to B only when the user selects it and is removed from A only when B is actually selected, not before.

Therefore, for most purposes, you should design your app to respond to click events rather than the other mouse events.

Click-Enabling Elements

If the element you are working with is not considered “clickable” by Safari on IOS then all mouse-related events for it are ignored. However, there are certain situations in which this can be problematic, such as if you are using span or div elements in a cascading menu and want to change the menu display based on the context of the user.

To override Safari’s default behavior, you need to force the element to be considered “clickable” by Safari on IOS. To do so, you assign an empty click handler to the element (click="void(0)"). For example:

<span mousemove="displayMenu(event)" click="void(0)">Run Lola Run</span>

After you add the empty click handler, the other mouse-related events begin to fire.

Event Flow

Besides the anomaly of the timing of the mousedown event, the rest of the supported mouse and key events fire in Safari on IOS in the same sequence as a standard web browser. Table 10-3 shows the event sequences that occur when both a block-level element and a form element are clicked. The form element column also displays the order of key events if the user types in the on-screen keyboard.

TABLE 10-3: Event Sequencing

CLICKABLE BLOCK-LEVEL ELEMENTS (E.G., LINK) FORM ELEMENT (E.G., TEXTAREA, INPUT)
mouseover mouseover
mousedown mousedown
mouseup focus
click mouseup
mouseout (only after the next element receives focus) click
     keydown
     keypress
     keyup
     change
blur (only after the next element receives focus)
mouseout (only after the next element receives focus)

Unsupported Events

You cannot trap for all events inside of Safari on IOS. For example, you cannot trap for events associated with a user switching between pages in Safari. The focus and blur events of the window object are not triggered when the focus moves off or on a page. Additionally, when another page becomes the active page, JavaScript events (including polling events created with setInterval()) are not fired. However, the unload event of the window object is triggered when the user loads a new page in the current window.

Table 10-4 lists the events that are fully supported and unsupported.

TABLE 10-4: Event Compatibility

SUPPORTED EVENTS UNSUPPORTED EVENTS
click cut
mouseout* copy
mouseover* paste
mouseup* drag
mousedown* drop
mouseout* dblclick
blur selection
change formfield.onmouseenter
focus formfield.onmouseleave
load formfield.onmousemove
unload formfield.onselect
reset contextmenu
mousewheel error
submit resize
abort scroll
orientationchange
touchstart
touchmove
touchend
touchcancel
gesturestart
gesturechange
gestureend

*Different behavior than in a desktop browser. (See the “Mouse Events: Think ‘Click,’ Not ‘Move’” section earlier in this chapter.)

TOUCH EVENTS

In addition to the mouse-emulation events, Safari on IOS also captures additional touch-related sequences of events for each finger that touches the screen surface. A touch event begins when a finger touches the screen surface, continues when the finger moves, and ends when the finger leaves it. The four touch events are shown in Table 10-5.

TABLE 10-5: Touch Events

EVENT DESCRIPTION
touchstart Fires when a finger touches the screen surface
touchmove Fires when the same finger moves across the surface
touchend Fires when a finger leaves the surface of the screen
touchcancel Fires when the touch is cancelled by the operating system

Each of these touch events have properties that enable you to get information about the touch:

  • event.touches returns an array of all of the touches on a page. For example, if there were four fingers on the surface, then the touches property would return four Touch objects.
  • event.targetTouches returns just the touches that were started from the same element on a page.
  • event.changedTouches returns all of the touches involved in the event.

The information contained in each of these properties varies depending on what multitouch event is performed. Table 10-6 shows several example scenarios.

Table 10-6: Touch Scenarios

image

The items inside these arrays are Touch objects (shown in Table 10-7) that provide the information related to the touch events.

TABLE 10-7: Touch Object Properties

PROPERTY DESCRIPTION
clientX x coordinate of the object relative to the full viewport (not including scroll offset)
clientY y coordinate relative to the full viewport (not including scroll offset)
identifier Unique integer of the touch event
pageX x coordinate relative to the page
pageY y coordinate relative to the page
screenX x coordinate relative to the screen
screenY y coordinate relative to the screen
target Originating element (node) that dispatched the touch event

Unlike mouse-emulated events, you can trap for multiple touches to occur on screen at the same time and then have your app respond to them.

For example, if you want to do a test to determine how these events are fired, you could add event handlers and then take different actions when these events occur. Here’s the JavaScript code:

function init()
{
document.addEventListener("touchstart", touchEventHandler, false);
document.addEventListener("touchmove", touchEventHandler, false);
document.addEventListener("touchcancel", touchEventHandler, false);
document.addEventListener("touchend", touchEventHandler, false);
}
 
function touchEventHandler(event)
{
    // Gather basic touch info
    var numTouch = event.touches.length;
    var numTargetTouches = event.targetTouches.length;
    var numChangedTouches = event.changedTouches.length;
 
    // Get first touch object
if (numTouch > 0)
    {
var touchObj = event.touches[0];
        var x = touchObj.screenX;
        var y = touchObj.screenY;
    }
 
    if (event.type == "touchstart")
    {
        // do something to begin
    }
    else if (event.type == "touchmove")
    {
        // do something on move
    }
    else if (event.type == "touchend")
    {
        // do something to end
    }
    else
    {
        // do something when cancelled
    }
}

GESTURE EVENTS

During a multitouch sequence, touch events are dispatched through touchstart, touchmove, touchend, and touchcancel. However, Safari on IOS also dispatches gesture events when multiple fingers are touching the surface of the screen. The three gesture events are shown in Table 10-8.

TABLE 10-8: Gesture Events

EVENT DESCRIPTION
gesturestart Fires when two or more fingers touch the screen surface
gesturechange Fires when the these fingers move across the surface or perform another change
gestureend Fires when one of the fingers involved in the gesture leaves the surface of the screen

The two key properties associated with gesture events are the following:

  • scale returns the multiplier of the pinch or push since the gesture started. (1.0 is the baseline value.)
  • rotation returns the rotation value since the gesture began.

DETECTING AN ORIENTATION CHANGE

One of the unique events that an iPhone web application developer needs to be able to trap for is the change between vertical and horizontal orientation. Safari on IOS provides support for the orientationchange event handler of the window object. This event is triggered each time the device is rotated by the user.

TRY IT OUT: Detecting an Orientation Change

For a demonstration of how to detect an orientation change in your app, follow the steps below.

1. Create the following HTML document in your text editor and then save the document as BIDHJ-Ch10-Ex2.html.

image
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Orientation Change Example</title>
<meta name="viewport" content="width=320; initial-scale=1.0;
   maximum-scale=1.0; user-scalable=0;">
</head>
<body onload="orientationChangeHandler();"
  onorientationchange="orientationChangeHandler();">
<h4 id="mode">Ras sed nibh.</h4>
<p>
Donec semper lorem ac dolor ornare interdum. Praesent condimentum.
Suspendisse lacinia interdum augue. Nunc venenatis ipsum sed ligula.
Aenean vitae lacus. Sed sit amet neque. Vestibulum ante ipsum primis
in faucibus orci luctus et ultrices posuere cubilia Curae; Duis
laoreet lorem quis nulla. Curabitur enim erat, gravida ac,
posuere sed, nonummy in, tortor. Donec id orci id lectus
convallis egestas. Duis ut dui. Aliquam dignissim dictum metus.
</p>
</body>
</html>

Code snippet BIDHJ-Ch10-Ex2.html

2. Add the following script code in the document head and then save the file:

image
<script type="application/x-javascript">
 
    function orientationChangeHandler()
    {
      var str = "Orientation: ";
      switch(window.orientation)
      {
          case 0:
              str += "Portrait";
          break;
 
          case -90:
              str += "Landscape (right, screen turned clockwise)";
          break;
 
          case 90:
              str += "Landscape (left, screen turned counterclockwise)";
          break;
 
          case 180:
            str += "Portrait (upside-down portrait)";
          break;
      }
      document.getElementById("mode").innerHTML = str;
     }
 
</script>

Code snippet BIDHJ-Ch10-Ex2.html

How It Works

An onorientationchange attribute is added to the body element and assigned the JavaScript function orientationChangeHandler(). The orientationChangehandler() function evaluates the window.orientation property to determine the current state: 0 (Portrait), -90 (Landscape, clockwise), 90 (Landscape counterclockwise), or 180 (Portrait, upside down). The current state string is then output to the document. Figure 10-1 shows the result in Portrait mode, and Figure 10-2 shows the page displayed in Landscape mode.

However, note that the onorientationchange event is not triggered when the document loads. Therefore, in order to evaluate the document orientation at this time, assign the orientationChangeHandler() function to the onload event.

Changing a Style Sheet When Orientation Changes

The most common procedure in which you will use an onorientationchange event is to specify a style sheet based on the current viewport orientation. To do so, you can expand upon the previous orientationChangeHandler() function by updating the orient attribute of the body element based on the current orientation and then updating the active CSS styles off of that attribute value.

TRY IT OUT: Changing a Style Sheet When Orientation Changes

For a demonstration of how to change a style sheet when the orientation changes in your app, use the following steps.

1. Create the following HTML document in your text editor and then save the document as BIDHJ-Ch10-Ex3.html.

image
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>orientationChange: Change CSS Stylesheet</title>
<meta name="viewport" content="width=320; initial-scale=1.0;
  maximum-scale=1.0; user-scalable=0;">
 
</head>
 
<body>
    <div id="canvasMain" class="container">
        <div class="toolbar anchorTop">
            <div class="main">
                <div class="header">AppTop</div>
            </div>
        </div>
        <div class="center">
    <p>Orientation mode:<span id="iMode"></span></p>
        <p>Width:<span id="iWidth"></span></p>
        <p>Height:<span id="iHeight"></span></p>
        <p>Bottom toolbar height:<span id="iToolbarHeight"></span></p>
        <p>Bottom toolbar top:<span id="iToolbarTop"></span></p>
        </div>
        <div id="bottomToolbar" class="toolbar anchorBottom">
            <div class="main">
                <div class="header">
                    AppBottom
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Code snippet BIDHJ-Ch10-Ex3.html

2. Add the following style code inside the document head:

image
Insert IconMargin  [download]
    <!-- Portions based on iUI -->
<style type="text/css" media="screen">
 
    body {
        margin: 0;
        padding: 0;
        width: 320px;
        height: 416px;
        font-family: Helvetica;
        -webkit-user-select: none;
        cursor: default;
        -webkit-text-size-adjust: none;
        background: #000000;
        color: #FFFFFF;
    }
  
    .container {
        position: absolute;
        width: 100%;
    }
  
    .toolbar {
        position: absolute;
        width: 100%;
        height: 60px;
        font-size: 28pt;
    }
  
    .anchorTop {
        top: 0;
    }
  
    .anchorBottom {
        bottom: 0;
    }
  
    .center {
        position: absolute;
        top: 60px;
        bottom: 60px;
    }
  
  
    .main {
        overflow: hidden;
        position: relative;
    }
  
    .header {
        position: relative;
        height: 44px;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        background-color: rgb(111, 135, 168);
        border-top: 1px solid rgb(179, 186, 201);
        border-bottom: 1px solid rgb(73, 95, 144);
        color: white;
        font-size: 20px;
        text-shadow: rgba(0, 0, 0, 0.6) 0 -1px 0;
        font-weight: bold;
        text-align: center;
        line-height: 42px;
    }
  
    /* Styles adjusted based on orientation  */  
    body[orient='portrait'] .container {
        height: 436px;
    }
  
    body[orient='landscape'] .container {
        height: 258px;
    }
  
    body[orient='landscape'] .toolbar {
        height: 30px;
        font-size: 16pt;
    }
  
    body[orient='landscape'] .center {
        top: 50px;
        bottom: 30px;
    }
 
</style>

Code snippet BIDHJ-Ch10-Ex3.html

3. Add the following script code in the document head and then save the file:

image
<script type="application/x-javascript">
 
    addEventListener('load', function() {
        setTimeout(orientationChange, 0);
    }, false);
 
    var currentWidth = 0;
 
    function orientationChange() {
        if (window.innerWidth != currentWidth) {
    currentWidth = window.innerWidth;
        var orient = currentWidth == 320 ? 'portrait' : 'landscape';
        document.body.setAttribute('orient', orient);
 
        setTimeout(function() {
                    document.getElementById('iMode').innerHTML = orient;
                    document.getElementById('iWidth').innerHTML = currentWidth
                      + 'px';
                    document.getElementById('iHeight').innerHTML =
                     document.getElementById('canvasMain').offsetHeight
                      + 'px';
                    document.getElementById('iToolbarHeight').innerHTML =
                       document.getElementById('bottomToolbar').offsetHeight
                          + 'px';
                    document.getElementById('iToolbarTop').innerHTML =
                       document.getElementById('bottomToolbar').offsetTop
                        +'px'; }, 100);          
          
        setTimeout(function() {
           window.scrollTo(0, 1);
        }, 100);          
     }
    }
 
    setInterval(orientationChange, 400);
 
</script>

Code snippet BIDHJ-Ch10-Ex3.html

How It Works

In this example, a series of div elements is used to imitate a basic iPhone interface, consisting of a top toolbar, content area, and bottom toolbar.

In the CSS styles, notice the selector for the final four rules are dependent upon the state of the orient attribute of body. Based on the body element’s orient value, the container CSS class changes its height, the top and bottom toolbars adjust their height and font-size, and the main content area (the center class) is repositioned to fit with the sizing changes around it.

In the JavaScript code, the orientationChangeHandler() function is called when the window loads or changes orientation. It updates the body element’s orient attribute to either portrait or landscape.

Figures 10-3 and 10-4 show the document loaded in both portrait and landscape modes, respectively.

CHANGING ELEMENT POSITIONING BASED ON ORIENTATION CHANGE

When you begin to understand the basic interaction between an orientationChangeHandler() function and orientation-dependent styles, you can begin to dynamically position elements of the UI based on whether the current viewport is in portrait or landscape mode. Suppose, for example, you would like to align an arrow image to the bottom left of a page. Here’s the img declaration:

<img id="pushBtn" src="bottombarknobgray.png"/>

To align the graphic in portrait mode, you could specify the CSS rule as the following:

#pushbtn
{
    position: absolute;
    left: 10px;
    top: 360px;
}

However, if you leave the positioning as is, the button goes off screen when the user tilts the viewport to landscape mode. Therefore, a second landscape-specific rule with an adjusted top value is needed for the button image:

body[orient="landscape"] #pushBtn
{
    left: 10px;
    top: 212px;
}

The orientationChangeHandler() function is as follows:

image
function orientationChangeHandler()
{
    if (window.orientation == 0 || window.orientation == 180)
        document.body.setAttribute('orient', 'portrait')
    else
        document.body.setAttribute('orient', 'landscape'),
}

Code snippet BIDHJ-Ch10-Ex4.html

As Figures 10-5 and 10-6 show, the button image aligns to the bottom left of the page document in both portrait and landscape modes respectively.

TRAPPING FOR KEY EVENTS WITH THE ON-SCREEN KEYBOARD

As with an ordinary web page, you can validate keyboard input by trapping the keydown event. To illustrate, suppose you have an input field in which you want to prevent the user from entering a numeric value. To trap for this, begin by adding a keydown handler to the input element:

<input onkeydown="return validate(event)" />

In the document header, add a script element with the following code inside of it:

     function validate(e) {
          var keynum = e.which;
          var keychar = String.fromCharCode(keynum);
          var chk = /d/;
          return !chk.test(keychar)
     }

As a standard JavaScript validation routine, this function tests the current character code value to determine whether it is a number. If a non-number is found, then true is returned to the input field. Otherwise, a false is sent back and the character is disallowed.

EXERCISES

1. What are the three major types of touch events?

2. Do you need to code all touch events in your web app?

3. What event do you trap to handle screen orientation changes?

Answers to the Exercises can be found in the Appendix.

• WHAT YOU LEARNED IN THIS CHAPTER

TOPIC KEY CONCEPTS
Handling mouse-like events No events trigger until the user’s finger leaves the touch screen.
Design your app to respond to click events rather than the other mouse events.
Responding to multitouch events Trap for multiple touches to occur on screen at the same time and then have your app respond to them.
Dealing with screen orientation changes Add a handler for the body element’s onorientationchange event.
Trapping for key events Add a keydown handler to the appropriate writable element.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset