16 min read

The human touch

There’s a reason touchscreen interfaces were rarely used before Apple re-invented them in the iPhone. It’s because programming them is very difficult. With a mouse-driven interface you have a single point of contact: the mouse’s pointer. With a touchscreen, you potentially have ten points of contact, each one with a separate motion. And you also have to deal with limiting spurious input when the user accidentally touches the tablet when they didn’t mean to. Does the user’s swipe downward mean they want to scroll the page or to drag a single page element? The questions go on to infinity.

With this article, we stand on the shoulders of those giants who have done the heavy lifting and given us a JavaScript interface that registers touch and gestures for use in our web pages. Many Bothans died to bring us this information.

To understand the tablet is to understand the touch interface, and in order to understand the touch interface, we need to learn how touch events differ from mouse events. But that begs the question: what is an event?

The event-driven model

Many developers use JavaScript-based events and have not even the slightest clue as to what they can do or their power. In addition, many developers get into situations where they don’t know why their events are misfiring or, worse yet, bubbling to other event handlers and causing a cascade of event activity.

As you may or may not know, an HTML document is made up of a series of tags organized in a hierarchical structure called the HTML document. In JavaScript, this document is referred to through the reserved word document. Simple enough, right? Well, what if I want to interact with the tag inside of a document, and not the document as a whole? Well, for that we need a way of addressing nested items inside the main <html> tag. For that, we use the Document Object Model (DOM).

DOM is a cross-platform and language-independent convention for representing and interacting with objects in HTML, XHTML, and XML documents. Aspects of the DOM (such as its elements) may be addressed and manipulated within the syntax of the programming language in use. The public interface of a DOM is specified in its Application Programming Interface (API). For more details on DOM, refer to the Wikipedia document at: http://en.wikipedia.org/wiki/Document_Object_Model.

The body of that document then becomes document.body. The head of the document, likewise, becomes document.head. Now, what happens when your mouse interacts with this web page? This is said to be a DOM event. When you click, the elements that are the receivers of that action are said to propagate the event through the DOM. In the early days, Microsoft and Netscape/Firefox had competing ways of handling those events. But they finally gave way to the modern W3C’s standard, which unifies the two ways and, even more importantly, jQuery has done a lot to standardize the way we think about events and event handling. In most browsers today, mouse events are pretty standardized, as we are now more than 20 years into the mouse-enabled computing era:

For tablets and touchscreen phones, obviously, there is no mouse. There are only your fingers to serve the purpose of the mouse. And here’s where things get simultaneously complicated as well as simple.

Touch and go

Much of what we talk about as touch interaction is made up of two distinct types of touches—single touches and gestures. A single touch is exactly that. One finger placed on the screen from the start till the end. A gesture is defined as one or more fingers touching the surface of the area and accompanied by a specific motion: Touch + Motion. To open most tablets, you swipe your finger across a specific area. To scroll inside a div element, you use two fingers pushing up and down. In fact, scrolling itself is a gesture and tablets only respond to the scroll event once it’s over. We will cover more on that later.

Gestures have redefined user interaction. I wonder how long it took for someone to figure out that the zoom in and zoom out is best accomplished with a pinch of the fingers? It seems so obvious once you do it and it immediately becomes second nature. My mom was pinching to zoom on her iPhone within the first 5 minutes of owning it.

Touch events are very similar to multiple mouse events without a hover state. There is no response from the device when a finger is over the device but has not pressed down. There is an effort on the part of many mobile OS makers to simulate the hover event by allowing the hover event to trigger with the first click, and the click event to trigger with the second click on the same object. I would advise against using it for any meaningful user interaction as it is inconsistently implemented, and many times the single click triggers the link as well as the hover-reveal in drop-down menus.

Not using the hover event to guide users through navigation changes the way we interact with a web page. Much of the work we’ve done to guide users through our pages is based on the hover-response event model to clue users in on where links are. We have to get beyond that.

Drop-down menus quickly become frustrating at the second and third levels, especially if the click and hover events were incorrectly implemented in the desktop browser. Forward and back buttons are rendered obsolete by a forward and backwards swipe gesture.

The main event

There are basically three touch events—touchstart, touchmove, and touchend. Gesture events are, likewise: gesturestart, gesturemove, and gestureend. All gestures register a touch event but not all touch events register gestures. Gestures are registered when multiple fingers make contact with the touch surface and register significant location change in a concerted effort, such as two or more fingers swiping, a pinch action, and so on.

In general, I’ve found it a good practice to use touch events to register finger actions; but it is required to return null on a touch event when there are multiple fingers involved and to handle such events with gestures.

jQuery mobile has a nice suite of touch events built into its core that we can hook into. But jQuery and jQuery mobile sometimes fall short of the interaction we want to have for our users, so we’ll outline best practices for adding customized user touch events to both the full and mobile version of the demo site.

Let’s get started…

Time for action – adding a swipe advance to the home page

The JavaScript to handle touch events is a little tricky; so, pay attention:

  1. Add the following lines to both sites/all/themes/dpk/js/global.js and sites/all/themes/dpk_mobile/js/global.js:
  2. Drupal.settings.isTouchDevice = function() { return "ontouchstart" in window; } if (Drupal.settings.isTouchDevice() ) { Drupal.behaviors.jQueryMobileSlideShowTouchAdvance = { attach: function(context, settings) { self = Drupal.behaviors.jQueryMobileSlideShowTouchAdvance; jQuery.each(jQuery(".views_slideshow_cycle_main. viewsSlideshowCycle-processed"), function(idx, value) { value.addEventListener("touchstart", self. handleTouchStart); jQuery(value).addClass("views-slideshow-mobileprocessed"); }) jQuery(self).bind("swipe", self.handleSwipe); }, detach: function() { }, original: { x: 0, y: 0}, changed: { x: 0, y: 0}, direction: { x: "", y: "" }, fired: false,handleTouchStart: function(evt) { self = Drupal.behaviors.jQueryMobileSlideShowTouchAdvance; if (evt.touches) { if (evt.targetTouches.length != 1) { return false; } if (evt.touches.length) { evt.preventDefault(); evt. stopPropagation() } self.original = { x: evt.touches[0].clientX, y: evt. touches[0].clientY } self.target = jQuery(this).attr("id").replace("views_ slideshow_cycle_main_", ""); Drupal.viewsSlideshow.action({ "action": "pause", "slideshowID": self.target }); evt.target.addEventListener("touchmove", self. handleTouchMove); evt.target.addEventListener("touchend", self. handleTouchEnd); } }, handleTouchMove: function(evt) { self = Drupal.behaviors.jQueryMobileSlideShowTouchAdvance; self.changed = { x: (evt.touches.length) ? evt.touches[0].clientX: evt.changedTouches[0].clientX, y: (evt.touches.length) ? evt.touches[0].clientY: evt.changedTouches[0].clientY }; h = parseInt(self.original.x - self.changed.x), v = parseInt(self.original.y - self.changed.y); if (h !== 0) { self.direction.x = (h < 0) ? "right":"left"; } if (v !== 0) { self.direction.y = (v < 0) ? "up": "down"; } jQuery(self).trigger("swipe"); }, handleTouchEnd: function(evt) { self = Drupal.behaviors.jQueryMobileSlideShowTouchAdvance; evt.target.removeEventListener("touchmove", self. handleTouchMove); evt.target.removeEventListener("touchend", self. handleTouchEnd); self.fired = false; }, handleSwipe: function(evt) { self = Drupal.behaviors.jQueryMobileSlideShowTouchAdvance; if (evt != undefined && self.fired == false) { Drupal.viewsSlideshow.action({ "action": (self.direction.x == "left")?"nextSlide":"previousSlide", "slideshowID": self.target}); self.fired = true; //only fire advance once per touch } } } }

  3. Clear Drupal’s cache by either navigating to Configuration | Performance and clicking on the Clear cache button or entering these lines in a terminal:

    cd ~/sites/dpk/
    drush cc all

  4. Navigate to either home page with a touch-enabled device and you should be able to advance the home page slideshow with your fingers.

What just happened?

Let’s take a look at how this code works. First, we have a function, isTouchDevice. This function returns true/false values if touch events are enabled on the browser. We use an if statement to wall off the touchscreen code, so browsers that aren’t capable don’t register an error. The Drupal behavior jQueryMobileSlideShowTouchAdvance has the attach and detach functions to satisfy the Drupal behavior API. In each function, we locally assign the self variable with the value of the entire object. We’ll use this in place of the this keyword. In the Drupal behavior object, this can sometimes ambiguously refer to the entire object, or to the current sub-object. In this case, we want the reference to be to just the sub-object so we assign it to self. The attach function grabs all slideshow_cycle div elements in a jQuery each loop. The iteration of the loop adds an event listener to the div tag. It’s important to note that the event listener is not bound with jQuery event binding. jQuery event binding does not yet support touch events. There’s an effort to add them, but they are not in the general release that is used with Drupal 7. We must then add them with the browser native function, AddEventListener. We use the handleTouchStart method to respond to the touchstart event. We will add touchend and touchmove events after the touchstart is triggered.
The other event that we’re adding listens to this object for the swipe event. This is a custom event we will create that will be triggered when a swipe action happens. We will cover more on that shortly.
The detach function is used to add cleanup to items when they are removed from the DOM. Currently, we have no interaction that removes items from the DOM and therefore no cleanup that’s necessary for that removal to take place.
Next, we add some defaults—original, changed, direction, and fired. We’ll use those properties in our event response methods.
HandleTouchStart event is fired when the finger first touches the surface. We make sure the evt.touches object has value and is only one touch. We want to disregard touches that are gestures. Also, we use preventDefault and stopPropagation on the event to keep it from bubbling up to other items in the DOM. self.original is the variable that will hold the touch’s original coordinates. We store the values for touch[0]. We also name the target by getting the DOM ID of the cycle containing the div element. We can use string transforms on that ID to obtain the ID of the jQuery cycle being touched and will use that value when we send messages to the slideshow, based on the touch actions, like we do in the next line. We tell the slideshow to pause normal activity while we figure out what the user wants. To figure that out, we add touchmove and touchend events listening to the div element. handleTouchMove figures out the changed touch value. It does so by looking at the ClientX and ClientY values in the touch event.
Some browsers support the changedTouches value which will do some calculations on how much the touch has changed since the last event was triggered. If it’s available, we use it, or we use the value of the X and Y coordinates in the touch event’s touches array. We do some subtraction against the original touch to find out how much the touch has changed and in what direction. We use self.direction to store the direction of the change. We store the direction in and tell the world that a swipe has begun on our div element by triggering a custom event on our self object.
If you remember correctly, we used the handleSwipe method to respond to the swipe event. In handleSwipe we make sure the event has not already fired. If it hasn’t, we use that swipe event to trigger a next or previous action on our jQuery cycle slideshow. Once we’ve fired the event, we change the self.fired to true so it will only fire once per touch. In the touchend responder, HandleTouchEnd, we remove both the touchmove and touchend responders and reset the fired state.
But adding the touch events to both the desktop and the mobile themes begs the question, “Into which category does the table fall?”

Have a go hero – adding a swipe gesture

Add a swipe gesture event to the Menu Item page that allows you to scroll through menu items.

The changing landscape (or portrait)

Responsive web design is a design discipline that believes that the same markup should be used for both desktop and mobile screens, with the browser managing the display of items, rather than the user choosing an experience. If the screen is smaller, the layout adjusts and content emphasis remains.
Conversely, the popularity of Internet-connected game consoles and DVI ports on large screen televisions gives us yet another paradigm for web pages—the large screen. I sit in front of a 72″ TV screen and connect it to either my laptop or iPad and I have a browsing experience that is more passive, but completely immersive.
Right now, I bet you’re thinking, “So which is it Mr Author, two sites or one?” Well, both, actually. In some cases, with some interactions it will be necessary to do two site themes and maintain them both. In some cases, when you can start from scratch, you can do a design that can work on every browser screen size. Let’s start over and put responsive design principals to work with what we already know about media queries and touch interfaces.

“Starting over” or “Everything you know about designing websites is wrong”

Responsive web design forces the designer to start over—to forget the artificial limitations of the size that print imposes and to start with a blank canvas. Once that blank canvas is in place, though, how do you fill it? How do you create “The One True Design” (cue the theme music)?
This book is not a treatise on how to create the perfect design. For that, I can recommend A Book Apart and anything published by smashingmagazine.com. Currently, they are at the forefront of this movement and regularly publish ideas and information that is helpful without too much technical jargon.
No, this book is more about giving you strategies to implement the designs you’re given or that you create using Drupal. In point of fact, responsive design, at the time of writing, is in its infancy and will change significantly over the next 10 years, as new technology forces us to rethink our assumptions about what books, television, and movies are and what the Web is.
So suffice to say, it begins with content. Prioritizing content is the job of the designer. Items you want the user to perceive first, second, and third are the organizing structure of your responsive design makeover. In most instances, it’s helpful to present the web developer with four views of the website.

Wire framing made easy

Start with wireframes. A great wire framing tool is called Balsamiq. It has a purposefully “rough” look to all of the elements you use. That way, it makes you focus on the elements and leave the design for a later stage. It’s also helpful for focusing clients on the elements. Many times the stake holders see a mockup and immediately begin the discussion of “I like blue but I don’t like green/I like this font, but don’t like that one.” It can be difficult to move the stake holders out of this mindset, but presenting them with black-and-white chalk-style drawings of website elements can, in many cases, be helpful. Balsamiq is a great tool for doing just that:

These were created with Balsamiq but could have been created in almost any primitive drawing program. There are many free ones as well as the more specialized pay ones. A simple layout like this is very easy to plan and implement. But very few of the websites you develop will ever be this simple. Let’s take for instance that the menu item we have not, as yet, implemented, is for online ordering. How does that work? What do those screens look like? At this point we have a Menu page but, as per this mockup, that menu page will become the online ordering section. How do we move these menu items we created to a place where they can be put in an order and paid for? And more importantly, how does each location know what was ordered from their location?
These are questions that come up in the mockup and requirements phase and whether you are building the site yourself or being given requirements from a superior, or a client, you now have a better idea of the challenges you will face implementing the single design for this site. With that, we’ve been given these mockups for the new online ordering system. The following mockup diagram is for adding an order:

The following mockup diagram is for placing an order:

We’ll implement these mockups using the Drupal 7 Commerce module. The Commerce module is just a series of customized data entities and views that we can use as the building blocks of our commerce portion. We’ll theme the views in the standard Drupal way but with an eye to multi-width screens, lack of hover state, and keeping in mind “hit zones” with fingers on small mobile devices. We’ll also add some location awareness to assist with the delivery process. Once an order is placed, an e-mail will need to be sent to the correct franchise notifying them of the pizza order and initiating the process of getting it out the door.

LEAVE A REPLY

Please enter your comment!
Please enter your name here