Hack 66. Add Your Own Custom Map
This time, it's personal.
Well, as everyone else has written in this book, those Google Maps sure are pretty. Then again, there is always room for improvement right? And sometimes Google's maps just don't highlight the right information. To really spice things up, you may want to add your own map…a map that looks the way you want it to look. This off-API hack shows you how to add your own custom map. In "Serve Custom Map Imagery" [Hack #67], you'll get a script to serve custom map tiles, and finally in "Automatically Cut and Name Custom Map Tiles" [Hack #68], there is a script to quickly make the thousands of little images you will need to display your map.
There are plenty of cool reasons to add your own map images. In creating the NYC Subway Google Map hack (http://www.onnyturf.com/subwaymap.php), I felt that Google's polylines were not elegant enough, and they were hard to see on top of Google's orange/green default map. To make the subway lines easier to see against the streetscape and to make the lines look nicer, I decided to add a custom map type that I illustrated, as you can see from Figure 7-14.
Another great use of adding your own map is using it as a semi-transparent overlay on the other map images. Figure 7-15 shows the street map layered on top of the satellite map, with a semi-transparent setting allowing you to see the relationship between the two. You can do this sort of thing with your own custom map too.
Creating this transparency effect is outside the scope of this tutorial. You can learn how to add transparency by looking at the source of the example above, which can be found at http://www.kokogiak.com/gmaps-transparencies.html. You will need to know these basics on adding a custom map in order to add transparency in that way.
Figure 7-14. Custom map for NYC subway map hack
7.6.1. Four Steps to Add a Custom Map
There are four simple things you will need to do to add your own map.
- Create a new map type.
- Tell the map where it can find the images for your new type.
- Customize your map's type button.
- Add your new map control to Google Maps' list of map types.
7.6.2. Create a New Map Type
The Google Map comes with three default maps, which you are probably already familiar with, namely, map, satellite, and hybrid. These are known in Google Maps as map types, and they are accessed from an array called mapTypes, which is a property of our GMap object. To add your own map, we need to create a new map type and then add it to this array.
Figure 7-15. Transparent road map overlaying the satellite map
Each map type Google provides has many properties. We need to make our custom map type just like these. But we really don't want to have to build a whole map type from scratch, setting all the properties anew. We can save a lot of time by duplicating an existing map type and switching just a few of the values to suit our needs.
For the NYC Subway Google Map hack, I made my map type match Google's default map type. This default map is the first map stored in the mapTypes array. So we are just going to copy that first map type and store it in a variable temporarily for editing (here it is named yourMapType, but you can name this variable what ever you like). There is one special thing we need to be aware of here; since JavaScript assigns object values by reference, we can't just dupe the map type object like this:
yourMapType = map.mapTypes[0];
We need to make sure we copy all the properties of the map type object, so we have a special little function we are going to include and call to copy all the properties of the default map type:
function copy_obj(o) { var c = new Object(); for (var e in o) c[e] = o[e]; return c; }
Using our copy_obj function, we can now duplicate the default map type:
yourMapType = copy_obj(map.mapTypes[0]);
Now we change a few of the properties to customize our map type.
7.6.3. Set the Path to Your Map Images
Each Google map type is made up of thousands of image tiles. When you see a Google map in a window, you are really seeing about 12 tiles at a time, depending on your screen size, as suggested by Figure 7-16.
As you drag the map around in the window, your browser downloads the tiles it needs in order to show more of the map. This happens in the background and is one of the more innovative features of Google Maps. Each map type has a path to its associated image tiles. This property is called baseURL. The default maps point to Google's server. To load our own image tiles, we need this path to point at our own server. We actually don't point right at a directory of images. The map sends values to the server and asks for an image in return. So we use a PHP script to serve up the tiles based on the values the map sends (this image serving script is discussed in more detail later in "Serve Custom Map Imagery" [Hack #67]). We set the baseURL to point at this script.
yourMapType.baseUrl = "http://www.yoursite.com/googlemap/images/index.php?";
You'll notice we include a ? at the end of our path. The Google Maps application adds CGI parameters at the end of the path when requesting images, so the ? is necessary for posting those values. With that path configured, our images will load when our custom map type is selected.
7.6.4. Customize Your Map's Button Name
Although the Google Map API does not automatically add the map types buttons that appear in the upper-right corner of their map, most people add them using the API addControl method. If you call this method in your map, a button will automatically be generated for your map type too, as you can see on the Subway map shown in Figure 7-17.
Figure 7-16. Google Maps tile grid
However, that button did not just magically get the name "Subway." We set the name of our map type's button by setting the getLinkText property. The Google Map application calls it as a function, so we want to return the name we want to give it, like so:
yourMapType.getLinkText = function() { return 'SUBWAY'; }
You'll note that getLinkText is set to a function. This means you can have that function return different values depending on external conditions.
Nice and simple eh? So that's all we have to do to make a custom map type. Now we add it to the array mapTypes.
7.6.5. Add Your Map to the List of Map Types
We will add our map to the end of the mapTypes array, and then, because we love our map more than any other map in the world, we set it to be the default map when our map page first loads. To add our custom map to the list, we just add the map type object that we have been working on to the end of the array. We use the API's setMapType( ) method to make our custom map type load first.
Figure 7-17. Subway map type button
map.mapTypes[map.mapTypes.length] = yourMapType; map.setMapType(map.mapTypes[map.mapTypes.length-1]);
Finally let's put it all in the context of the rest of our typical map initializing function. This function is called from onLoad attribute of the body element in our HTML:
function onLoad() { //Create a new map and load it to the map at the html object map = new GMap(document.getElementById('map')); // Copy Object Function function copy_obj(o) {var c = new Object(); for (var e in o) { c[e] = o[e]; } return c;} //Copy mapType yourMapType = copy_obj(map.mapTypes[0]); // Set Path to Our Custom Map Image Tiles yourMapType.baseUrl = "http://www.yoursite.com/googlemap/images/index. php?"; // Map Display name in the auto-generated maplink in the top right corner. yourMapType.getLinkText = function() { return 'SUBWAY'; } // Register the new mapType with the running google map. map.mapTypes[map.mapTypes.length] = yourMapType; //Set the onload view to our new map map.setMapType(map.mapTypes[map.mapTypes.length-1]); //Add Map Type buttons in the upper right corner map.addControl(new GMapTypeControl()); //Add Small zoom controls map.addControl(new GSmallZoomControl()); }
Even though we added our map to the list of map types, we still need to serve up the images when requested [Hack #67].
7.6.6. See Also
- "Add More Imagery with a WMS Interface" [Hack #65]
- "Serve Custom Map Imagery" [Hack #67]
- "Automatically Cut and Name Custom Map Tiles" [Hack #68]
Will James