Here's an update of my Earth Quake Heat Map. It is an example of two types of custom overlays for Google Maps (Flash API). Overlays in Google Maps are used for things like map markers or for superimposing an image, a polygon, or other data on top of the map. In my first attempt at the heat map, I superimposed Michael VanDaniker's heat map component on top of a Google map. However, I didn't do that as a map overlay, it was merely one component sitting on top of another component, inside a Flex Canvas.
The result of this was that sometimes the heat map would be drawn on top of the map controls (pan/zoom controls, etc). It was pretty apparent that the heat map wasn't actually a part of the Google map.
The solution was to make the heat map into a proper overlay by extending the OverlayBase class. Using composition, I added Michael VanDaniker's HeatMap to the overlay. The result is that now the heat map is rendered underneath the map's pan/zoom controls ... it is actually part of the map! Doing this also removed a layer of event handling, because the map automatically tells the overlay to redraw/reposition itself.
Extending OverlayBase
It's pretty straight forward for a simple overlay. Override two methods, and add two event handlers to detect when the overlay is added/removed.
- Override the
getDefaultPane()method
override public function getDefaultPane(map:IMap):IPane
{
return map.getPaneManager().getPaneById(PaneId.PANE_OVERLAYS);
}
This method is called by the map (I assume) to figure out which "pane" to put your overlay on. There are constants defined in the PaneID class for markers, overlays, etc.
- Override the
postionOverlay()method
override public function positionOverlay(zoom:Boolean):void
{
if (zoom)
{
heatMap.itemRadius = Math.max(20, Math.pow( pane.map.getZoom(),1.5));
}
// positioned at (0,0) by default
heatMap.width = (pane.map as Map).width;
heatMap.height = (pane.map as Map).height;
heatMap.invalidateProperties();
}
This method positions the overlay on the map. It's called frequently when the map is moved/zoomed, the docs suggest avoiding heavy calculations. You can also redraw your component here. For the heat map, the position was always 0,0 because we want the heat map overlay to cover the entire map. I used this method to tell the heat map to redraw it self. For a marker, you would obviously set the x,y coords of the marker's lat/lon.
- Add event handlers for
MapEvent.OVERLAY_ADDEDandMapEvent.OVERLAY_REMOVED
public function GHeatMapOverlay(heatMap:HeatMap)
{
super();
this.heatMap = heatMap;
addEventListener(MapEvent.OVERLAY_ADDED, handleOverlayAdded,false,0,true);
addEventListener(MapEvent.OVERLAY_REMOVED, handleOverlayRemoved,false,0,true);
}
private function handleOverlayAdded(event:Event):void
{
addChild(heatMap);
}
private function handleOverlayRemoved(event:Event):void
{
removeChild(heatMap);
}
HeatMap is a Flex component! This shouldn't work, should it?
You normally cannot create overlays or markers out of Flex components with the Google Maps API for Flash. To create a custom marker you could draw your own graphics (with say the graphics property of a Sprite) or use your own images/icons.
It turns out you can use some Flex components in overlays and map markers. These components, however, need to render themselves using the graphics property (my assumption as to why it works) ... Michael VanDaniker's heat map does just that. I'm really excited about discovering this, because the Degrafa framework also supports this! With a Degrafa GeometryComposition you can draw shapes targeted at the graphics property of a UIComponent, and add that UIComponenet to your maps!
In my next post, I'll show how I created a map marker with Degrafa by extending OverlayBase and implementing the IMarker interface. In the mean time, you can see the heat map overlay and Degrafa markers in action here. (View Source is enabled in the app.)
