When I first heard about possibilities of AIR 2.0 after MAX Conference I got enthusiast, specially about features that were so awaited. Among them, one of the most promising for the future way of creating applications with rich interfaces is – multitouch support. Thanks to the updated AIR 2.0 we have access to gestures on when using touch pads and multitouch screen displays. I was looking forward to create very simple demo using multitouch and I thought about mapping using Google Maps.

Here is the simple recipe how to create the simplest application using three gestures: Pan (with two fingers), Zoom (also with two fingers) and Swipe (using three fingers). I built it and tested on MB Pro with multitouch running under Snow Leopard with AIR 2.0 beta 1.

Ok, let’s get started. First – we need to set up a map. I almost pasted the code from the Google site to make it simpler for you. I listen to to the event mapevent_mappreinitialize, where I set up map types, zoom etc.:

private function onMapInitialize( event : MapEvent ) : void
{
mapTypes = MapType.DEFAULT_MAP_TYPES;
 
var mapOptions : MapOptions = new MapOptions();
 
mapOptions.zoom = 14;
mapOptions.mapType = mapTypes[ currentMapType ];
 
map.setInitOptions( mapOptions );
}

Ok, than we set up the map itself on mapevent_mapready.  We will look for The Ministry of Ideas in Cracow and put a marker there:

private function onMapReady( event : MapEvent ) : void
{
doGeocode();
}
 
private function doGeocode() : void
{
var geocoder : ClientGeocoder = new ClientGeocoder();
geocoder.addEventListener( GeocodingEvent.GEOCODING_SUCCESS, function ( event : GeocodingEvent ) : void
{
var placemarks : Array = event.response.placemarks;
if ( placemarks.length > 0 )
{
map.setCenter( placemarks[ 0 ].point );
var marker : Marker = new Marker( placemarks[ 0 ].point );
marker.addEventListener( MapMouseEvent.CLICK, function ( event : MapMouseEvent ) : void
{
marker.openInfoWindow( new InfoWindowOptions( { content: placemarks[ 0 ].address } ) );
} );
map.addOverlay( marker );
 
var latlng : LatLng = marker.getLatLng();
 
map.panTo( latlng );
}
} );
geocoder.addEventListener( GeocodingEvent.GEOCODING_FAILURE, function ( event : GeocodingEvent ) : void
{
Alert.show( "Geocoding failed: " + event.toString() );
} );
geocoder.geocode( "Mostowa 2, Krakow, Poland" );
}

Now, when the map is set up it’s time to do the magic. On creationComplete for Application we add:

public function onCreationComplete() : void
{
Multitouch.inputMode = MultitouchInputMode.GESTURE;
 
this.addEventListener( TransformGestureEvent.GESTURE_ZOOM, onZoom );    // zoom map in/out
this.addEventListener( TransformGestureEvent.GESTURE_SWIPE, onSwipe );    // change map type
this.addEventListener( TransformGestureEvent.GESTURE_PAN, onPan );        // pan map around
}

We also use a constant to set up threshold for reading the gestures and a variable to hold the last update time. We need them so the application feedback is comfortable to the client:

private static const IDLE_THRESHOLD : int = 300;
private var lastUpdate : Number = 0;

Zooming is simple. If the zoom variables from the gesture event are below 1 – we zoom out, if greater than 1 we zoom in. Simple as that. We have all we need in the event variables.

private function onZoom( event : TransformGestureEvent ) : void
{
if( getTimer() - lastUpdate > IDLE_THRESHOLD )
{
if( event.scaleX > 1 && event.scaleY > 1 )
map.setZoom( map.getZoom() + 1 );
if( event.scaleX < 1 && event.scaleY < 1 )
map.setZoom( map.getZoom() - 1 );
 
lastUpdate = getTimer();
}
}

Than we go to panning. Panning is also easy. What I decided to do is to read a movement from the event and create a new “vector” based on it. I use it to set up a new center of the map:

private function onPan( event : TransformGestureEvent ) : void
{
var point : Point = map.fromLatLngToPoint( map.getCenter() );
var newPoint : Point = new Point( point.x + ( event.offsetX * 10 ), point.y + ( event.offsetY * 10 ) );
var newLatLon : LatLng = map.fromPointToLatLng( newPoint );
 
map.setCenter( newLatLon );
}

I thought that we could use swiping for changing the map type, which is quite useful as Google Maps API has four map types. when you swipe right or left the map type will change. As you can see I use helper variable to hold the current map type.

private function onSwipe( event : TransformGestureEvent ) : void
{
if( getTimer() - lastUpdate > IDLE_THRESHOLD )
{
if( event.offsetX > 0 )
currentMapType++;
if( event.offsetX < 0 )
currentMapType--;
 
if( currentMapType < 0 )
currentMapType = mapTypes.length - 1;
 
currentMapType = currentMapType % mapTypes.length;
 
map.setMapType( mapTypes[ currentMapType ] );
 
lastUpdate = getTimer();
}
}

You will find the full source code here. Comments and critique are welcomed, as always.

You can try it by quickly installing the following AIR file. Have in mind that to test it you will need a computer with a multitouch screen or pad and a PC with Windows 7 or a Mac with Snow Leopard.

Please upgrade your Flash Player

Have a great day,
W.