For the past year, I have been working on a client project that utilized the Google Maps for Flash API. One issue that I hoped to address was the sluggishness that results from instantiating 100+ instances of com.google.map.overlays.Marker. The forums have a few threads discussing this topic. Digging into them, you immediately get the idea to not use Google’s Marker class, but rather a single instance of a custom class you create that extends OverlayBase. This class would then create markers as instances of Sprite. You would override the OverlayBase’s positionOverlay() method to reposition your markers. This technique allowed us to achieve a few hundred interactive markers before the application became noticeably sluggish.
Getting to the next level of supporting 1,000+ interactive markers, however, was a much more difficult task. There was this thread, where Jonathan Wagner described the use of bitmap tiles. He went further by providing an example and sharing his code. Unfortunately, while the example achieved an ultra-high number of markers, the markers were not interactive. However, it certainly pointed me in the right direction.
Basically, what you need to do is create 256 x 256 bitmaps that will exactly overlay the 256 x 256 bitmap tiles that Google serves up for their map.
When each marker was its own instance of Sprite, you could easily register event listeners for the MouseEvents. However, with a bitmap that can contain several markers, you have to get more creative. More on that below.
The classes are:
Your application creates an instance of MarkerTileLayer. It also creates an instance of com.google.maps.overlays.TileLayerOverlay, passing in the MarkerTileLayer as a parameter.
markerTileLayer = new MarkerTileLayer(map);
tileLayerOverlay = new TileLayerOverlay(markerTileLayer);
The TILES_LOADED event listener is important because it is how we keep the number of Tile instances under control by calling markerTileLayer.disposeOffscreenCachedTiles().
In the addMarkers() method, I create instances of Marker. The constructor takes two parameters: the LatLng and BitmapData. I add the event listeners for Marker.MARKER_CLICK and Marker.MARKER_HOVER directly to the Marker instances.
So my application only deals directly with two of the four classes in the above list: MarkerTileLayer and Marker.
MarkerTileLayer deals with the other two classes: MarkerGroup and Tile.
MarkerGroup is pretty simple. It is a group of Marker objects that are contained by a LatLngBounds. Both of these are passed into the MarkerGroup constructor. It then exposes a public method whose signature is
Tile is more complex. Tile extends Sprite and is the DisplayObject that gets returned from
MarkerTileLayer has a setter for the markers Array. This is where I break up the Markers into MarkerGroups. I use MarkerGroups so that the MarkerTileLayer.loadTile() method does not have to cycle through every Marker instance to check if it should be rendered onto that Tile. Instead, it can check a smaller number of MarkerGroups. If the MarkerGroup’s latLngBounds does not intersect the Tile, then the entire MarkerGroup can be skipped.
When a marker is clicked, figuring out which marker is tricky. You just need to register an event listener on the Marker instance for Marker.MARKER_CLICK, but underneath the hood MarkerTileLayer has event listeners on the Tile. When a Tile is clicked, it must determine which Marker. It does this in the method Tile.getTopmostMarkerAtPoint().
One issue I have found is that if a Marker has a pixel with an alpha value of less than 1.0, and that pixel is the one clicked, and the Marker overlaps another Marker, then the Tile.getTopmostMarkerAtPoint() does not return the Marker (and thus the Marker does not dispatch any event).
I have commented the code pretty well. Here are the application and source code. Be sure to try a larger number of markers than the default 500. On my machine, performance is excellent up to 5,000 and still very good at 10,000 and 20,000 (with only a slight stutter when zooming).
A major challenge is still animated markers. I have a solution to accommodate limited animation (4 frames) which I hope to go over in a future blog post. Basically each Tile has 4 BitmapData objects and swaps them out on the ENTER_FRAME event.