Custom Maps

Google Maps API Tutorial

Browser Connection Limits

Inspiration

This page was inspired by the fact that Google seem to have imposed timeouts on the tile fetches. That’s fine for Google tiles that are provided by fast servers, but if you have a slow server, it looks like the API doesn’t always wait long enough before giving up and deciding that the fetch has failed.

I noticed that fetching an individual tile from a page that exhibits the problem wasn’t much any longer than fetching an individual Google tile. The significant difference was that the Google map types were fetching more tiles at once, so the total time taken to fetch all the tiles was significantly shorter. Google achieve this effect by using aliases to break the browser connection limits.

What are Browser Connection Limits?

Although browsers are capable of fetching many files simultaneously, only two files will be fetched simultaneously from the same domain. This limit made some sense back in the days when the majority of Internet users had slow dial-up connections, but it makes no sense with today’s high speed connections. For most pages, the continuing existence of these limits doesn’t slow the page loading down to make it worthwhile for the limits to be redesigned, but they do have a significant effect on map tile fetches.

So what can we do?

What Google do is have four different subdomains mt0.google.com, mt1.google.com, mt2.google.com, mt3.google.com, and share the tile fetching between them. The browser doesn’t know that these are all aliases for the same machine, and allows two simultaneous fetches to each subdomain. So eight tiles get fetched at the same time, instead of two.

Here’s an example where I spread the load across four subdomains of econym.org.uk.

The code looks like this

      CustomGetTileUrl=function(a,b){
        var subdomain=(a.x+a.y)%4;
        return "http://sub" +subdomain+ ".econym.org.uk/gmap/tiles/"+a.x+"_"+a.y+"_"+(17-b)+".jpg"
      }

The rest of the code is the same as that used in custommap1.htm.

I created “sub0.econym.org.uk” etc., as subdomanins that have the same destination (or “Document root”) as “econym.org.uk”, so there actually is only one set of tiles on the webserver, but the browser has no way of knowing that.

How much faster is it?

In those examples, you may not notice much speed difference visually, but when the pages are analysed with PageTest, the old one typically loads in 4.5 seconds and the new one in 3.4 seconds.

Even then, that doesn’t seem like a huge improvement, but if you compare the timings from the start of the first tile request to the completion of the last tile request, those times have gone down from 2.9 seconds to 1.4 seconds. If you have a slow server, the differences would be expected to be more significant.

The timings

I don’t know how long PageTest keeps the timing results, but for now you can see one set of results for the custommap1 at pagetest.patrickmeenan.com:8080/result/RC8/1/details/ and for custommap1p atpagetest.patrickmeenan.com:8080/result/RC7/1/details/

Advertisements

Custom Maps

Google Maps API Tutorial

Custom Map Types

To create a custom map, you first need to create a set of 256*256 tiles, or obtain a set for which you have the relevant permissions. Or, alternatively, write your own tileserver code that runs on your server and can create the tile images on the fly.

A Simple Custom Map

To use these tiles as a simple Custom Map Type, you need to do following:

  • Create a GCopyright object
  • Create a GCopyrightCollection
  • Add the GCopyright to the GCopyrightCollection
  • Create a GTileLayer object
  • Create a GMapType object
  • Add the GMapType to the map

These steps are well described in The Mapki so I’ll not repeat that information here.

Here’s an example.

The only significant difference between this example and the Makpki information is that my tiles are stored as images in my web folder, rather than being generated by a tileserver script.

Aligning your map

There’s a very nice facility at open.atlas.free.fr/GMapsTransparenciesImgOver.php which can be used to align a map image in the correct place on top of a Google map.

It specifies the preprocessing (scaling and padding) that should be performed on your image before using something like the Automatic Tile Cutter mapki.com/wiki/Automatic_Tile_Cutter to cut your image into tiles.

Bounds checks

One problem with the previous example is that it causes the API to perform standard error tile handling when the user drags the map out of the custom region. This is a bit ugly and slow.

So what we can do is to add a check in the CustomGetTileUrl() code to see if the tile is in the custom region, and if not return a special “blank.jpg” tile.

Here’s an example.

It would have been nice to have been able to store the information about the custom region tiles in a series of GBounds() objects (one for each supported zoom level) and test to see if the GPoint() representing the tile number is inside the GBounds(), but there is no GBounds.contains(point) method.

Bounds Checks 2

Instead of returning a blank tile for tiles that are outside the custom region, you could return the URL of a tile from G_NORMAL_MAP or G_SATELLITE_MAP.

The problem with this is that you should then display the Google copyright string whenever a Google tile is visible. This turns out to be extremely tricky to get right.

In this example, I display the custom copyright string whenever a custom tile is visible and the Google copyright string whenever no custom tiles are visible.

If you know a better way of handling the copyright, please let me know atlas@econym.demon.co.uk

Common CustomGetTileUrl formats

This code returns URLs in the format created by the Photoshop tile splitter: “http://mydomain.com/tiles/5295_5922_3.jpg”

      CustomGetTileUrl=function(a,b){
          return "http://mydomain.com/tiles/"+a.x+"_"+a.y+"_"+(17-b)+".jpg";
      }

This code returns URLs in the format created by the Paint Shop Pro tile splitter: “http://mydomain.com/tiles/14_5922x5295.jpg”

      CustomGetTileUrl=function(a,b){
          return "http://mydomain.com/tiles/"+b+"_"+a.y+x+a.x+".jpg";
      }

This code returns URLs in the format used by the Google Normal Map tileserver: “http://mydomain.com/tileserver.php?x=5295&y=5922&zoom=3”

      function CustomGetTileUrl(a,b) {
        var z = 17 - b;
        var f = "http://mydomain.com/tileserver.php?x="+a.x+"&y="+a.y+"&zoom="+z;
        return f;
      }

Potential Pitfalls

  1. Some API features, such as polylines and ground overlays, perform their calculations at zoom level 17, rather than at the max zoom level of the map type. These features will fail if the GProjection() of the map type ahs less than 18 zoom levels.

More advanced stuff

Google Maps API Tutorial

Toned map – New method

You can now change the colour tone of a map by overlaying partially opaque GPolygons over the map.

Things go slightly askew if you try to use a single polygon for the whole 360 degrees of longitude. Four polygons that span 90 degrees each works.

Things can also go wrong when a polygon crosses the International Date Line, but you can have one polygon that ends at 180 degrees and the next polygon starts at 180.000001.

Here’s an example

Restriction

Polygons don’t wrap round the Earth. If you zoom out so that more than one copy of the Earth is visible, then only one copy of the Earth will be toned.

Draggable Markers and GTileLayerOverlays

Draggable markers

We added draggable markers as a hidden feature in revision 2.46, but today they are making their official debut as part of the Maps API. To make a marker draggable, set the marker option draggable to true when you declare it: var marker = new GMarker(center, {draggable: true});.

When you drag the marker, a little X will appear to mark the spot where the marker will fall. After you let go of the marker, it bounces into place (to let you know how much fun it’s having). If you prefer non-bouncy markers, set the marker option bouncy to false.

Try dragging this marker:

GTileLayerOverlays

The Maps API has GTileLayers (which you can use to build GMapTypes) and GOverlays (which you can show on top of a Google Map). Today we’re introducing GTileLayerOverlays, which lets you add tile layers without needing to introduce new map types. You can also add & remove them on the fly, unlike map types.

For example, to create a desaturated map, you can overlay it with a white tile overlay at 50% opacity:

 var tilelayer = new GTileLayer(new GCopyrightCollection(), 0, 17); tilelayer.getTileUrl = function(tile, zoom) { // A more interesting tile server would do something with the numbers // tile.x, tile.y and zoom. return "http://kml.lover.googlepages.com/white_map_tile.gif"; }; tilelayer.getOpacity = function() {return 0.5;} map.addOverlay(new GTileLayerOverlay(tilelayer)); 

If you’d like to start testing these new features right away, don’t forget to add the v=2.x parameter to your<script> src, so you get the latest revision instead of the default v2.60.

API v1 Current: 1.31
API v1 Default: 1.31
API v2 Current: 2.61
API v2 Default: 2.60

The Basics

Google Maps API Tutorial

Using different languages

Normally, the text used by the API will be in US English.

The API will look through the preferred languages in your browser options and use the first language that Google supports.

If you wish to specify a particular language, then you can add a “hl” parameter to the line that loads the API code, e.g.
src=”http://maps.google.com/maps?file=api&amp;v=2&amp;hl=de&amp;key=abcdefg” 
The official list of supported languages is kept here: code.google.com/support/bin/answer.py?answer=60737&topic=12267

A slightly different, but equally official, list is available on this spreadsheet, in the “localized” column.gmaps-samples.googlecode.com/svn/trunk/mapcoverage_filtered.html

Directions details

When you use GDirections, by default, the route description text will be in the same language as that used in the API as described above.

If you want to use a different one of the supported languages, then you can add the locale option to your .load() or .loadFromWaypoints() call, e.g. gdir.load(“from: Detroit to: Dayton”, {locale:”fr”});.

Other languages

If you want to use a language that’s not yet supported by Google then you can do it like this example. All I’ve done there is replace the Google text with the same text in upper case. To use a real language, you’d need to translate all that text into your chosen language.

The way it works is that the API loader uses GAddMessages() to pass the language specific text strings to the main API code. We can overwrite those text strings with our own GAddMessages() call.

However, the GMapTypes are created before the loader returns control to our code. We can performGAddMessages{10050: ‘SATELLITE’} in our own code, but it’s too late to affect the map type. What we can do, however, is create our own map types which are clones of the Google map types except that they use different texts in the “name” parameter and in the “shortName”, “errorMessage” and “alt” options.

Copyright texts associated with a map type are generated in a server, so they’re not accessible by that method. What we can do is write our own custommap.getCopyrights() method which reads through the prefixes and replaces any occurrences of “Map Data” and “Imagery” with the equivalent in the desired language.

There’s no reasonable way to produce GDirections details in unsupported languages, because that’s performed in the direction server.

Google Maps API Tutorial

Google Maps API Tutorial

This tutorial is intended to help you create your own interactive maps using the Google API.

Do take a look at the Google documentation.

There are two ways to use this tutorial:

  1. Read it and try to understand the principles involved.
  2. Use the example files as templates. Paste the code into your own web page and change the API key and data. Read the “potential pitfalls” sections, and try to avoid them.

Using the Google Map API is not easy if you don’t have much Javascript experience.
If you find the Google documentation too difficult to understand, it’s not because it’s badly written it’s just that the subject is not easy.