Information and advice for healthcare consumers.

Web/Tech Mobile, social & web news for clinics

How to make Google static maps interactive

Today I’m happy to bring you part one of a post by Tim, one of our researchers. In it he discusses a smart way to add some interactivity to a static Google map. In the second part coming next week he is going to post some code you can use to see his idea in action.

Adding marker divs to your static maps

The Google Maps API is great, but for some things it’s overkill. Enter Google’s static maps, which are also great, but for some applications they might not be enough.

One solution is to use the static maps and then add a bit of panache. Let’s take a typical example where we take a location and in our data find 10 places close to that location. Using static maps we create an URL that has markers for our points and we might set the zoom level using the handy Span attribute.

Unfortunately we cannot interact with the map: if markers overlay each other we cannot tell which is where, we need to provide a key for the markers as they have no tool-tips or events.

By placing divs at the points our markers are displayed we can recover a good deal of our lost ground without needing to use a full map with all its associated overheads, load times and initialization especially. However, to do this we need to know a bit about map projections and a bit about the way Google makes its static maps.

The static maps use a Mercator projection, you can read about the maths here which is probably more than most people want to know. Lets look at the useful bits for us:

Getting the x-position

Longitude has a nice simple equation

x = y – yo

What does this mean for us? Well if we have a map 200 pixels wide and we know the map’s centre point and the length in pixels of a degree is 2.84 pixels then –  say a point 3o to the west (left) is 8.533 pixels left of our centre.

How do we know the width of a degree? Well, the map we have is a small window onto a projection of the whole world. At a Google zoom level of 0 we can see the whole world (or a little more depending on the width of our map, at a width of 256 pixels it fits the world exactly). As we zoom in our window shows us a smaller and smaller part of the whole world, 2zoom to be exact. The pixel width of our whole world grows accordingly so though we see a 256px window at zoom 1 the world is 512px wide, at zoom 2, 1024 pixels and so on.

The world being 360o in the round, at zoom level 3 a degree would be 1024/360 = 2.84 ( or 1024/2pi if we want to work in radians).

Phew! Feel like we’re getting somewhere? Now we can correctly position a div from the edge of our static image.

Getting the y-position

Latitude is a little harder to calculate. From our page of maths we’ll take

y = ln( (1+sinO)/(1-sinO)) / 2   (I use this one as it uses basic calculator functions)

If we take our centre then plug its latitude (in radians) into our equation (replace that O after each sin) and multiply by the size of a radian calculation we did for Longitude, then we get where on our virtual map of the world the centre is. Since it is the centre we know it’s at 128px on a map thats 256px wide.

Now when we plug in the latitudes of our markers we get their y co-ordinates on our virtual map and we can place them on the window onto that world because we know its centre on both the virtual map and our window: Subtract our centre’s virtual y pixel value from our markers virtual y pixel – As if by magic it will give you the value to offset from our images centre.

Somethings missing here…

Now the observant among us will have noticed a bit of skating around some problems. We’ve been using the zoom value but we were hoping to use that nice Span attribute to give us our static map… Also, if instead of having a centre point we want the map to centre on the middle of a set of markerpoints then though the longitude of the centre will just be (maxLongitude+minLongitude)/2. The centre latitude, however, needs us to do some inverting on our y-position function.

Next week we’ll wrap up these problems and provide some code so you can happily ignore everything I’ve been talking about and actually see it in action.

Tim
Senior Researcher
RevaHealth.com

5 Responses to “How to make Google static maps interactive”

  1. Nesan says:

    Hi,
    I followed the given formulas for calculating the pixel values of map.I have 256×256 pix map.Center is at 40.702147,-73.9986.I substituted in the given formula but i am not getting 128px i am geetting someother values.Can you please tell me where i am going wrong.

    • Philip Boyle says:

      Hi Nesan,

      I’ve asked Tim to take a look at this and I’ll have an answer for your later today.

      Philip

  2. Tim says:

    Hi Nesan – hard to know what problem you are having but I did notice I wrote some of the examples down wrong 2 to the power of a zoom of 2 is clearly 4 and 4 times 256 is 1024… if that is not the problem here is some example code for the dynamic api that shows the same equations in action (some rounding errors in there but gives a pretty good idea of what’s going on). Should work off the file system without a key – play around with the ideas and then ask if you have any problems.

    Google Maps JavaScript API Example

    function initialize() {
    if (GBrowserIsCompatible()) {
    var map = new GMap2(document.getElementById(“map_canvas”));
    map.setCenter(new GLatLng(40.702147,-73.9986), 2);
    map.setUIToDefault();

    var leftEdge = new GPoint(0, 128);
    var leftLatLng = map.fromContainerPixelToLatLng(leftEdge);
    var rightEdge = new GPoint(255, 128);
    var rightLatLng = map.fromContainerPixelToLatLng(rightEdge);

    var degreesToLeftEdge = leftLatLng.lng()-map.getCenter().lng();
    var degreesToRightEdge = rightLatLng.lng()-map.getCenter().lng();

    var pixelWidth = (256 * Math.pow(2, map.getZoom()))/360;
    var calcDegreesToEdge = 128/pixelWidth;

    var radianPixelWidth = (256 * Math.pow(2, map.getZoom()))/(2*Math.PI);

    var radianCalc = Math.log( (1+Math.sin(map.getCenter().latRadians())) / (1-Math.sin(map.getCenter().latRadians())) )/ 2;

    var calcCentre = radianCalc * radianPixelWidth + 1;

    alert(degreesToLeftEdge + “, ” + degreesToRightEdge + “, ” + calcDegreesToEdge + “, ” + calcCentre);

    }

    }

  3. Nesan says:

    Thank you for your reply Tim.I got it correct now.

  4. Lots of incredibly good reading here, thank you! I had been seeking on yahoo when I uncovered your article, I’m going to add your feed to Google Reader, I look forward to more from you.

Comment

[Read More Web/Tech Posts]