This article needs a technical review. How you can help.
The touch event interfaces support application-specific single and multi-touch interactions. However, the interfaces can be a bit tricky for programmers to use because touch events are very different from other DOM input events, such as mouse events
. The application described in this guide shows how to use touch events for simple single and multi-touch interactions, the basics needed to build application-specific gestures.
A live version of this application is available on Github. The source code is available on Github and pull requests and bug reports are welcome.
Example
This example demonstrates using the touchstart
, touchmove
, touchcancel
, and touchend
) touch events for the following gestures: single touch, two (simultaneous) touches, more than two simultaneous touches, 1-finger swipe, and 2-finger move/pinch/swipe.
Define touch targets
The application uses <div>
for four touch areas.
<style> div { margin: 0em; padding: 2em; } #target1 { background: white; border: 1px solid black; } #target2 { background: white; border: 1px solid black; } #target3 { background: white; border: 1px solid black; } #target4 { background: white; border: 1px solid black; } </style>
Global state
tpCache
is used to cache touch points for processing outside of the event where they were fired.
// Log events flag var logEvents = false; // Touch Point cache var tpCache = new Array();
Register event handlers
Event handlers are registered for all four touch event types. The touchend
and touchcancel
event types use the same handler.
function set_handlers(name) { // Install event handlers for the given element var el=document.getElementById(name); el.ontouchstart = start_handler; el.ontouchmove = move_handler; // Use same handler for touchcancel and touchend el.ontouchcancel = end_handler; el.ontouchend = end_handler; } function init() { set_handlers("target1"); set_handlers("target2"); set_handlers("target3"); set_handlers("target4"); }
Move/Pinch/Zoom handler
This function provides very basic support for 2-touch horizontal move/pinch/zoom handling. The code does not include error handling, vertical moving. Note that the threshold for pinch and zoom movement detection is application specific (and device dependent).
// This is a very basic 2-touch move/pinch/zoom handler that does not include // error handling, only handles horizontal moves, etc. function handle_pinch_zoom(ev) { if (ev.targetTouches.length == 2 && ev.changedTouches.length == 2) { // Check if the two target touches are the same ones that started // the 2-touch var point1=-1, point2=-1; for (var i=0; i < tpCache.length; i++) { if (tpCache[i].identifier == ev.targetTouches[0].identifier) point1 = i; if (tpCache[i].identifier == ev.targetTouches[1].identifier) point2 = i; } if (point1 >=0 && point2 >= 0) { // Calculate the difference between the start and move coordinates var diff1 = Math.abs(tpCache[point1].clientX - ev.targetTouches[0].clientX); var diff2 = Math.abs(tpCache[point2].clientX - ev.targetTouches[1].clientX); // This threshold is device dependent as well as application specific var PINCH_THRESHHOLD = ev.target.clientWidth / 10; if (diff1 >= PINCH_THRESHHOLD && diff2 >= PINCH_THRESHHOLD) ev.target.style.background = "green"; } else { // empty tpCache tpCache = new Array(); } } }
Touch start handler
The touchstart
event handler caches touch points to support 2-touch gestures. It also calls preventDefault()
to keep the browser from applying further event handling (for example, mouse event emulation).
function start_handler(ev) { // If the user makes simultaneious touches, the browser will fire a // separate touchstart event for each touch point. Thus if there are // three simultaneous touches, the first touchstart event will have // targetTouches length of one, the second event will have a length // of two, and so on. ev.preventDefault(); // Cache the touch points for later processing of 2-touch pinch/zoom if (ev.targetTouches.length == 2) { for (var i=0; i < ev.targetTouches.length; i++) { tpCache.push(ev.targetTouches[i]); } } if (logEvents) log("touchStart", ev, true); update_background(ev); }
Touch move handler
The touchmove
handler calls preventDefault()
for the same reason mentioned above, and invokes the pinch/zoom handler.
function move_handler(ev) { // Note: if the user makes more than one "simultaneous" touches, most browsers // fire at least one touchmove event and some will fire several touchmoves. // Consequently, an application might want to "ignore" some touchmoves. // // This function sets the target element's border to "dashed" to visually // indicate the target received a move event. // ev.preventDefault(); if (logEvents) log("touchMove", ev, false); // To avoid too much color flashing many touchmove events are started, // don't update the background if two touch points are active if (!(ev.touches.length == 2 && ev.targetTouches.length == 2)) update_background(ev); // Set the target element's border to dashed to give a clear visual // indication the element received a move event. ev.target.style.border = "dashed"; // Check this event for 2-touch Move/Pinch/Zoom gesture handle_pinch_zoom(ev); }
Touch end handler
The touchend
handler restores target's background color back to its original color.
function end_handler(ev) { ev.preventDefault(); if (logEvents) log(ev.type, ev, false); if (ev.targetTouches.length == 0) { // Restore background and border to original values ev.target.style.background = "white"; ev.target.style.border = "1px solid black"; } }
Application UI
The application uses <div>
elements for the touch areas and provides buttons to enable logging and to clear the log.
<div id="target1"> Tap, Hold or Swipe me 1</div> <div id="target2"> Tap, Hold or Swipe me 2</div> <div id="target3"> Tap, Hold or Swipe me 3</div> <div id="target4"> Tap, Hold or Swipe me 4</div> <!-- UI for logging/bebugging --> <button id="log" onclick="enableLog(event);">Start/Stop event logging</button> <button id="clearlog" onclick="clearLog(event);">Clear the log</button> <p></p> <output></output>
Miscellaneous functions
These functions support the application but aren't directly involved with the event flow.
Update background color
The background color of the touch areas will change as follows: no touch is white
; one touch is yellow
; two simultaneous touches is ping
, and three or more simultaneous touches is lightblue
. See touch move for information about the background color changing when a 2-finger move/pinch/zoom is detected.
function update_background(ev) { // Change background color based on the number simultaneous touches // in the event's targetTouches list: // yellow - one tap (or hold) // pink - two taps // lightblue - more than two taps switch (ev.targetTouches.length) { case 1: // Single tap` ev.target.style.background = "yellow"; break; case 2: // Two simultaneous touches ev.target.style.background = "pink"; break; default: // More than two simultaneous touches ev.target.style.background = "lightblue"; } }
Event logging
The functions are used to log event activity to the application window, to support debugging and learning about the event flow.
function enableLog(ev) { logEvents = logEvents ? false : true; } function log(name, ev, printTargetIds) { var o = document.getElementsByTagName('output')[0]; var s = name + ": touches = " + ev.touches.length + " ; targetTouches = " + ev.targetTouches.length + " ; changedTouches = " + ev.changedTouches.length; o.innerHTML += s + " "; if (printTargetIds) { s = ""; for (var i=0; i < ev.targetTouches.length; i++) { s += "... id = " + ev.targetTouches[i].identifier + " "; } o.innerHTML += s; } } function clearLog(event) { var o = document.getElementsByTagName('output')[0]; o.innerHTML = ""; }