f

unk rock


iPhone Touch Events in JavaScript

Yesterday I gave a presentation at the San Francisco JavaScript Meetup about the new JavaScript touch events API in iPhone 2.0. I thought I’d share the slides, in case people were interested in viewing them after the fact.

I owe a great deal of thanks to Neil Roberts from SitePen, who’s post on the topic was my main source of information. My co-founder Tom Robinson was also helpful, thanks to his iPhone light-table.

One of the interesting things I was able to talk about was reusing existing mouse based libraries with the iPhone by using touch events to simulate mouse events. The basic idea behind it was to address the fact that mouse events don’t work particularly well on the phone. It’s unpredictable when you’ll get them, if at all (you won’t if you attach only to document, for example). Mousemove in particular doesn’t work in any meaningful way.

In contrast, the touch events are completely predictable and reliable (excepting the existing bugs). We can use these events to simulate the existing mouse events with a fair amount of accuracy. In particular, when one finger is down on the screen, touchstart, touchend, and touchmove correspond nicely with mousedown, mouseup, and mousemove. There’s some difference in the way mousemove works, since we can’t get mousemove events when the finger is not touching the screen, but this is an acceptable trade off. It doesn’t make sense on the iPhone anyway because there’s no persistent cursor.

I took this jQuery based drag and drop example to see if I could get it working on the iPhone without modification. Here’s the working iPhone demo. The only existing code that I modified was some CSS to make the page fit nicely on the iPhone screen, and a viewport meta tag. The added code to get drag and drop working is really simple:

function touchHandler(event)
{
    var touches = event.changedTouches,
        first = touches[0],
        type = “”;
    
    switch(event.type)
    {
        case “touchstart”: type = “mousedown”; break;
        case “touchmove”:  type=“mousemove”; break;        
        case “touchend”:   type=“mouseup”; break;
        default: return;
    }
        
    //initMouseEvent(type, canBubble, cancelable, view, clickCount,
    //           screenX, screenY, clientX, clientY, ctrlKey,
    //           altKey, shiftKey, metaKey, button, relatedTarget);
    
    var simulatedEvent = document.createEvent(“MouseEvent”);
    simulatedEvent.initMouseEvent(type, true, true, window, 1,
                              first.screenX, first.screenY,
                              first.clientX, first.clientY, false,
                              false, false, false, 0/*left*/, null);
                                                                            
    first.target.dispatchEvent(simulatedEvent);
    event.preventDefault();
}

function init()
{
    document.addEventListener(“touchstart”, touchHandler, true);
    document.addEventListener(“touchmove”, touchHandler, true);
    document.addEventListener(“touchend”, touchHandler, true);
    document.addEventListener(“touchcancel”, touchHandler, true);    
}

I’ve captured the touch events and then manually fired my own mouse events to match. Although the code isn’t particularly general purpose as is, it should be trivial to adapt to most existing drag and drop libraries, and probably most existing mouse event code. Hopefully this idea will come in handy to people developing web applications for the iPhone.

Update: In posting this, I noticed that calling preventDefault on all touch events will prevent links from working properly. The main reason to call preventDefault at all is to stop the phone from scrolling, and you can do that by calling it only on the touchmove callback. The only downside to doing it this way is that the iPhone will sometimes display its hover popup over the drag origin. If I discover a way to prevent that, I’ll update this post.

Second Update: I’ve found the CSS property to turn off the callout, “-webkit-touch-callout”. You can read about it in Apple’s documentation.

5 Responses to “iPhone Touch Events in JavaScript”

  1. Neil Roberts Says:

    You’re welcome!

  2. uglychart.com: a blog about stocks » Blog Archive » links for August 20th Says:

    [...] RossBoucher.Com » Funk Rock » Blog Archive » iPhone Touch Events in JavaScript - [...]

  3. raoli.com » Blog Archive » links for 2008-08-24 Says:

    [...] iPhone Touch Events in JavaScript (tags: javascript iphone js webdev touch event cite:rentzsch) [...]

  4. Touch and OpenLayers at GeoSpiel Says:

    [...] The first approach works off of Ross Boucher’s  mouse emulation code (see IPhone Touch Events in Javascript) which approaches touch events by rewrite dispatching them as mouse events.  This works pretty well.   Most other clickable elements still work and the approach requires no modification of existing code. [...]

  5. Spatial Distillery » Blog Archive » Touch and OpenLayers Says:

    [...] The first approach works off of Ross Boucher’s mouse emulation code (see IPhone Touch Events in Javascript) which approaches touch events by rewrite dispatching them as mouse events. This works pretty well. Most other clickable elements still work and the approach requires no modification of existing code. [...]

Leave a Reply