Custom Google Map Tiles part 2/2: Slicing the tiles and creating the HTML
Posted on 2008-05-01 14:38:46


Time to create a Custom Tiled Google Map from out previous created World of Warcraft map. We'll do 3 maps in this tutorial. Starting with an easy of GTASA (Grand Theft Auto Sanandreas), then we'll make it a bit harder and make a Guild Wars map. After that we'll make a World of Warcraft map out of 4 parts. Below are the images needed for each map. With the GTASA I'll take you by hand over each step so you can get familier with the steps and give a short explanation of what each option/handling does. With the Guild Wars map we'll make a bigger map and with the World of Warcraft map we make a map out of 4 images and use some extra techniques to speed things up.

For this we need the following things:

  • A decent amount of RAM (atleast 2GB should do the trick)
  • Photoshop (One with JavaScript support)
  • A Google Maps API key
  • An HTML editor (one wich you can edit the source with) and maybe a JS editor if your HTML editor can't handle it.
  • The tile cutter script from mapki.com
  • Beer (No download available working on that sorry.)
  • Popcorn or something else to eat

And you'll need the following images:

Grand Theft Auto: San Andreas

Guild Wars

World of Warcraft

Before we start take a few things in mind. This tutorial was written on a Quad Core (Q6600) Intel Proc, 2GB RAM, Striped 7500rpm SATA HDD running Vista Home Premium. Performance can be different for you depending on the box your using. So if I say a few minutes on my box it can very well but a few days, weeks heck maybe even months on your x486 ;). Also path used are my own. Make sure to keep an eye on that the ones you use are correct and make sure not to mix up :). The file paths used

GTA Sanandreas

As said we'll start easy, just follow my instructions and get used to the steps.

Configurating the script

We'll start with downloading the map image. And open the .js file. In the .js file look for this line.

var FolderPath = "C:/Users/test/"; //<-- path to where we will save our tiles

Change it to the location where you want the tile slices to end up. In my case I aimed it at my localwebserver's wwwroot directory, and to a specific folder for the GTA Sanandreas slices.

var FolderPath = "C:/htdocs/gtasa/"; //<-- path to where we will save our tiles

Now find this lines. These lines controll the number of zoom level sliced.

var HighestZoomLevel = 17; // Enter the highest zoom level we are creating tiles for (should be less than OrgZoom; technically the script should be able to handle values larger as well, but your image quality will suffer)
var LowestZoomLevel = 12; // Enter the last zoom level we want to create tiles for (must be <= HighestZoomLevel for the script to do anything)

And change it into.

var HighestZoomLevel = 6; // Enter the highest zoom level we are creating tiles for (should be less than OrgZoom; technically the script should be able to handle values larger as well, but your image quality will suffer)
var LowestZoomLevel = 1; // Enter the last zoom level we want to create tiles for (must be <= HighestZoomLevel for the script to do anything)

For GTASA We'll use fixed values to keep it easy. Later on I'll explain it in more detail and with the last one I'll give hints so you can figure it out ;).

Next up are the lines that controll the file naming indirectly.

var OrgX = 31551; // the Google Maps X value of the tile at the top left corner of your Photoshop document
var OrgY = 50899; // the Google Maps Y value of the tile at the top left corner of your Photoshop document
var OrgZoomLevel = 17; // the Google Maps zoom level of your Photoshop document (for best results, you will need to resize your Photoshop document to match a zoom level as closely as possible before running this script)

Change it into.

var OrgX = 1; // the Google Maps X value of the tile at the top left corner of your Photoshop document
var OrgY = 1; // the Google Maps Y value of the tile at the top left corner of your Photoshop document
var OrgZoomLevel = 6; // the Google Maps zoom level of your Photoshop document (for best results, you will need to resize your Photoshop document to match a zoom level as closely as possible before running this script)

The reason why both OrgX and OrgY are 1 is to keep it simple. The OrgZoomLevel is the same as HighestZoomLevel since it's causing very tiny results on low zoom levels and end up with an ugly effect.

Following are the lines that controll what image type to output.

var saveJPEG = true;
var savePNG = false;
var saveGIF = false;

Into.

var saveJPEG = false;
var savePNG = true;
var saveGIF = false;

Slicing the tiles

This is the easiest step of all since you just sit and wait. Fire up Photoshop, and open the GTASA map image. Set foreground and background color to black (or white, or yellow if you like but I found black the best suiteble color for this). Now go to File -> Scripts -> Browse. Go to where ever you saved the tile cutter script and open it. No open up yer first beer and grab a bite. This will take a few minutes. You should see alot of screenings opening, resizing and closing and doing it all over again. Once the script is finished you'll see the full map image again. And if you check in C:/htdocs/gtasa/, there should be a shit load of 256x256 images in there.

Putting together the HTML

We'll start with including the Google Maps API. (Make sure you replace [KEY] with your Google Maps API key.)

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[KEY]" type="text/javascript"></script>

Next we'll create the div that will contain the map widget. We'll name it gtasa_map and size is 450 by 300.

<div id="gtasa_map" style="width: 450px; height: 300px"></div>

We'll create a function that will be called when the loading of the page is finished. Within that function is a check if the used browser can run Google Maps. And after the function with hook it up to the onload event.

<script type="text/javascript">

function on_load_maps()
{
   if (GBrowserIsCompatible())
   {
   }
}

window.onload = on_load_maps;

</script>

All of the following code lines should be place within the if that checks the browsers compatibility. First we create a new GMap2 object hooked to the early created div.

      var gtasa_map = new GMap2(document.getElementById("gtasa_map"));

This adds the zoom and panning control.

      gtasa_map.addControl(new GLargeMapControl());

Prepare the copyright info.

      var gtasa_copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)), 1, "(c) 2008 WyriHaximus.net");
      var gtasa_copyrightCollection = new GCopyrightCollection('Map Data:');
      gtasa_copyrightCollection.addCopyright(gtasa_copyright);

This is the most importend bit. This will tell Google Maps what the URL of the tiles is.

      gtasa_CustomGetTileUrl=function(a,b){
         var f = "http://mt1.servcontent.wyrihaximus.net/gtasa/"+b+"_"+a.x+"_"+a.y+".png";
         return f;
      }

Combine the copyright info and the custom tile code.

      var gtasa_tilelayers = [new GTileLayer(gtasa_copyrightCollection,1,6)];
      gtasa_tilelayers[0].getTileUrl = gtasa_CustomGetTileUrl;
      var gtasa_custommap = new GMapType(gtasa_tilelayers, new GMercatorProjection(7), "Old OS");

Set the center of the map so we have the map nice in the middle of our widget.

      gtasa_map.setCenter(new GLatLng(73.92246884621463,-105.8203125, true), 1, gtasa_custommap);

This applies the custom map to the widget.

      gtasa_map.addMapType(gtasa_custommap);

You should end up with this big of code:

<div id="gtasa_map" style="width: 450px; height: 300px"></div>

<script
src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[KEY]" type="text/javascript"></script> <script type="text/javascript">

function on_load_maps()
{
   if (GBrowserIsCompatible())
   {
      var gtasa_map = new GMap2(document.getElementById("gtasa_map"));
      gtasa_map.addControl(new GLargeMapControl());
      var gtasa_copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)), 1, "(c) 2008 WyriHaximus.net");
      var gtasa_copyrightCollection = new GCopyrightCollection('Map Data:');
      gtasa_copyrightCollection.addCopyright(gtasa_copyright);
      gtasa_CustomGetTileUrl=function(a,b){
         var f = "http://mt1.servcontent.wyrihaximus.net/gtasa/"+b+"_"+a.x+"_"+a.y+".png";
         return f;
      }
      var gtasa_tilelayers = [new GTileLayer(gtasa_copyrightCollection,1,6)];
      gtasa_tilelayers[0].getTileUrl = gtasa_CustomGetTileUrl;
      var gtasa_custommap = new GMapType(gtasa_tilelayers, new GMercatorProjection(7), "Old OS");
      gtasa_map.setCenter(new GLatLng(73.92246884621463,-105.8203125, true), 1, gtasa_custommap);
      gtasa_map.addMapType(gtasa_custommap);
   }
}

window.onload = on_load_maps;

</script>

The Result

Now we've got something cool, a fully working Google Map Mashup of the GTASA map. From here we can put markers on places, create permalinks to special places and more. But I'll cover that in another tutorial.

Guild Wars

Lets step it up a bit, the following instructions are in essention the same but with a Guild Wars twist.

Configurating the script

Open the .js file we used last time. We are going to change a few things to prepare it for to Guild Wars map.

var FolderPath = "C:/htdocs/gtasa/"; //<-- path to where we will save our tiles

Change it to a map for the Guild Wars tiles, preferable like we did last time to keep everythings together.

var FolderPath = "C:/htdocs/gw/"; //<-- path to where we will save our tiles

Now find this lines. These lines controll the number of zoom level sliced.

var HighestZoomLevel = 6; // Enter the highest zoom level we are creating tiles for (should be less than OrgZoom; technically the script should be able to handle values larger as well, but your image quality will suffer)

And change it into the below. This changes the HighestZoomLevel to something higher since this image is something over twice as big. To keep is simple we add 2 to the value in the GTASA example.

var HighestZoomLevel = 8; // Enter the highest zoom level we are creating tiles for (should be less than OrgZoom; technically the script should be able to handle values larger as well, but your image quality will suffer)

Next up are the lines that controll the file naming indirectly. They add numbers to the tile name representing the X and Y values for each zoom level based on what you give here.

var OrgZoomLevel = 6; // the Google Maps zoom level of your Photoshop document (for best results, you will need to resize your Photoshop document to match a zoom level as closely as possible before running this script)

Change it into. Once again we set OrgZoomLevel to HighestZoomLevel to avoid funny effects.

var OrgZoomLevel = 8; // the Google Maps zoom level of your Photoshop document (for best results, you will need to resize your Photoshop document to match a zoom level as closely as possible before running this script)

Slicing the tiles

This is the easiest step of all since you just sit and wait. Now open up yer seccond and third beer since this will take a while or go take a shower. When this is done you'll see alot of images in C:/htdocs/gw/.

Putting together the HTML

Since we allready build this piece of code I'll describe what each changed does (beside the nameing ofcourse).

We'll start with the changed code:

<div id="gw_map" style="width: 450px; height: 300px"></div>

<script
src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[KEY]" type="text/javascript"></script> <script type="text/javascript">

function on_load_maps()
{
   if (GBrowserIsCompatible())
   {
      var gw_map = new GMap2(document.getElementById("gw_map"));
      gw_map.addControl(new GLargeMapControl());
      var gw_copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)), 1, "(c) 2008 WyriHaximus.net");
      var gw_copyrightCollection = new GCopyrightCollection('Map Data:');
      gw_copyrightCollection.addCopyright(gw_copyright);
      gw_CustomGetTileUrl=function(a,b){
         var f = "http://mt1.servcontent.wyrihaximus.net/gw/"+b+"_"+a.x+"_"+a.y+".png";
         return f;
      }
      var gw_tilelayers = [new GTileLayer(gw_copyrightCollection,1,8)];
      gw_tilelayers[0].getTileUrl = gw_CustomGetTileUrl;
      var gw_custommap = new GMapType(gw_tilelayers, new GMercatorProjection(9), "Old OS");
      gw_map.setCenter(new GLatLng(68.78414378041504,-99.140625, true), 1, gw_custommap);
      gw_map.addMapType(gw_custommap);
   }
}

window.onload = on_load_maps;

</script>

Since the number of zoom levels we only have to change 2 lines. We'll start with telling the Google Maps API that the zoom levels will range from 1 to 8 instead of fom 1 till 6.

      var gw_tilelayers = [new GTileLayer(gw_copyrightCollection,1,6)];

Into:

      var gw_tilelayers = [new GTileLayer(gw_copyrightCollection,1,8)];

And since the number of zoom levels (form 0 till the max you entered before, and in our case 8) to be exspected. Change it form 7 to 9 to match the Guild Wars map.

      var gw_custommap = new GMapType(gw_tilelayers, new GMercatorProjection(7), "Old OS");

Into:

      var gw_custommap = new GMapType(gw_tilelayers, new GMercatorProjection(9), "Old OS");

And last but most importend, the new image slices location:

         var f = "http://mt1.servcontent.wyrihaximus.net/gtasa/"+b+"_"+a.x+"_"+a.y+".png";

Into:

         var f = "http://mt1.servcontent.wyrihaximus.net/gw/"+b+"_"+a.x+"_"+a.y+".png";

The Result

Congratulations you've (with minor alterations) created a Google Maps Mashup Guild Wars Map. As you can see once you got the hang of it, it's simple :).

World of Warcraft

Ok this is going to be fun, instead of 1 image we got 4 this time. And we'll also get a more improved tile script to speed things up. We'll start with setting up the script for the first image.

Change:

var FolderPath = "C:/htdocs/gw/"; //<-- path to where we will save our tiles

Into:

var FolderPath = "C:/htdocs/wow/"; //<-- path to where we will save our tiles

Start Photoshop, open Full_Map_1x0_16384x16384.jpg and fire up the script. Go do something untill it's done. When it's done close the current document (don't save) and open Full_Map_1x0_16384x16384.jpg. Now we are going to change 1 setting of the script so we don't overwrite the tiles just created.

Change:

var OrgX = 1; // the Google Maps X value of the tile at the top left corner of your Photoshop document

Into:

var OrgX = 65; // the Google Maps X value of the tile at the top left corner of your Photoshop document

Now we are going to add the next 2 images below the previous 2. Change the folowing things in the script.

Change:

var OrgX = 65; // the Google Maps X value of the tile at the top left corner of your Photoshop document
var OrgY = 1; // the Google Maps Y value of the tile at the top left corner of your Photoshop document

Into:

var OrgX = 1; // the Google Maps X value of the tile at the top left corner of your Photoshop document
var OrgY = 65; // the Google Maps Y value of the tile at the top left corner of your Photoshop document

Close the current image and open Full_Map_3x0_16384x16384.jpg, start the script and wait till it's done. After that change the script again:

var OrgX = 1; // the Google Maps X value of the tile at the top left corner of your Photoshop document

Into:

var OrgX = 65; // the Google Maps X value of the tile at the top left corner of your Photoshop document var OrgX = 1; // the Google Maps X value of the tile at the top left corner of your Photoshop document
var OrgY = 1; // the Google Maps Y value of the tile at the top left corner of your Photoshop document

Now close the current image and open Full_Map_3x1_16384x16384.jpg, start the script and wait till it's done. When it's done you created all the tiles needed. To be honest this isn't the best method but on machines with low memory (2GB) it's the best and most simple way. The best way would be just 1 big image but that is out of reach in this cause, those images take up 6GB of RAM ;). Anyway lets move on to the next step and create the JavaScript.

Putting together the HTML

We'll start with the same scripts as the others (except the naming prefix).

<div id="wow_map" style="width: 450px; height: 300px"></div>

<script
src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[KEY]" type="text/javascript"></script> <script type="text/javascript">

function on_load_maps()
{
   if (GBrowserIsCompatible())
   {
      var wow_map = new GMap2(document.getElementById("wow_map"));
      wow_map.addControl(new GLargeMapControl());
      var wow_copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)), 1, "(c) 2008 WyriHaximus.net");
      var wow_copyrightCollection = new GCopyrightCollection('Map Data:');
      wow_copyrightCollection.addCopyright(wow_copyright);
      wow_CustomGetTileUrl=function(a,b){
         var f = "http://mt1.servcontent.wyrihaximus.net/wow/"+b+"_"+a.x+"_"+a.y+".png";
         return f;
      }
      var wow_tilelayers = [new GTileLayer(wow_copyrightCollection,1,8)];
      wow_tilelayers[0].getTileUrl = wow_CustomGetTileUrl;
      var wow_custommap = new GMapType(wow_tilelayers, new GMercatorProjection(9), "Old OS");
      wow_map.setCenter(new GLatLng(63.860035895395306,-80.15625, true), 1, wow_custommap);
      wow_map.addMapType(wow_custommap);
   }
}

window.onload = on_load_maps;

</script>

Now we are going to add a bit of code that spreads the image requests over multiple servers. This makes the map loading alot faster when it loads for the first time or your moving around. Most browsers have a limit of simultanious downloaded files (images/css/html etc etc) we'll by pass that by using multiple servers. First find the following 2 lines:

   if (GBrowserIsCompatible())
   {

After that add this code (note that these are my servers you should replace them with your own!):

      var current_server = 0;
      var number_of_servers = 0;
      var myservers=new Array();
      myservers[number_of_servers++]="mt1.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt2.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt3.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt4.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt5.servcontent.wyrihaximus.net";

Now we are going to alter the line that gives the Google Maps API the tile URL. The change will pick the next server in row every time the function is called. This will spread out the connections over different servers and speed up the loading of the map.

Change:

         var f = "http://mt1.servcontent.wyrihaximus.net/wow/"+b+"_"+a.x+"_"+a.y+".png";

Into:

         current_server = (current_server+1) % number_of_servers;
         var f = "http://" + myservers[current_server] + "/wow/"+b+"_"+a.x+"_"+a.y+".png";

You should have this code now

<div id="wow_map" style="width: 450px; height: 300px"></div>

<script
src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[KEY]" type="text/javascript"></script> <script type="text/javascript">

function on_load_maps()
{
   if (GBrowserIsCompatible())
   {
      var current_server = 0;
      var number_of_servers = 0;
      var myservers=new Array();
      myservers[number_of_servers++]="mt1.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt2.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt3.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt4.servcontent.wyrihaximus.net";
      myservers[number_of_servers++]="mt5.servcontent.wyrihaximus.net";
      var wow_map = new GMap2(document.getElementById("wow_map"));
      wow_map.addControl(new GLargeMapControl());
      var wow_copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)), 1, "(c) 2008 WyriHaximus.net");
      var wow_copyrightCollection = new GCopyrightCollection('Map Data:');
      wow_copyrightCollection.addCopyright(wow_copyright);
      wow_CustomGetTileUrl=function(a,b){
         current_server = (current_server+1) % number_of_servers;
         var f = "http://" + myservers[current_server] + "/wow/"+b+"_"+a.x+"_"+a.y+".png";
         return f;
      }
      var wow_tilelayers = [new GTileLayer(wow_copyrightCollection,1,8)];
      wow_tilelayers[0].getTileUrl = wow_CustomGetTileUrl;
      var wow_custommap = new GMapType(wow_tilelayers, new GMercatorProjection(9), "Old OS");
      wow_map.setCenter(new GLatLng(63.860035895395306,-80.15625, true), 1, wow_custommap);
      wow_map.addMapType(wow_custommap);
   }
}

window.onload = on_load_maps;

</script>

The Result

Resources

All the images, tiles and html for this tutorial are available with this torrent. (It's 580MB so I'm not going to put that up for download on my site ;).)

Information Sources

I couldn't have wrote this tutorial without some sites, persons and the combination of them.

WyriHaximus