Using Google Maps API in Actionscript 3.0 to render images

November 21, 2008 at 9:31 am 8 comments

So, as some of you know, I’ve been working on inventoriana.com for a while now. In its new iteration, I am trying to shake of some of the problems of the existing version – one of the most important of which is allowing images of arbitrary size to be displayed and navigated easily.

Taking a page from the playbook of the Center for Hellenic Studies, I’ve been playing with Google Maps. They have a nice, easy to use interface, and the added luxury of playing well with ActionScript 3.0 and Flash (which much of inventoriana is currently implemented in).

So this is a little bit of documentation for anyone who wants to just render images in flash using the Google Maps API. If javascript is enough for you, you can also pay a visit to University College London, which has developed a number of handy tools (one of which I will use shamelessly here). I hope it helps, since the online documentation for google maps is a bit obscure

Step 1: Get a Google Maps API Key

This part is easy: sign up at http://code.google.com/apis/maps/signup.html. All you have to do is name your website, and agree to the terms of service.

Step 2: Get the Flash Component

Again, no problem: get the SDK at http://maps.googleapis.com/maps/flash/release/sdk.zip

Step 3: Chop up an Image

This is a bit tricky with existing tools. On the one hand, there is a really good utility called the Google Maps Image Cutter which will run in batch mode as well as interactive mode, and also lets you define the depth of image that you want. On the other hand, it spits out filenames in a nonstandard format, which you can figure out with a little bit of head scratching.

What you really want are filenames of the format

{zoom}-{x}-{y}.jpg

which will make writing the actionscript a breeze. This is how zoomify spits out its images, but you can’t control the depth of resolution, at least not with the export feature of Photoshop CS3 (buying the component is another question).
So you can use this php script from the command line to convert them:

<?php

// Takes a directory and copies the files from the GMap Image Cutter name format to the easier to use other one.
// usage: g2z source-directory target-dir

$source_directory = $_SERVER['argv'][1];
$target_directory = $_SERVER['argv'][2];
$dh = opendir($source_directory);

while (false !== ($file = readdir($dh))) {

if (!strstr($file,’.jpg’)) {continue;}

// Zoom Level determined by length of filename.
$zoom = strlen($file) – 4;
$file_munge = substr($file,0,$zoom);

$x_arr = array(‘q’ => 0,
‘r’ => 1,
‘s’ => 1,
‘t’ => 0);

$y_arr = array(‘q’ => 0,
‘r’ => 0,
‘s’ => 1,
‘t’ => 1);
// The beginning t doesn’t count, throw it away.

$location = substr($file_munge,1,$zoom);

// In php5 we could just call str_split. sigh.

$x = 0;
$y = 0;
for ($i = 0; $i < $zoom – 1; $i++) {

$x = $x +  pow(2,($zoom – 2 – $i)) * $x_arr[substr($location,$i,1)];
$y = $y +  pow(2,($zoom – 2 – $i)) * $y_arr[substr($location,$i,1)];

}

$newName = $zoom . ‘-‘ . $x . ‘-‘ . $y . “.jpg”;
echo “$file copy to $newName \n”;
copy($source_directory .’/’ . $file, $target_directory . ‘/’ . $newName);
}

?>

Step 4: Write a .swf

This is pretty similar to the .swf that Pamela Fox over at Google has shown for doing custom overlays, but is different primarily because we want to define a custom map type that overwrites the normal map (after all, you don’t want Greenland poking through your image if your picture isn’t big enough).

So just open up flash, and save a .fla named GoogleMapExperiment.fla (or whatever — make sure that it is ActionScript 3.0). All you need to do is add some actionscript to the first frame:

import com.google.maps.LatLng;
import com.google.maps.Map;
import com.google.maps.MapEvent;
import com.google.maps.MapType;
import com.google.maps.MapTypeOptions;
import com.google.maps.InfoWindowOptions;
import com.google.maps.controls.*;
import com.google.maps.overlays.*;
import com.google.maps.interfaces.*;
import com.google.maps.*;

import inventoriana.FolioTilesBase; // We’ll define this in the next step.

var map:Map = new Map();
map.key = “your-key-here”;
map.setSize(new Point(stage.stageWidth, stage.stageHeight));
map.addEventListener(MapEvent.MAP_READY, onMapReady);

this.addChild(map);

function onMapReady(event:Event):void {
map.setCenter(new LatLng(0,0), 2, MapType.NORMAL_MAP_TYPE);
map.addControl(new ZoomControl());
map.addControl(new PositionControl());
map.addControl(new OverviewMapControl());

// We actually do two things here: We define an overlay Tile Base, which spits out the

// tiles to the appropriate place, and then we also define a map type.

var inventorianaFolioTilesBase:FolioTilesBase = new inventoriana.FolioTilesBase();
var tileLayers:Array = new Array();
tileLayers.push(inventorianaFolioTilesBase);

var inventorianaMapType:MapType = new MapType(tileLayers,map.MERCATOR_PROJECTION,”Inventoriana”);
inventorianaFolioTilesBase.setMapType(inventorianaMapType);

var inventorianaOverlay:TileLayerOverlay = new TileLayerOverlay(inventorianaFolioTilesBase, 256, map.MERCATOR_PROJECTION);

map.addMapType(inventorianaMapType);
map.setMapType(inventorianaMapType);
map.addOverlay(inventorianaOverlay);

}

Step 5: Write your high-fallutin’ action script

Then, save this package in a directory named ‘inventoriana/FolioTilesBase.as3′

package inventoriana {
import com.google.maps.Alpha;
import com.google.maps.TileLayerBase;
import com.google.maps.CopyrightCollection;
import com.google.maps.interfaces.*;
import flash.geom.Point;
import flash.display.*;
import flash.net.*;
import flash.events.IOErrorEvent;
import flash.events.IEventDispatcher;
import flash.events.Event;

public class FolioTilesBase extends TileLayerBase {
public function FolioTilesBase() {
// For now, Inventoriana will just load six layers of zoom.
// In theory, it could get this info from the folio table in the database.
super(new CopyrightCollection(“Inventoriana.com”),2,8);
}

public override function loadTile(tilePos:Point, zoom:Number):DisplayObject {
var loader:Loader = new Loader();
configureListeners(loader.contentLoaderInfo);

// Here is where you specify what directory to look in for the tiles.
// Obviously you could do this dynamically if you are talking to a DB.

var tileUrl:URLRequest = new URLRequest(‘your file directory’);
loader.load(tileUrl);
return loader;
}

private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, _secondaryLoad);
}
private function _secondaryLoad(event:IOErrorEvent):void {
// Whatever error handling you want here if  an image fails to load.
}

}

}

Step 6: Make a Martini.

No promises that this will be remotely useful for your application, but if it is, or even if it isn’t, you can kick it Bond style with a Martini.

About these ads

Entry filed under: technology. Tags: , , , .

Zoe Lang’s Guest Blog: Laying Down the Ground Rules Music as Currency

8 Comments

  • 1. Pamela Fox  |  December 6, 2008 at 4:20 pm

    These are fantastic articles, may I link to them from the articles section of the documentation?

  • 2. afalldorf  |  April 5, 2009 at 7:50 am

    Hey thanks for the tutorial! It was very helpful.
    Although I was unable to get the PHP part to work, are you using a specific version of PHP?
    I get an error on line 43

  • 3. Free Designs and Templates  |  April 20, 2009 at 4:02 am

    I dont understand what you mean with
    “So you can use this php script from the command line to convert them:” should i just make the php page and run it in a browser ?

  • 4. Drew Massey  |  April 20, 2009 at 7:12 am

    Well, if you have a shell account, you can just write

    # g2z source-directory target-dir

    Otherwise you’ll have to specify those explicitly in the file (where the SERVER args get passed in to the script), and then you can run it from your browser … of course you’ll want to make it non-executable after you are done so that not just anyone can run it.

  • 5. Full Downloads  |  June 7, 2009 at 6:03 am

    Great usefull article, thanks for informing us with this lovely post.

  • 6. son  |  June 16, 2009 at 3:02 pm

    Tank You!

  • 7. John Harrison  |  November 12, 2009 at 11:33 am

    Cheers

    This has to be THE MOST useful article on tiling images onto Google maps. Having spent the last 3 days reading tutorials and the Google docs to my frustration.

    Excellent work. cheers again!

  • 8. arjan  |  June 9, 2010 at 7:21 am

    HI,
    thanks for the article, although i dont seem to get to load the tiles.
    (grey screen, no error)
    tried it locally as on a server.

    swf location: http://www.birthright.net/arjan/googlemaptest2.swf
    tiles location: http://www.birthright.net/arjan/tiles

    fla: http://www.birthright.net/arjan/googlemap.rar

    hope you can help


About

Amusicology is an online forum for musicologists, academic or otherwise. Although Ryan Raul Banagale and Drew Massey are its founders and chief contributors, we welcome guest submissions. Please let us know if you would like to contribute a guest posting. Comments are always welcome and encouraged!

Please bookmark us or add our RSS feed.

Bookmark and Share

Twitter: Amusicology in 140 Characters or Less!

Archives



Follow

Get every new post delivered to your Inbox.

Join 160 other followers

%d bloggers like this: