Recently I’ve worked on a mobile app for the company I work for , and instead of just showing company’s address or displaying it on a map I thought.. wouldn’t it be more helpful to give user directions from wherever he is to where the company is ?
To do this, you of course, need to utilise a few APIs:
1. Google Maps API to download map tiles and draw a poly line from user’s location to destination,
2. Air’s Geolocation API to determine current users location
3. Air’s Multitouch API to let the user pan/zoom and rotate the map.
Getting the google maps to show on your display list is pretty straightforward, there’s a couple caveats though. It is now compulsory to initialise map with a sensor parameter (just a Boolean switch expressed in string format indicating whether map is used on a device with geolocating sensor.)
Also , to get it working in AIR app, you have to pass the ‘url’ parameter. I used local host for this.
private function initMap() : void
{
//init map
map = new Map3D();
map.x = mapsDimensionsBox.x;
map.y = mapsDimensionsBox.y;
map.key = apiKey;
map.url = "http://localhost";
map.sensor = "true";
map.setSize(new Point(mapsDimensionsBox.width, mapsDimensionsBox.height));
map.addEventListener(MapEvent.MAP_READY, onMapReady);
map.addEventListener(MapEvent.MAP_PREINITIALIZE, onMapPreinitialize);
gfx.addChild(map);
}
Getting user’s location is relatively simple, but it’s best to check first whether user’s device support’s it and whether it has been turned on :
private function getGeolocation() : void
{
if (Geolocation.isSupported)
{
geo = new Geolocation();
if (geo.muted)
{
alert("Please turn on the location or select a manual address input",showManualLocation);
}
else
{
geo.setRequestedUpdateInterval(100);
geo.addEventListener(GeolocationEvent.UPDATE, geolocationUpdateHandler);
}
}
else
{
alert("Geolocation not supported, please input your location manualy", showManualLocation);
}
}
Once we have the GeolocationEvent fired , we can determine user’s location from event.latitude and event.longitude.
However, Google maps Directions.load normally works with address format query, eg. “from 25 apple Street, NewYork to 22 Boulevard Street, San Francisco”. To get it working with LatLng you have to use this format (Thanks to Barry Hunter from Google maps forums for this tip)
private function geolocationUpdateHandler(event : GeolocationEvent) : void
{
originLatLong = new LatLng(event.latitude, event.longitude);
dirQuery = "from: Start@"+originLatLong.lat()+","+originLatLong.lng()+" to: Destination@"+fbfLatLong.lat()+","+fbfLatLong.lng();
initMap();
}
(fbfLatLong being hardcoded LatLng destination variable)
After the geolocation is known and direction query is formulater we can get directions by calling load function:
private function requestDirections() : void
{
//create directions
dir = new Directions();
dir.addEventListener(DirectionsEvent.DIRECTIONS_SUCCESS, onDirLoad);
dir.addEventListener(DirectionsEvent.DIRECTIONS_FAILURE, onDirFail);
dir.load(dirQuery);
}
Once the requested directions are computed and returned we can draw the route. I am also attaching a custom markers at the start and the end of the journey.
private function onDirLoad(event : DirectionsEvent) : void
{
map.clearOverlays();
var directions : Directions = Directions(event.directions);
var startLatLng:LatLng=directions.getRoute(0).getStep(0).latLng;
var endLatLng:LatLng=directions.getRoute(directions.numRoutes-1).endLatLng;
createMarkers(startLatLng,true);
createMarkers(endLatLng,false);
var directionsPolyline:IPolyline = directions.createPolyline();
map.addOverlay(directionsPolyline);
//get bound center
var directionsBounds : LatLngBounds = directionsPolyline.getLatLngBounds();
map.setCenter(directionsBounds.getCenter());
//get the zoom level from direction bounds
var zoomLevel:Number = map.getBoundsZoomLevel(directionsBounds);
map.setZoom(zoomLevel);
map.setAttitude(map.getAttitude());
}
It’s important to centre and zoom the map so that the whole journey is visible on the map.
OnDirFail is called when the given coordinates couldn’t be resolved, and then it’s probably best option to give user a chance to input the address manually.
Tested on Android 2.2 on Desire HD with Air 2.6 runtime.