nwebb

Flex, Flash, AIR

GoogleMaps 101

GoogleMaps 101

I've already covered some of the basics for getting up and running with the new GoogleMaps AS3 API in Flex, with a Hello World example and an explanation of how to get rid of "Debug Mode" text / geocode when testing locally.

My experiences so far have been really positive. The documentation is well written, and although the AS3 API isn't as fully featured as it's counterpart, the team are bug fixing and adding features on a daily basis (plus taking requests, so be sure to check out the group). You shouldn't really have any major problems getting to grips with the code and finding out what you need. The purpose of this post is simply to distil what I thought may be the most sought after bits of code, in to a handy post.


GoogleMap tips

The code (from point 3 onwards) is taken from this application

1. Adding the GoogleMaps .swc to your project in FlexBuilder 3 is really easy!

2. After you have obtained your key, you can then create your new map. You will need to add it to the stage as the child of a UIComponent:

Actionscript:
  1. //as3 code
  2.         _map = new Map();
  3.         mapContainer.addChild(_map);
  4.  
  5. //mxml code
  6.         <mx:UIComponent id="mapContainer" width="100%" height="100%"/>;
  7.  
  8. /************************************************************
  9. Note: Alternatively you can create a map component by subclassing UIComponent
  10. as shown here: http://www.igorcosta.org/?p=140
  11. *************************************************************/

All code from here-on-in assumes we have created our own map component by subclassing UIComponent - see here for an example.

3. You cannot interact with your map until it is ready! To know when this happens you need to listen out for the MapEvent.MAP_READY event:

Actionscript:
  1. private function init(event:Event):void
  2. {
  3.         _map = new Map();
  4.         _map.key = "paste your key here";
  5.         _map.addEventListener(MapEvent.MAP_READY, onMapReady);
  6.         _map.setSize( new Point (this.width, this.height))
  7.         this.addChild(_map); //add as child of UIComponent
  8. }

4. Once we know our map is ready we can set it up by instantiating controls, adding markers to it and so on. Below is the code needed to centre the map on a particular location as well as add the familiar GoogleMap controls such as the zoom slider and map-type buttons (we'll talk more about locations and LatLng in a moment):

Actionscript:
  1. private function onMapReady(event:Event):void
  2. {
  3.     _map.setCenter( new LatLng(54.4700,-3.4277), 14, MapType.PHYSICAL_MAP_TYPE);
  4.     _map.addControl(new ZoomControl());
  5.     _map.addControl(new PositionControl());
  6.     _map.addControl(new MapTypeControl());
  7.     _map.setZoom(5);
  8.    
  9.         //dispatch event from our map component so that we know basic setup is complete
  10.     dispatchEvent(new Event(Event.COMPLETE));
  11. }

5. Whether you are centring your map as in the above example, or placing a marker on the map, you will at some point need to deal with latitude and longitude. Essentially they are number representing your location on the map. Latitude is used to express how far north or south you are and longitude shows your location in an east-west direction, relative to the Greenwich meridian.

I found the following resources useful for calculating latlng:

http://www.capelinks.com/cape-cod/maps/geocode/ - type the address in to the top input box, and the latitude/longitude appear in xml tags at the bottom of the page

http://www.satsig.net/maps/lat-long-finder.htm - this is useful for when you don't know the address. Drag the map around and it gives you both lat and lng. If you put it in to your map and it doesn't look the same, that's probably due to your zoom level, which you can set.

6. Geocoding is the process of taking an address in the form of a String, and having it converted to lat and lng. You may be thinking "cool, I'll just geocode everything", but a word of warning: Google's geocoder has a max number of queries per second, so it's not wise to loop over addresses and goecode them all. Plus geocoding is an aysnchronous operation, so bear your user in mind and don't make them wait that long. Instead, convert addresses to lat and lng in advance where possible. The tools mentioned above will help - or you can build your own of course :]

Read this thread for information of a geocoding bug ... it will hopefully be fixed by the time you read this post

7. Creating markers is something you will very likely want to do when you've got your map up and running. Here is a quick overview of how I went about it.

First off is a snippet of the xml. Note that I set isBranch="false" on the point nodes - this is so they show as leaf-nodes and not branch nodes in the Flex Tree component...

Actionscript:
  1. //EXAMPLE OF XML STRUCTURE...
  2. <group label="offices" color="0x00FF00">
  3.     <point label="Winchfield Lodge" isBranch="false">
  4.         <address lat="51.284920" lng="-0.909787">Some address</address>
  5.         <phone>12345678</phone>
  6.         <fax>12345678</fax>
  7.         <email>email@address.com</email>
  8.     </point>
  9.     <point label="Hartham Park" isBranch="false">
  10.         <address lat="51.448433" lng="-2.199214">Another address</address>
  11.         <phone>12345678</phone>
  12.         <fax>12345678</fax>
  13.         <email>email@address.com</email>
  14.     </point>
  15. </group>

Next we have the code in the main application file. I send in an XMLList of the point nodes, loop through each one, generate a marker object, extract the latitide and longitude, and then call a method on my map component:

Actionscript:
  1. //CODE WITHIN MY MAIN APPLICATION FILE
  2. /**
  3. * Creates and places markers on the map.
  4. */
  5. private function plotMarkers(points:XMLList):void
  6. {
  7.     for each(var item:XML in points)
  8.     {
  9.         var markerOptionObj:MarkerOptions = getMarkerObject(item);
  10.         var lat:Number = Number(item.address.@lat);
  11.         var lng:Number = Number(item.address.@lng);
  12.         mapComp.setMarkerFromLatAndLng(lat,lng, markerOptionObj);
  13.     }
  14. }
  15.  
  16. /**
  17. * @return An object which specifies the visual attributes of the marker
  18. * (e.g. colour & roll-over text)
  19. */
  20. private function getMarkerObject(item:XML):MarkerOptions
  21. {
  22.     var markerOptionObj:MarkerOptions = new MarkerOptions
  23.                 ({
  24.                     fillStyle:{color:Number(item.parent().@color)},
  25.                     label:item.@label.substr(0,1).toUpperCase().toString(),
  26.                     labelFormat:{color:0x000000, bold:true},
  27.                     strokeStyle:{thickness: 2, color: 0x333333},
  28.                     tooltip: String(item.@label)
  29.                 });
  30.     return markerOptionObj;
  31. }

Finally here is the code within my map component. It takes the lat, lng and marker options object and generates a marker. I also add each marker to an ArrayCollection, to make it easy to loop over the markers later.

Actionscript:
  1. //CODE WITHIN MY MAP COMPONENT
  2. /**
  3. * This takes lat and lng and places a marker at that location.
  4. * @param   lat                The latitude of the marker.
  5. * @param   lng                The longitude of the marker.
  6. * @param   markerOptionObj    An object of type MarkerOptions, defining how the marker should look.
  7. * @return  A reference to the Marker instance created.
  8. */
  9. public function setMarkerFromLatAndLng(lat:Number, lng:Number, markerOptionObj:MarkerOptions = null):void
  10. {
  11.     var latlng:LatLng = new LatLng(lat, lng);
  12.     var marker:Marker = new Marker(latlng);
  13.     marker.addEventListener(MapMouseEvent.CLICK, onMarkerClick);
  14.         if(markerOptionObj != null) marker.setOptions(markerOptionObj);
  15.         _map.addOverlay(marker);
  16.         _markers.addItem(marker); // add to ArrayCollection
  17. }

Hopefully this will give you enough info to get on with building your own map using the API. Any questions related to this post please feel free to leave a comment :]

8 comments

8 Comments so far

  1. [...] GoogleMaps 101 [...]

  2. Chris May 25th, 2008 5:10 pm

    Thanks for this post…it was helpful! I have a related question: Can I assign custom variables to the marker and/or how do I pass an existing MarkerOption on the mousec lick event?

    I’ve been able to call a function on the mouse click, but I can’t pass a variable with it. When the user clicks on the marker, I want to capture a unique ID from the marker (that I assign) and then query my database on that ID.

    Thanks

  3. S.P. May 27th, 2008 3:19 am

    I’m a beginner about AS.
    Could you show me complete code in TXT?

  4. Chris May 27th, 2008 9:39 pm

    I figured out how to do what I wanted:

    marker.addEventListener(MapMouseEvent.CLICK, function(e:MapMouseEvent):void {
    my_function(parameter);
    });

  5. nwebb May 28th, 2008 7:31 am

    @Chris. Glad you sorted it. You could also use a hash array. For example:

    private function createMarker(id:String, latLng:LatLng):void
    {
    var marker:Marker = new Marker(latLng);
    myHash[id] = marker;
    }
    or even use the label property of your marker as your id, but that would not suit all scenarios.

  6. nwebb May 28th, 2008 7:39 am

    @SP – Hi, if you’re a beginner, try the “Hello World!” tutorial here :)
    http://nwebb.co.uk/blog/?p=193

  7. Dan June 6th, 2008 3:42 am

    Has anyone else contacted Google about updating their crossdoman policy files to meet the new player spec?

  8. Manu June 7th, 2008 11:22 am

    Thanks for this helpful post. Although I am stuck at one point, that is, the map displayed in my application is not draggable, neither i can change map type. Although, I can see all these controls on my map and clicking them doesn’t give me any results.

    Here is where I am adding these controls(as in your code):

    private function onMapReady(event:Event):void {
    _mapa.setCenter( new LatLng(1.365580,103.827713),14,MapType.NORMAL_MAP_TYPE);
    _mapa.enableScrollWheelZoom();
    _mapa.enableContinuousZoom();
    _mapa.addControl(new ZoomControl());
    _mapa.addControl(new PositionControl());
    _mapa.addControl(new MapTypeControl());
    _mapa.setZoom(10);
    dispatchEvent(new Event(Event.COMPLETE));
    }

    So, after adding these controls, do I need to listen for these events? As I couldn’t find anywhere someone handling these events in there examples, which are draggable,zoomable and all.

    Thanks.

Leave a reply

Bad Behavior has blocked 517 access attempts in the last 7 days.