This group and the posts here have been very helpful to me, so now is
my turn to help someone else. I modified the code of Pamela Fox for
loading KML into a google map. I've put it into an actionscript class
and made a few enhancements:
1) support setting opacity for polygons
2) support drawing polygon edges (or not)
3) fix KML namespace issue
4) draw custom marker icons (for placemarks)
5) easy to use class--just add it to your project and use it

You can just add GoogleMapKMLLoader.as to your project and use it to
display your kml inside Google Maps for Flash. Feel free to change the
package name from gov.noaa.kml to whatever you want, of course.

First, here is an example of the code you'll need in your mxml file
(mine is creatively called "main.mxml"):

      import gov.noaa.kml.GoogleMapKMLLoader;

      private var kmlLoader : GoogleMapKMLLoader = null;
      private var zoomControl : ZoomControl;
      private var mapTypeControl : MapTypeControl;
      private var kml : String = null;
      private var kmlLoader : GoogleMapKMLLoader = null;

      private function onMapInitialize(event:Event) : void
      {
        var mapOptions : MapOptions = new MapOptions();
        mapOptions.zoom = 5;
        mapOptions.center = new LatLng(38, -100);
        mapOptions.mapType = MapType.HYBRID_MAP_TYPE;
        map.setInitOptions(mapOptions);
      }

      private function onMapReady(event:Event) : void
      {
        zoomControl = new ZoomControl();
        mapTypeControl = new MapTypeControl();
        chkShowMapControls_clickHandler(null);
        map.addEventListener(MapMoveEvent.MOVE_END, onMapMoveEnd);
        map.openInfoWindow(map.getCenter(), new
InfoWindowOptions({title: "FIM MAPS", content: "Select the FIM data
you wish to view on the right and then press the 'Refresh Map'
button."}));
      }

      //if the user pans the map a significant amount, load new kml
      private function onMapMoveEnd(event:MapMoveEvent) : void
      {
        var center:LatLng = map.getCenter();
        var changeInLat : Number = Math.abs(center.lat() - centerLat);
        var changeInLon : Number = Math.abs(center.lng() - centerLon);
        var change : Number = changeInLat + changeInLon;
        var MAX_GRID_LEVEL : Number = 9;
        var currentGridLevel : Number = cbFimGridLevels.selectedIndex
+ 5;
        var maxChangeWithoutChangingView : Number = (MAX_GRID_LEVEL -
currentGridLevel + 1) * 2;

        if (change > maxChangeWithoutChangingView)
          btnRefresh_clickHandler(null);
      }

I have a web service I call that returns the KML as a string. Here is
the function that handles that web service call (on success):
      public function handleGetKMLSuccess(event:ResultEvent):void
      {
        kml = event.result.toString();
        kmlLoader = new GoogleMapKMLLoader(map, "FIM Map");
        kmlLoader.showPolygonEdges = true;
        kmlLoader.opacity = 0.5;  //50% opacity
        kmlLoader.loadKML(kml);
      }

Here's my Map object from the .mxml:
        <maps:Map xmlns:maps="com.google.maps.*" id="map"
mapevent_mappreinitialize="onMapInitialize(event)"
mapevent_mapready="onMapReady(event)" width="100%" height="100%"
key="<your google maps key goes here"/>

Below is my GoogleMapKMLLoader class. This class allows you to display
your KML within the map. Note that for my KmlPoints, I display a
custom "plane-icon.png" image. You could do your own custom marker
icon in your projects. Just swap out planeIcon for your own icon(s).
If you don't need custom marker icons, then delete the references to
plane-icon.png and the corresponding imgCls variable.

Another note. I use this class for drawing polygons in Google Maps,
and for that purpose, I have two public variables that can be set
before calling the main loadKML() method:
    public var showPolygonEdges : Boolean = true;
    public var opacity : Number = -1;
If you set showPolygonEdges=true, then the edges of polygons are drawn
(instead of simply the fill color). If you set the opacity to some
number (e.g. 0.5 for 50% opacity), then this opacity setting overrides
whatever is in your kml. For an example of what my kml looks like, see
the getSampleKML() function at the end of the class file.

Well, enough said. Here's the GoogleMapKMLLoader class:

package gov.noaa.kml
{
  import com.google.maps.LatLng;
  import com.google.maps.LatLngBounds;
  import com.google.maps.Map;
  import com.google.maps.extras.xmlparsers.kml.*;
  import com.google.maps.overlays.GroundOverlay;
  import com.google.maps.overlays.Marker;
  import com.google.maps.overlays.MarkerOptions;
  import com.google.maps.overlays.Polygon;
  import com.google.maps.overlays.PolygonOptions;
  import com.google.maps.overlays.Polyline;
  import com.google.maps.styles.FillStyle;
  import com.google.maps.styles.StrokeStyle;

  import flash.display.Loader;
  import flash.events.Event;
  import flash.net.URLRequest;

  import mx.core.BitmapAsset;

  /**
   * This class is based on the open source KMLParser.mxml written by
Google employee, Pamela Fox.
   * Jeff Smith adapted it into this class (OOP) form and added
support for alternative kml namespaces, setting the opacity,
   * turning on/off polygon edges, adding custom marker icons (for
placemarks).
   * Required Lib: GoogleMapsAPIUtilityLibrary_04262009.swc
   */
  public class GoogleMapKMLLoader
  {
    private var map : Map;
    private var markerTooltipMsg : String;
    private var kmlObj : Object;
    private const KML_NAMESPACE : String = "<kml xmlns='http://
earth.google.com/kml/2.2' xmlns:gx='http://www.google.com/kml/ext/2.2'
xmlns:atom='http://www.w3.org/2005/Atom'>";
    public var showPolygonEdges : Boolean = true;
    public var opacity : Number = -1;

    [Embed(source="assets/plane-icon.png")]
    [Bindable]public var imgCls : Class;


    public function GoogleMapKMLLoader(map : Map, markerTooltipMsg :
String)
    {
      this.map = map;
      this.markerTooltipMsg = markerTooltipMsg;
    }

    /**
     *  Swap out this: <kml xmlns='http://earth.google.com/kml/2.1'>
     *       For this: <kml xmlns='http://earth.google.com/kml/2.2'
xmlns:gx='http://www.google.com/kml/ext/2.2' xmlns:atom='http://
www.w3.org/2005/Atom'>
     * Without this namespace switch, Kml22 class returns
kml.feature=null
     */
    private function fixKMLNamespace(kmlStr : String) : String
    {
      var startPos : int = kmlStr.indexOf("<kml");
      var endPos : int = kmlStr.indexOf(">", startPos);
      var fixedKmlStr : String = kmlStr.substring(0, startPos) +
KML_NAMESPACE + kmlStr.substring(endPos+1, kmlStr.length);
      return(fixedKmlStr);
    }

    public function loadKML(kmlStr : String):void
    {
      map.clearOverlays();

      kmlObj = new Object();
      var fixedKmlStr : String = fixKMLNamespace(kmlStr);
      var kml:Kml22 = new Kml22(fixedKmlStr);
      var rootFeature:Feature = kml.feature;

      kmlObj.name = rootFeature.name;
      kmlObj.mapObjs = new Array();
      kmlObj.bounds = new LatLngBounds();

      if (canContainFeatures(rootFeature))
        kmlObj.children = getChildrenFeatures(Container(rootFeature));
      else
        associateWithMapObject(kmlObj, rootFeature);
    }

    private function getChildrenFeatures(container:Container):Array
    {
      var childrenFeatures:Array = new Array();
      for (var i:Number = 0; i < container.features.length; i++)
      {
        var feature:Feature = container.features[i];
        var childObj:Object = new Object();
        childObj.mapObjs = new Array();
        childObj.name = feature.name;
        if (childObj.name == null)
          childObj.name = getAlternateName(feature);

        if (canContainFeatures(feature))
          childObj.children = getChildrenFeatures(Container(feature));
        else
          associateWithMapObject(childObj, feature);
        childrenFeatures.push(childObj);
      }
      return childrenFeatures;
    }

    private function getAlternateName(feature:Feature):String
    {
      if (feature is Folder)
        return "Unnamed Folder";
      else if (feature is Document)
        return "Unnamed Document";
      else if (feature is Placemark)
      {
        var placemark:Placemark = Placemark(feature);
        if (placemark.geometry != null)
        {
          if (placemark.geometry is KmlPoint)
            return "Unnamed Point";
          else if (placemark.geometry is LineString)
            return "Unnamed Linestring";
          else if (placemark.geometry is LinearRing)
            return "Unnamed LinearRing";
          else if (placemark.geometry is KmlPolygon)
            return "Unnamed Polygon";
        }
        return "Unnamed Placemark";
      }
      else if (feature is
com.google.maps.extras.xmlparsers.kml.GroundOverlay::KmlGroundOverlay)
        return "Unnamed GroundOverlay";
      return "Unnamed Feature";
    }

    private function associateWithMapObject(obj:Object,
feature:Feature):void
    {
      // at this point it can either be a placemark or a groundoverlay
      if (feature is Placemark)
      {
        var placemark:Placemark = Placemark(feature);
        if (placemark.geometry != null)
        {
          var placemarkDesc : String = placemark.description;
          placemarkDesc = placemarkDesc.replace("<br>",
"\n").replace("<br/>", "\n");
          associateGeometryWithMapObject(obj, placemarkDesc,
placemark.geometry, placemark.styleUrl);
        }
      }
      else if (feature is KmlGroundOverlay)
      {
        var groundOverlay:KmlGroundOverlay =
KmlGroundOverlay(feature);
        var latLngBounds:LatLngBounds = new LatLngBounds(new
LatLng(groundOverlay.latLonBox.south,groundOverlay.latLonBox.west),
new
LatLng(groundOverlay.latLonBox.north,groundOverlay.latLonBox.east));
        updateLatLngBounds(obj, latLngBounds);

        var testLoader:Loader = new Loader();
        var urlRequest:URLRequest = new
URLRequest(groundOverlay.icon.href);
        testLoader.contentLoaderInfo.addEventListener
          (
            Event.COMPLETE,
            function(e:Event):void
            {
              obj.mapObject = new
com.google.maps.overlays.GroundOverlay::GroundOverlay(testLoader,
latLngBounds);
              map.addOverlay(obj.mapObject);
            });
        testLoader.load(urlRequest);
      }
    }

    private function getRGBFromKMLStyle(styleURL : String) : Number
    {
      if (styleURL == null)
        return(uint("0x008080"));
      else
      {
        var red : String = styleURL.substring(6, 8);
        var green : String = styleURL.substring(4, 6);
        var blue :  String = styleURL.substring(2, 4);
        var fillColor : Number = uint("0x" + red + green + blue);
        return(fillColor);
      }
    }

    private function associateGeometryWithMapObject(obj:Object,
placemarkDesc: String, geometry:Geometry, styleURL : String):void
    {
      var multiGeometry : MultiGeometry = null;
      var isMultigeometryOfOnePolygon : Boolean = false;
      if (geometry is MultiGeometry)
      {
        multiGeometry = MultiGeometry(geometry);
        if (multiGeometry.geometries.length == 1)
          isMultigeometryOfOnePolygon = true;
      }

      var polyline:Polyline;
      var fillAlpha : Number;
      if (styleURL != null && styleURL.charAt(0) == '#')
      {
        styleURL = styleURL.substr(1, styleURL.length);
        fillAlpha = parseInt(styleURL.substr(0, 2), 16) / 256.0;
      }
      else
      {
        styleURL = "FF0000a1";
        fillAlpha = 0.75;
      }

      if (opacity >= 0)  //if opacity level set, then use it
(overriding what is in the KML)
        fillAlpha = opacity;

      var thisFillStyle: FillStyle = new FillStyle();
      thisFillStyle.alpha = fillAlpha;
      thisFillStyle.color = getRGBFromKMLStyle(styleURL);
      var thisStrokeStyle : StrokeStyle = new StrokeStyle();
      if (showPolygonEdges)
        thisStrokeStyle.alpha = 0.8;
      else
        thisStrokeStyle.alpha = 0.0;
      thisStrokeStyle.color = 0xffffff;

      if (geometry is KmlPoint)
      {
        var point:KmlPoint = KmlPoint(geometry);
        var latlng:LatLng = new
LatLng(point.coordinates.coordsList[0].lat,
point.coordinates.coordsList[0].lon);

        var markerOptions : MarkerOptions = new MarkerOptions();
        var planeIcon : BitmapAsset = new imgCls() as BitmapAsset;
        markerOptions.icon = planeIcon;
        markerOptions.tooltip = markerTooltipMsg + latlng;
        markerOptions.iconAlignment =
MarkerOptions.ALIGN_HORIZONTAL_CENTER;
        markerOptions.hasShadow = true;
        markerOptions.radius = 12;
        var marker: Marker = new Marker(latlng, markerOptions);

        obj.mapObjs.push(marker);
        updateLatLngBounds(obj, new LatLngBounds(latlng, latlng));
        map.addOverlay(obj.mapObjs[obj.mapObjs.length -1]);
      }
      else if (geometry is LineString)
      {
        var lineString:LineString = LineString(geometry);
        polyline = new
Polyline(getCoordinatesLatLngs(lineString.coordinates));
        obj.mapObjs.push(polyline);
        updateLatLngBounds(obj, polyline.getLatLngBounds());
        obj.center = polyline.getLatLngBounds().getCenter();
        obj.bounds = polyline.getLatLngBounds();
        map.addOverlay(polyline);
      }
      else if (geometry is LinearRing)
      {
        var linearRing:LinearRing = LinearRing(geometry);
        polyline = new
Polyline(getCoordinatesLatLngs(linearRing.coordinates));
        obj.mapObjs.push(polyline);
        updateLatLngBounds(obj, polyline.getLatLngBounds());
        map.addOverlay(polyline);
      }
      else if (geometry is KmlPolygon || isMultigeometryOfOnePolygon)
      {
        var kmlPolygon : KmlPolygon;

        if (isMultigeometryOfOnePolygon)
        {
          multiGeometry = MultiGeometry(geometry);
          kmlPolygon = multiGeometry.geometries[0];
        }
        else
          kmlPolygon = KmlPolygon(geometry);

        var polygonOptions : PolygonOptions = new
PolygonOptions({fillStyle:thisFillStyle, strokeStyle:thisStrokeStyle,
tooltip:placemarkDesc});
        var polygon : com.google.maps.overlays.Polygon = new
com.google.maps.overlays.Polygon(getCoordinatesLatLngs(kmlPolygon.outerBoundaryIs.linearRing.coordinates),
polygonOptions);
        obj.mapObjs.push(polygon);
        updateLatLngBounds(obj, polygon.getLatLngBounds());
        map.addOverlay(polygon);
      }
      else if (geometry is MultiGeometry)
      {
        multiGeometry = MultiGeometry(geometry);
        for (var i:uint = 0; i < multiGeometry.geometries.length; i++)
{
          associateGeometryWithMapObject(obj, placemarkDesc,
multiGeometry.geometries[i], styleURL);
        }
      }
    }

    private function
getCoordinatesLatLngs(coordinates:Coordinates):Array
    {
      var latlngs:Array = new Array();
      for (var i:Number = 0; i < coordinates.coordsList.length; i++)
      {
        var coordinate:Object = coordinates.coordsList[i];
        latlngs.push(new LatLng(Number(coordinate.lat),
Number(coordinate.lon)));
      }
      return latlngs;
    }

    private function updateLatLngBounds(obj:Object,
bounds:LatLngBounds):void
    {
      if (obj.bounds)
        obj.bounds.union(bounds);
      else
        obj.bounds = bounds;
      kmlObj.bounds.union(bounds);
    }

    private function canContainFeatures(feature:Feature):Boolean
    {
      return (feature is Container);
    }

    //this function is useful for debugging. It is not currently
called.
    public function getSampleKML() : String
    {
      return("<?xml version='1.0' encoding='UTF-8'?> " +
        "<kml xmlns='http://earth.google.com/kml/2.1'> " +
        "<Document> " +
        "<name>FIM Earth Grid Level 5</name> " +
        "<Style id='7F008000'><LineStyle><color>60FFFFFF</
color><width>1.0</width></LineStyle><PolyStyle><color>7F008000</
color></PolyStyle></Style> " +
        "<Placemark> " +
        "  <name>FIM Grid Cell 1</name> " +
        "  <description>TEMP=295.9104></description> " +
        "  <open>false</open> " +
        "  <styleUrl>#7F008000</styleUrl> " +
        "  <MultiGeometry>  " +
        "    <Polygon> " +
        "      <altitudeMode>absolute</altitudeMode> " +
        "      <outerBoundaryIs> " +
        "      <LinearRing> " +
        "        <coordinates>-98,41.953,35000 -98,40.723,35000
-96.46,39.997,35000 -94.883,40.681,35000 -94.826,41.911,35000
-96.393,42.659,35000 -98,41.953,35000</coordinates> " +
        "      </LinearRing> " +
        "      </outerBoundaryIs> " +
        "    </Polygon> " +
        "  </MultiGeometry> " +
        "</Placemark> " +
        "</Document> " +
        "</kml>");
    }

  }
}

-- 
You received this message because you are subscribed to the Google Groups 
"Google Maps API For Flash" group.
To post to this group, send email to google-maps-api-for-fl...@googlegroups.com.
To unsubscribe from this group, send email to 
google-maps-api-for-flash+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-maps-api-for-flash?hl=en.

Reply via email to