GeoSpiel

schwerpunkt geography

Touch and OpenLayers

6 comments

A major part of my recent investigations for mobile and opengeo have focused on getting OpenLayers to do a basic version of it’s thing on the iphone.   I’ve had limited success, but maybe these demos will help someone else get a little further or perhaps help crystallize a more effective approach than mine, since I’m pretty green with OL.

From Mouse to Finger

The iphone replaces mouse event with multi-touch (Neil Roberts of SitePen does a good general overview of touch events for iphone 2.0 +).   This gives developers some nice new hammers (guesture events with rotation and scale), but renders OpenLayers out of the box ui broken.   Some touch events iphone safari automatically refires as touch events (prime example, hyperlinks), while such paradigns as clicking and dragging are simply removed requiring a translation to touch and drag.

2 Tips for doing IPhone webdev

Before show and tell, a few things I’ve found helpful in this process.

  1. for testing, I’ve found it easier (at least for concentrating on the major event handling issue), to use the IPhone Simulator packaged with the SDK.  There are some significant differences (mousing in the simulator is far more precise than your butter fingers), but the ability to cut and paste urls saves alot of time.  Holding down the option key causes the mouse click to act like a rotational touch event, and holding do Shift-option causes the mouse to act like a 2 finger scroll (as does 2 finger scrolling on the mouse pad on a macbook).
  2. for introspection and logging, there is no Firebug; unfortunately ibug, joe hewitt’s firebug bridge for the iphone, afaik does not work on iphone 2.1 . You *can* enable the javascript debugging console in the safari settings (see ADC guide on safari debugging).   Firebug-like “console.log(’someinfo’)” statements will then appear in a accessible from safari by a large screen realestate-eating tab.

Show and Tell

I’ve put together a partial demonstration of two different, possibly complementary approaches to getting OpenLayers working with touch events.  I’d recommend using the simulator if available, as the small buttons are rather hard to click at the moment on an actual device.

see Touch Demo

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.

There is a huge caveat though.. the default image saving behavior in safari gets triggered when one drags the map to navigate and holds their finger down for an extended period of time.  I have yet to figure out a way to work around this issue.

The second approach deals with hooking touch events directly up to the map (special thanks to Fan Baiquan  of http://www.whatamap.com for sharing the code on which this example is based).   Here I hook a one touch handler for dragging and one for zooming directly to the map’s div. Note, for the pinch zoom I used a touch event. I have yet to see a guesture event in the wild, but touch events also register rotation and scale and this seems to work ok.

This works great for the basics, but the other controls remain out of operation.  Using the mouse emulation code I can hook up the PanZoomBar (the arrows and zoom drag bar), but some reason, the rest of the controls resist mouse emulation hookup.

Looking Ahead

I talked to Tim Schaub a bit about these approaches, and he pointed out that alot of the general OL controls do not necessarily make the best sense in an environment like mobile safari.   He suggested building custom controls over trying to retrofit the small mouse centric web controls, the most important being the Navigation -> DragPan -> Drag hierarchy (where the touch events are mostly handled in the OpenLayers.Handler.Drag).  This is where I’m going to focus my efforts next.

Written by whit

October 21st, 2008 at 2:10 pm

6 Responses to 'Touch and OpenLayers'

Subscribe to comments with RSS or TrackBack to 'Touch and OpenLayers'.

  1. [...] has written a blog post on what he’s been working on getting OpenLayers to work with Mobile Safari on the iPhone (and iTouch). A major part of my recent investigations for mobile and opengeo have [...]

  2. whit,

    you just saved me from losing my mind. Spent weeks trying to find a good solution to showing maps in an UIWebview on the iPhone. Google maps handles the scrolling brilliantly without a hitch. problem is their controls and markers don’t respond to clicks (anyone know why this is?)

    So I turned my attention to Open Layers. Lovely i thought, everything clicks and gets passed through to the controllers delegate method but then I discovered no scrolling…

    and then you came to my rescue! So thanks.

    regards. Michael.

    Michael Kaye

    22 Oct 08 at 10:48 pm

  3. Hi, Whit!

    I have implemented double-tap zoomIn/Out for iPhone, and I tested on both WAM (Whatamap.com) and OSM. It seems working fine.

    As there is no “ondbltap” similar to “ondblclick” on Iphone, so I took and modified the code by Jon Brisibn somewhere from http://groups.google.com/group/iphonewebdev/browse_thread/thread/f159a737a439c8ce/ebf3dbe9f855a849.

    So we now have:

    1 && e.scale != obj.scale) {
    obj.map.zoomIn();
    } else {
    if (e.scale < 1 && e.scale != obj.scale) {
    obj.map.zoomOut();
    }
    }
    obj.scale = e.scale;
    };
    },

    hook_touch: function (){
    var map = this.map;
    map.div.addEventListener(”touchstart”, this.touchstart(), false);
    map.div.addEventListener(”touchmove”, this.pan_touch(map), false);

    // guestures are currently like unicorns to me… never seen on in the wild
    // but touchevents have scale and rotation
    map.div.addEventListener(”touchend”, this.zoom_guesture(map), false);
    map.div.addEventListener(”guestureend”, this.zoom_guesture(map), false);
    }
    });

    FAN Baiquan

    23 Oct 08 at 8:57 am

  4. the message was truckated! so here is the part I modified:

    touchstart: function(){
    var inDoubleTap = false;
    var doubleTapTimer = false;
    var zoom = null;

    var obj = this;
    return function (e) {
    event.preventDefault();
    if(e.touches.length == 1) {
    if(!doubleTapTimer){
    doubleTapTimer = setTimeout(function(){ inDoubleTap = false; doubleTapTimer = false; }, 500);
    }

    if(!inDoubleTap) {
    inDoubleTap = true;
    }else{
    inDoubleTap = false;
    if (zoom == null || zoom == “out”) {
    obj.map.zoomIn();
    zoom = “in”;
    } else {
    obj.map.zoomOut();
    zoom = “out”;
    }
    }

    var touch = e.touches[0];
    obj.touchStartX = touch.clientX;
    obj.touchStartY = touch.clientY;

    if (touch.target.width === 128) {
    return false;
    } else {
    return true;
    }
    };
    return null;
    };
    },

    FAN Baiquan

    23 Oct 08 at 8:59 am

  5. Thanks Fan!

    whit

    23 Oct 08 at 4:52 pm

  6. [...] the hood, the classes IOL.Handler.DoubleTap (thanks again to Fan of whatamap who posted the double tap code in the comments of this blog), IOL.Handler.Pinch and IOL.Handler.Drag do all the interacting with the [...]

Leave a Reply