Monday, February 2, 2009

Custom Google Map Markers, Made Easy with Degrafa

Last week I realized that I could create map markers using the Google Maps API for Flash and the Degrafa framework. I believe creating interactive markers in MXML this way is much easier than the alternatives.

I whipped up this example app, which shows how to extend OverlayBase and implement the IMarker interface. Read here for my comments about extending OverlayBase. The IMarker interface is mostly self explanatory, however, there were a couple of methods I did not bother implementing.

I'd also like to mention that in my experiments I was able to add numerous Flex components to a Google Map: Canvas, Panel, Button, TextInput, etc! It's quite wonky, but it works to some degree. More on this later...

Caveats with these markers

  • Need to figure out how to change the "z order" (or child order) of markers when they are clustered close together (like the real Marker class does).
  • If using these w/MarkerManager, you need to modify the method signatures in MarkerManager to accept IMarker instead of Marker.
  • These are the result of an afternoon's experiments, the code is not necessarily optimal.

I'm still wrapping my head around all the things you can do with Degrafa. The more I work with it, the more I like it.

Cheers,

Sunil

Friday, January 30, 2009

Creating Map Overlays with the Google Maps API for Flash

This 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_ADDED and MapEvent.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.)

Sunday, January 25, 2009

Earthquake Heat Map

Update: An updated application which creates the heat map as a Google map overlay. Read about it here.

The United States Geological Survey (USGS) publishes data on recent earthquakes through various RSS feeds. I came across this recently when I thought I had felt an earthquake. This was a nice opportunity to do something with a heat map, I thought... So I made this mashup with Google Maps and the USGS data.

Nerdy Details

I used a nice heat map component from Michael VanDaniker, the Google Maps Flash API, the AS3 MarkerManager, and Cairngorm. Using the Cairngorm framework was probably a little overkill for a small project like this... but at least it's ready to go if I want to add more functionality.

As usual, you can view the source by right clicking on the app. Click here, or the image above to launch the map.

Monday, January 12, 2009

A Simple Degrafa Color Picker

A comment from my last post suggested I check out com.degrafa.paint.palette.PaletteUtils. Thank you so very much, gwd, for pointing that out! PaletteUtils is very cool! I wish I would have known about it a couple of months ago when I wrote my own color generating code.

PaletteUtils has some static methods that will return an array of colors:

  • getCategoryPalette()
  • getCoolPalette()
  • getHotPalette()
  • getHSBPalette()
  • getInterpolatedPalette()

Below is an example of a simple color picker that uses PaletteUtils to generate colors. Note that I had to fix a few issues with getHSBPalette() and getCategoryPalette() (issues in Degrafa Beta 3, for which I've filed some bugs).

Right click on the app to view the Flex source. Click here for a larger version.

Note: some of the sliders (like Saturation2) are only used in conjunction w/some of the palettes.