Topographic Images on a Google Map

This post assumes intermediate understanding of the Google Maps API.

While I was working on a personal project I bumped into the need to create a Google Map that included locations and driving directions of the different Keweenaw waterfalls. This gave me the opportunity to learn about the Google Maps API, including displaying driving routes, arrays of points, and custom markers/descriptions. After working with Google Maps for awhile, I decided to take my website's map to the next level and add USGS topographic maps to the features.

Google Maps already offers several premade maps automatically with neat features, like Satellite, Terrain, and Map view that can work with street routes, but I needed to go a step further for a good topographic view. The maps work by displaying different 'tiles', or images, based on your zoom level and position. While the premade maps do all of this behind the scenes, to add custom maps (either self-made or supplied by another web service), I needed to sort out what tiles were needed and where to display them so all the latitude/longitude information could display properly.

The first step was finding a good topographic map service that had their own API that I could request tiles from. This wasn't hard - Terraserver, a service through Microsoft, has an API to show USGS topographic maps. In my Google Maps load() function, I added this map the same way I added other maps (Satellite, Terrain).

  1. map.addMapType(WMS_TOPO_MAP);

Build the WMS_TOPO_MAP function first with the applicable information.

  1. var WMS_TOPO_MAP = WMSCreateMap('Topo','Imagery by USGS / Web Service by TerraServer','','DRG',4,17,'t');

  2. function WMSCreateMap(name,copyright,baseUrl,layer,minResolution,maxResolution,urlArg) {

  3. var cr = new GCopyright(1,new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90,180)),0,copyright);

  4. var crc = new GCopyrightCollection();

  5. crc.addCopyright(cr);

  6. var tileLayer = new GTileLayer(crc,minResolution,maxResolution);

  7. tileLayer.baseUrl = baseUrl;

  8. tileLayer.layer = layer;

  9. tileLayer.getTileUrl = WMSGetTileUrl;

  10. var tileLayers = [tileLayer];

  11. return new GMapType(tileLayers,G_SATELLITE_MAP.getProjection(),name,{errorMessage:'',urlArg:'o'});

  12. }

Most of this is fairly straightforward if you read it one line at a time. The name is what displays on the top right corner of the finished Google Maps and copyright displays on the bottom right. The baseUrl is used to request the different tiles, and min and maxResolution is based on the available layers from TerraServer. The copyright information is carried through and the url request information as well as the min and maxResolution is used to request tiles and implement using the same 'format' as Google's Satellite tiles.

This function is used for the requests to get tiles.

  1. function WMSGetTileUrl(tile,zoom) {

  2. var southWestPixel = new GPoint(tile.x*256,(tile.y+1)*256);

  3. var northEastPixel = new GPoint((tile.x+1)*256,tile.y*256);

  4. var southWestCoords = G_NORMAL_MAP.getProjection().fromPixelToLatLng(southWestPixel,zoom);

  5. var northEastCoords = G_NORMAL_MAP.getProjection().fromPixelToLatLng(northEastPixel,zoom);

  6. var bbox = southWestCoords.lng()+','','+northEastCoords.lng()+',';

  7. return this.baseUrl+'?VERSION=1.1.1&REQUEST=GetMap&LAYERS='+this.layer+'&STYLES=&SRS=EPSG:4326&BBOX='+bbox+'&WIDTH=256&HEIGHT=256&FORMAT=image/jpeg&BGCOLOR=0xCCCCCC&EXCEPTIONS=INIMAGE';

  8. }

Based on the tile requested from the map and using Google's Satellite tile information, this function pulls images from Terraserver and plants them onto the map.

That's all that is really needed. This code was introduced from an excellent online service,, and re-implemented on my waterfalls site. It also provides a great introduction on how to create your own Google Maps tiles, something I hope to play with in the near future.