Posted by Michael to Flash/Actionscript on June 2nd, 2008
For a project we're working on, it occured to us very early on that though we wanted the location accuracy of Google Maps, we didn't need the incredible detail that Google provides. We also knew that we wanted to have a more visually customized map.
Unfortunately, the GM API and docs dont give an overwhelming amount of information on how to create custom map types, and even less is available for the Flash API. But something you will realize quickly is that GM requires tiles, lots and lots of tiles, which are traditionally going to be hundreds of individually sliced PNG files.
Fortunately, the Flash API gives us an easier solution. The method used to create tiles (loadTile) returns a DisplayObject. Among other things, that means theres nothing to stop you from creating animated map tiles. The code below uses Bitmap objects, but the principle is the same.
We started by creating a vector map that matched up with the Google map at its most zoomed-out level (there are lots of free vector maps on the web to use as a starting point). This meant we had a 512 pixel wide vector world map. We instantiate the map in the TileLayer class, and from there, we simply used Google's math (256px tiles, 2^zoom number of tiles) to generate all of the tiles. The vector map overlay matches with the Google Map at every zoom from there on—no PNG files needed! Demo with sample code after the jump.
EDIT: Check out the example
Also, this experiment exposed a bug in the Flash API implementation, which was very quickly fixed by the folks at Google. It will surely be included in the 1.4 SDK but in the meantime, you can get the fix by just specifying the SDK version in the Map constructor (see VectorMap.as below).
VectorMap.as
public class VectorMap extends Map { public function VectorMap() { super(); version = "1.4"; addEventListener(MapEvent.MAP_READY, onMapReady); } private function onMapReady(e:MapEvent):void { var vectorMapType:IMapType = new VectorMapType(MERCATOR_PROJECTION); addMapType(vectorMapType); setMapType(vectorMapType); } }
VectorMapType.as
public class VectorMapType extends MapType { public function VectorMapType(mercator:IProjection) { var tileLayers:Array = new Array(); var tl:VectorMapTileLayer = new VectorMapTileLayer(); tileLayers.push(tl); var mto:MapTypeOptions = new MapTypeOptions({ alt: "VectorMap", errorMessage: "Could not load tile", maxResolution: 18, minResolution: 1, shortName: "VM", tileSize: 256 }); super(tileLayers, mercator, "VectorMap", mto); } }
VectorMapTileLayer.as
public class VectorMapTileLayer extends TileLayerBase { [Embed(source="../assets/sprites.swf", symbol='MapEmbed')] private var WorldMapEmbed :Class; private const MAP_BASE_WIDTH :uint = 512; private const TILE_WIDTH :uint = 256; private var _map :DisplayObject; public function VectorMapTileLayer() { var cc:CopyrightCollection = new CopyrightCollection(); super(cc, 1, 18, 1); _map = new WorldMapEmbed(); } public override function loadTile(tilePos:Point, zoom:Number):DisplayObject { var scaleFactor:Number = TILE_WIDTH * Math.pow(2, zoom) / MAP_BASE_WIDTH; var tileBMData:BitmapData = new BitmapData(TILE_WIDTH,TILE_WIDTH,false,0xffffff); var matrix:Matrix = new Matrix(); matrix.scale(scaleFactor, scaleFactor); matrix.translate(-tilePos.x * TILE_WIDTH, -tilePos.y * TILE_WIDTH); tileBMData.draw(_map, matrix); return new Bitmap(tileBMData); } }
View our full portfolio
Subscribe to our RSS feed
Contact us
3stripe on June 3rd, 2008 at 5:07 pm
Sounds cool, do you have a demo anywhere?
Michael on June 6th, 2008 at 12:39 am
updated with example, and AS code highlighting (w00t!)
Matt on July 7th, 2008 at 7:19 pm
Hey Michael,
Great stuff, but I am having a bit of trouble understanding the code.
What does the ‘WorldMapEmbed’ class do?
Also, could the scaling be avoided (like just zooming into a vector map)?
Thanks and great work!
-Matt Magpayo
Matt on July 7th, 2008 at 7:25 pm
Also, I was playing with the idea of using a vector map as an GroundOverlay. A zooming of the map would then trigger the overlay to be replaced with a zoomed up version of the vector map.
Any thoughts?
Michael on July 8th, 2008 at 10:02 pm
Matt,
The WorldMapEmbed class is just a reference to the embedded display object for the map (i.e. the map I made in Illustrator, brought into Flash and published into a SWF), which uses the standard Flex embed method, see http://www.adobe.com/devnet/fl.....ng_assets/. This is much the same idea as using a library item in a .fla.
And Im not totally clear what you mean by avoiding the scaling… but if you mean that the map loads by tiles even when using the vector version, no, this is unavoidable. But I find the loading of the vector tiles to be fast enough that its not really an issue.