dira ⋅ geek ⋅ girl

GMap_to_static: one-click static maps creation

dira

GMap_to_static is a bookmarklet for creating a static map that looks just like a given dynamic Google Map. It is useful when you want to embed a Google Map as a ligthweight image, not as a full frame.

Note: In early 2011 this tool stopped working, as more aggressive minification of the map information hid the essential properties used by the algorithm.

Go to dira.ro/code/GMap-to-static to install it and github to watch the project.

Here’s how it works:

Why I wanted it

In order to create a Static Map image, you need the coordinates of all your markers and paths.

I already had a map with a lot of nice colorful markers spread across South America. But there is no tool to export it as a static map, so I was left with manually getting the coordinates of each marker… or writing a tool to get them.

I boldly chose the “write a tool” option.

But it’s not a piece of cake

The good news is that calling window.gApplication.getMap() in a Google Maps page will return the current map.

The bad news is that most of its properties and functions have been minified to cruel one or two-letter identifiers. So, except getBounds, getCenter and some conversion functions, there are no recognizable names in sight.

Enthusiastically digging through the tree of minified JS properties, I found out that the markers are minified too, but only partially. They still have some typical functions, like infoWindow and latlng, exposed fullname.

Quite a handy discovery, but relying on a path like map.Kd.St[0] is not a long-term solution. The path will probably change each time Google Maps is deployed.

Luckily, backtracking was invented for this kind of tasks. So, I’m searching the entire map object tree, looking for properties that “quack” like a marker. Finders, keepers!

Once the secret of markers is exposed, a similar strategy can be applied to paths and shapes. They too quack in a specific way, as they are the only ones having the function getVertex. The difference is that paths have the property name, while shapes don’t. However, shapes are not yet supported by the Static Maps API, so only their contour is rendered in the static image.

Guessing the zoom level

Another property that is minified is the zoom level. Unfortunately, it is just a number, so the quack-based detection does not really work to find it.

I observed that the map’s longitude span (in degrees) and its width (in pixels) are proportional within the same zoom level (thank you rectangular projection!).

When zoom = 3, for example, longitude_span.map_width/ ~= 0.175 for any Google Map.

Even more, for each increment in the zoom level, the longitude span is multiplied by 2.

Therefore, an easy formula can be created to compute the zoom for a map:

zoom = 3 + log2(0.175 * map_width / longitude_span)

Viewport optimization

The size of the static map’s URL is limited to 2048 characters. This means that we should strive not to put unused information in it. :)

This is why I optimized the URL generation by including only the markers and the path segments that are actually visible in the current viewport and left out the others.

Also, the algorithm starts by trying to include as much precision in the coordinates as appropriate for the zoom level, and decreases the precision if the resulting URL is too long.

Limitations

  • the map width and height are limited by the Static Maps API to 640
  • the URL size is limited to 2048 characters. This basically means that maps with complicated paths (such as those of Directions for long distances) cannot be made static as the URL would be too big.
  • the map type for the static map is the default one: roadmap. If you want a different kind of map, you can change the maptype parameter from roadmap to satellite, terrain or hybrid.

Conclusion

GMap_to_static is one of the most challenging and rewarding pet projects I created. Using nice algorithms and playing with logarithms reminds me of the high-school days. And being able to easily generate static maps is wonderful (and addictive, beware!).