2010
08.06

For the past few days I’ve been messing around with the API that Google Maps put out for Flash. It lets you use Google maps in your own Flash/AIR applications and customize them however you want. I’m going to explain how to make your own AIR app that lets you display bus routes and stops using the Google Maps API and ZendAMF.

We’re also going to create a function that lets us see the approximate time the next bus will come to any given stop (ex. “5 minutes until the next bus”).

Some helpful links (be sure to read the Google Maps references and examples):

Google Maps API/Libraries (you’ll need an API key)

ZendAMF

For this example, I’m using the LTC of London Ontario with the 21/15 route, and the 17.

First we want to make a new “map” and we want a remote object that lets us communicate with PHP (I’m just generating XML here, see the source code for my example).

<maps:Map xmlns:maps=”com.google.maps.*” id=”map” mapevent_mapready=”onMapReady(event)” width=”100%” height=”100%”
url=”http://code.google.com/apis/maps/” key=”YOUR GOOGLE MAPS API KEY HERE”/>
<mx:RemoteObject id=”amfcall” destination=”LTC” source=”LTC” endpoint=”YOUR ZENDAMF URL HERE” showBusyCursor=”true” />
Start a script tag and import all the libraries we’ll need.
import com.google.maps.InfoWindowOptions;
import com.google.maps.LatLng;
import com.google.maps.Map;
import com.google.maps.MapEvent;
import com.google.maps.MapMouseEvent;
import com.google.maps.MapType;
import com.google.maps.controls.ZoomControl;
import com.google.maps.overlays.EncodedPolylineData;
import com.google.maps.overlays.Marker;
import com.google.maps.overlays.MarkerOptions;
import com.google.maps.overlays.Polyline;
import com.google.maps.overlays.PolylineOptions;
import com.google.maps.styles.FillStyle;
import com.google.maps.styles.StrokeStyle;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
As well as some variables we’re going to use later on (for all I know, I could define these in the actual functions, but I’m lazy and didn’t check)
public var origmilliseconds:Number;
public var dayString:String;
public var content:String;
public var weekDayLabels:Array = new Array(“Sun”,
“Mon”,
“Tue”,
“Wed”,
“Thu”,
“Fri”,
“Sat”);
For our initial function, we’re going to center the map on London Ontario and create 3 buttons. One for each route, and one to clear all our map overlays. We’ll also add a Zoom Control (not needed, but I personally prefer it to using the mouse wheel to zoom)
private function onMapReady(event:Event):void {
this.map.addControl(new ZoomControl());
this.map.setCenter(new LatLng(42.979398,-81.246138), 12, MapType.NORMAL_MAP_TYPE);
createButton(“21/15”, 0, 0, function(event:Event):void { showTwentyOne(); });
createButton(“17”, 100, 0, function(event:Event):void { showSevenTeen(); });
createButton(“Clear”, 200, 0, function(event:Event):void { clearOverlays(); });
}

And while we’re at it, we’ll make our Clear Overlay function since it’s really simple.

private function clearOverlays():void{

map.clearOverlays();

}

The next bit of code specifies how the buttons we just created will look. It’s pretty self explanatory (colors, size, position, etc.)

private function createButton(text:String,x:Number,y:Number,callback:Function):void {

var button:Sprite = new Sprite();

button.x = x;

button.y = y;

var label:TextField = new TextField();

label.text = text;

label.x = 2;

label.selectable = false;

label.autoSize = TextFieldAutoSize.CENTER;

var format:TextFormat = new TextFormat(“Verdana”);

label.setTextFormat(format);

var buttonWidth:Number = 100;

var background:Shape = new Shape();

background.graphics.beginFill(0xFFFFFF);

background.graphics.lineStyle(1, 0x000000);

background.graphics.drawRoundRect(0, 0, buttonWidth, 18, 4);

background.graphics.endFill();

button.addChild(background);

button.addChild(label);

button.addEventListener(MouseEvent.CLICK, callback);;

map.addChild(button);

}

Next we’ll define our route. Google Maps uses a weird algorithm to define waypoints and paths, but fortunately they made a tool to make them really easily and spit out the code you need here. For the 21/15 route, this is the function/algorithm I used. (It gets a little wacky)

private function showTwentyOne():void{

//21 ROUTE START

var twentyonePoints:String = “eiqeGnkunNeRebAtN{FsIyd@tDuWwSaCgHsAiBVe@{BgFlCiCpEcA~EuAhKrDdCnBhGlApGlBzBrBlLBnBu@~DxIxCfD?tEgAfa@jvBbd@{Pn|@n{E`cAia@d_@c@xh@sSxFpYtd@yQbEnTp@lc@bcAiG|@l[fGbyAlHs@bM`CjKgBxHnBpJcAzEiC|AdP}@jW?xQpA|[“;

var twentyoneLevels:String = “BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB”;

var twentyonePolyline:Polyline = Polyline.fromEncoded(

new EncodedPolylineData(twentyonePoints, 32, twentyoneLevels, 4),

new PolylineOptions({ strokeStyle: new StrokeStyle({

color: 0x0000ff,

thickness: 4,

alpha: 0.7})

}));

map.addOverlay(twentyonePolyline);

getStops(21);

}

Then we’ll run the “getStops” function that gets all out stops from the database and displays them as overlays on the map.

private function getStops(route:Number):void{

var tok:AsyncToken = amfcall.getStops(route);

tok.addResponder(new AsyncResponder(getStopsWin, somethingfail, tok));

}

Using AsyncToken, we use PHP to generate the list of stops from the DB and bring them back as XML. Google Maps uses longitude and latitude so we’ll be bring those coordinates back from the database.

private function getStopsWin(event:ResultEvent, token:AsyncToken):void{

var xml:XML = XML(event.result);

var xmlList:XMLList;

xmlList = xml.children();

for(var i:int=0; i<xmlList.length(); i++)

{

map.addOverlay(createStop(xmlList.stopID[i],new LatLng(xmlList.lat[i],xmlList.lang[i]),””));

}

}

private function createStop(stopID:int, latlng:LatLng, content:String):Marker {

var marker:Marker = new Marker(latlng);

marker.addEventListener(MapMouseEvent.CLICK, function(e:MapMouseEvent):void {

var tok:AsyncToken = amfcall.getTimes(stopID);

tok.addResponder(new AsyncResponder(getTimesWin, somethingfail, tok));

});

return marker;

}

As an extra feature, we’re going to calculate the approximate time that the next bus will appear to any given stop we click on. For this, we use the Date functions in AS3 to compare the current time with the bus times we have in the database for any given stop. I’m sure there is some easier way to compare times, but this is the way that works for me.

private function closestTime(now:Number, after:Number):int{

var difference:int = after – now;

difference = difference/1000;

difference = difference/60;

return difference;

}

private function getTimesWin(event:ResultEvent, token:AsyncToken):void{

var currentTime:Date = new Date();

var currentMilliseconds:Number = currentTime.valueOf();

var dayString:String = weekDayLabels[currentTime.getDay()];

var xml:XML = XML(event.result);

var xmlList:XMLList;

xmlList = xml.children();

for(var i:int=0; i<xmlList.length(); i++)

{

var time:String = xmlList.time[i]+” GMT-0″+(currentTime.getTimezoneOffset()/60)+”00 “+dayString+” “+(currentTime.month+1)+”/”+(currentTime.getDate())+”/”+currentTime.getFullYear();

var milliseconds:Number = Date.parse(time);

var minutesleft:int = closestTime(currentMilliseconds,milliseconds);

var latlng:LatLng = new LatLng(xmlList.lat[i],xmlList.lang[i]);

if (i==0){

var compareTime:int = minutesleft;

} else {

if(compareTime > minutesleft || compareTime < 0){

compareTime = minutesleft;

}

}

}

if(compareTime == 1){

content = compareTime+” minute left till the next bus”;

} else if(compareTime == 0){

content = “Bus should already be there!”;

}else {

content = compareTime+” minutes left till the next bus”;

}

var timeTitle:String = “Bus Stop”;

map.openInfoWindow(latlng, new InfoWindowOptions({titleHTML: timeTitle, contentHTML: content}));

}

The only thing that’s left to do, is add a fail function in case the PHP or MySQL doesn’t work right.

public function somethingfail(event:FaultEvent, token:AsyncToken):void{

Alert.show(“Uh oh, something went wrong on our side! Try again in a bit!”);//OH GAWD

}

Here’s the source files which include all this AS3 source code, PHP, and a SQL dump of the database I used.

If you have any questions or comments, let me know.

1 comment so far

Add Your Comment
  1. i am trying to insert google map in hyderabadcitybusroutes website..
    actually i inserted the map with an API key…but in that map i want to searech(locate) the places by entering in to the textbox..i dnt know how to get the geocode to my textbox..like google maps website..plz give me ideas or share the source code to get this…plz…today is deadline for me to solve this problem..plz let u people respond to my problem…thanks in advance.