Following on from his post last week, Tim is back to with a little bit more explanation and some code to show you how to implement his method of making Google static maps interactive.
Add Marker divs to your static maps (Part 2)
Lets start by handling a set of points. We can easily loop over them to find the max and min latitudes and longitudes of the set.
Getting the centre
To find the longitude centre is easy: sum the max and min longitudes and divide by 2. The centre latitude is harder – put the max and min latitudes through our Mercator equation for latitude that we used last time:
y = ln( (1+sinO)/(1-sinO)) / 2
Add the results together and divide by 2 – then invert the function, which is Math.Atan(Math.Sinh( RESULT )) – where RESULT is (ln((1+sin(radians(maxLatitude))/(1-radians(maxLatitude))) / 2 + ln((1+sin(radians(minLatitude))/(1- adians(minLatitude)))) /2
We’ll have been working in radians so multiply this result by 180.00 / Math.PI to get the centre Latitude in degrees.
Calculate the zoom level
To find the zoom level necessary to contain our set of points we first calculate the span of degrees of the latitudes and longitudes. Subtract the minimums from the maximums to give us the largest spans by degrees for our latitude and longitude. If we zoom to a set level on a Google map: at any given zoom level anywhere on the earth the difference
between the maximum longitude and the minimum longitude remains the same. – If we return to our discussion of zoom levels from last week and work backwards… we can see that once we know a longitude span we can use it to find an appropriate zoom level. The equation ends up being:
log base2 of (180o / longitudeSpano)
That all required that the longitude was the span we were interested in… Now – if we look at a square map on a page, the central x-axis span does not equal the y-axis span (except at the equator) – Longitude is greater. This means that even if the longitude span is greater than the latitude span, if we set our zoom by longitude all our points’ latitude
values do not necessarily fit inside our returned map. Luckily, there is a consistent relationship between these spans that depends on latitude – as we get nearer to the equator our latitude spans get closer and closer to our longitude spans (on our handy square map), and by dividing our latitude span by the cos of the centre latitude we’ll get the value of our longitude span. This means we can use the zoom level calculation above – using max( longitude span , adjusted latitude span ) as our value.
As if that all wasn’t enough, the old problem crops up: that the map only fits the world perfectly at zoom level 0 if it is 256 pixels wide. To account for this before we take our log, divide by 256 and multiply by the width of the map in pixels (at 256pixels wide we get back to where we started).
Well that about wraps it up! As promised, it is possible, maybe even advisable to ignore my convoluted explanation and just use some preprepared code snippets instead!
MAP_SIZE = 256;
private double atanh(double rad)
enumerator.MoveNext(); ) // for(Iterator<LaitutudeLongitude>
latitudeLongitudeIterator = etc.. for java heads
// LaitutudeLongitude markerDetails
= latitudeLongitudeIterator.next(); for java heads, you get the idea
id=’id” + id + “‘ ” + ROLLOVER_STYLE_STRING + ” left:” + roleOverX +
“px; top:” + roleOverY + “px; ‘></div>”;
Thanks!