Set zoom level of a google map based on markers

Posted by Aiska Hendra


Yesterday my Project Manager asks me to embedded Google Map into the module.

It’s should be easy to do, but after I try so many times I failed to complete this task.

The main problem is I cannot set zoom level of Google Map that all markers are visible.

Then I search in Google and Google Map Documentation, and I still did not find any good solution,

So I decide to find my own solution. This is my solution
First think I do is get the minimum, maximum and center of the marker.

var minlat = [Minimum Latitude];
var maxlat = [Maximum Latitude];
var minlng = [Minimum Longitude];
var maxlng = [Maximum Longitude];
var ctrlng = [Center Longitude];
var ctrlng = [Center Longitude];


The second way is I calculate the distance of Minimum and Maximum Latitude and Longitude. After I search in Google I found formula to calculate distance in Google Map.

var dist = (6371 * Math.acos(Math.sin(minLat / 57.2958) * Math.sin(maxLat / 57.2958) + (Math.cos(minLat / 57.2958) * Math.cos(maxLat / 57.2958) * Math.cos((maxLng / 57.2958) - (minLng / 57.2958)))));

Then I calculate Google Map distance for each Zoom Level by using of formula of distance.
Base on calculate of Google Map distance for each level, so I make formula to calculate zoom level. The formula is :

var zoom = Math.floor(8 - Math.log(1.6446 * dist / Math.sqrt(2 * (mapdisplay * mapdisplay))) / Math.log (2));


where :
dist = the distance of bound
mapdisplay = the square display of Google Map in pixel (I get from height or width of Google Map where is the smallest).

But I have a problem when Minimum and Maximum of Latitude is equal, and the zoom level become incorrect,

The problem is I calculate the horizontal marker, and calculate the diagonal of Google map where diagonal is more longer than horizontal or vertical, that's why zoom level is not correct.

So I decide to make all diagonal calculate. And I change the minimum and maximum of latitude and longitude. To the largest value so I can calculate the diagonal value.

var interval = 0;
If ((maxlat - minlat) > (maxlng - minlng)) {
interval = (maxlat - minlat) / 2;
minlng = ctrlng - interval;
maxlng = ctrlng + interval;
} else {
interval = (maxlng - minlng) / 2;
minlat = ctrlat - interval;
maxlat = ctrlat + interval;
}


Then I calculate again, and it’s work.

full code should be like this

var minlat = [Minimum Latitude];
var maxlat = [Maximum Latitude];
var minlng = [Minimum Longitude];
var maxlng = [Maximum Longitude];
var ctrlng = [Center Longitude];
var ctrlng = [Center Longitude];
var mapdisplay = 600;
var interval = 0;

If ((maxlat - minlat) > (maxlng - minlng)) {
interval = (maxlat - minlat) / 2;
minlng = ctrlng - interval;
maxlng = ctrlng + interval;
} else {
interval = (maxlng - minlng) / 2;
minlat = ctrlat - interval;
maxlat = ctrlat + interval;
}

var dist = (6371 * Math.acos(Math.sin(minLat / 57.2958) * Math.sin(maxLat / 57.2958) + (Math.cos(minLat / 57.2958) * Math.cos(maxLat / 57.2958) * Math.cos((maxLng / 57.2958) - (minLng / 57.2958)))));

var zoom = Math.floor(8 - Math.log(1.6446 * dist / Math.sqrt(2 * (mapdisplay * mapdisplay))) / Math.log (2));

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(ctrlat, ctrlng), zoom);


Ok that’s all Thank you, and I hope this article can help you and others.
Thanks to Dusan for the formula and all Google Map Programmer for helping me to Finnish this task.

27 comments:

  1. Alex said...

    Your formula for getting the zoom level looks very promising - does it work 100%?

    Check out my approach too: http://www.adick.at/2008-12-30,set-zoom-level-of-a-google-map-so-that-all-markers-are-visible/

  2. Aiska Hendra said...

    Thanks Alex you're inspire me to finish this task.

  3. Sujai SD said...

    Why not trying this method


    var mapUtil = {

    minLat: null,
    maxLat: null,
    minLng: null,
    maxLng: null,

    calculateBorders: function(latitude, longitude) {
    latitude = Number(latitude);
    longitude = Number(longitude);
    if(typeof(latitude) == 'number' && typeof(longitude) == 'number') {
    if(mapUtil.minLat == null || mapUtil.minLat > latitude) {
    mapUtil.minLat = latitude;
    }

    if(mapUtil.maxLat == null || mapUtil.maxLat < latitude) {
    mapUtil.maxLat = latitude;
    }

    if(mapUtil.minLng == null || mapUtil.minLng > longitude) {
    mapUtil.minLng = longitude;
    }

    if(mapUtil.minLax == null || mapUtil.maxLng < longitude) {
    mapUtil.maxLng = longitude;
    }
    }
    },

    zoomToViewAll: function() {
    var visibleBounds = mapUtil.getVisibleBounds();
    if(visibleBounds) {
    var boundsCentre = visibleBounds.getCenter();
    var zoomLevel = mainMap.getBoundsZoomLevel(visibleBounds);
    if(zoomLevel < 15 ) {
    mainMap.setCenter(boundsCentre, zoomLevel);
    }
    else {
    mainMap.setCenter(minBoundsCentre, 15);
    }
    }
    },

    getVisibleBounds: function() {
    if(mapUtil.maxLng) {
    var swLatLng = new GLatLng(mapUtil.minLat, mapUtil.minLng);
    var neLatLng = new GLatLng(mapUtil.maxLat, mapUtil.maxLng);
    var minBounds = new GLatLngBounds(swLatLng, neLatLng);
    return minBounds;
    }
    return null;
    }
    }


    use the
    mapUtil.calculateBorders(lat, lng); for each marker
    then call the mapUtil.zoomToViewAll()

    the mainMap is the variable containing GMap2

  4. Saleem said...

    Hi Tnx A lot 4 ur code.......................

  5. Anonymous said...

    horray! good solution, works for me.
    i did implement it server-side only the calculation of the zoom level using:

    int mapdisplay = Math.min(pixelHeight, pixelWidth);
    return (int) Math.floor(8 - Math.log(1.6446 * distance*2 / Math.sqrt(2 * (mapdisplay * mapdisplay))) / Math.log(2));

    distance * 2 because of radius vs diameter...

  6. Flyzoom said...

    Does this work when there is only one marker and it zoom too close?

  7. Niladri Sarkar said...

    Excellent! Thanks a lot for such a nice input.

    Although I have only tested this in Firefox, but I hope it will work fine in other browsers too.

  8. Irineu Martins Junior said...

    @Sujai SD, thanks for your code.
    I guess that I fix it =)

    http://www.mixd.com.br/irineu/gmaps/index.php

    @Aiska, thanks a lot... excellent post.

  9. Anonymous said...

    Could any one let me know how to calculate the
    center latitude and longitude.

    May be I sound like a dumb, but that would be very grateful.

    Thanks.

  10. Anonymous said...

    $ctrlat=($minLat+$maxLat)/2;
    $ctrlng=($minLng+$maxLng)/2;

    MYRE REalty Manager

  11. Bruce said...

    You saved my life. Thanks you!
    I just needed that piece of Zoom calculation from your program.. I could not find that anywhere.. did google have that formula somewhere??
    Anyways, really appreciate you sharing that with us!

  12. Anonymous said...

    Thank you very much. This is worked.

  13. Anonymous said...

    Thank you!!! it really works.

  14. Anonymous said...

    Nice solution. I had a similar problem, but I just decided to only display markers inside the bounds of my map :P Sort of avoided the problem...

  15. Luis Merino said...

    I'm using Google's V3 API like this:

    var bounds = new google.maps.LatLngBounds();
    bounds.extend(myMarker.getPosition());
    myMap.fitBounds(bounds);

    However, when having only a marker in the map I find it zooms in too close. I've been looking to calculate a circular distance of X meters from the marker without having to create a Circle or any other Overlay. e.g.

    bounds.extend(new google.maps.Circle({map:map, radius:100}).getBounds());

    <<< that would be the quick solution, but creating an unnecessary overlay.

    I've been looking a way to reckon SW tangent and NE tangent points, so I can achieve a nice zoom level.

    How would you do this?

  16. Luis Merino said...

    I found the answer to my problem. I anybody is interested refer to: movable-type.co.uk/scripts/latlong.html -> "Destination point given distance and bearing from start point"

  17. Anonymous said...

    Thank you!
    You did a great job!
    All well calculate, look: http://map.vashotdyh.com/

    Sincerely, Alexander.

  18. Anonymous said...

    I can confirm this works beautifully!

    Thanks!

  19. Anonymous said...

    Nice work, that's saved me a bunch of time!

    Just a quick note to say that the casing is inconsistent in the javascript so doesn't work straight away. E.g minlat in top two blocks of code and minLat in bottom formulas.

  20. Anonymous said...

    Very nice, saved me a whole lot of time, THANK YOU!

  21. Indu said...

    It worked perfectly for me..Thank you very much Aiska...

  22. Anonymous said...

    This is an excellent solution, thank you so much for your help. Works great, I multiplied the Distance by 2 as suggested by Comment 5 above.

  23. Anonymous said...

    This code saved my day, thank you.

  24. Wuri Nugrahadi said...

    Saya pke plugin jQuery, jd critanya klo ngatur zoom level pke GLatLngBounds harus ngoprek plugin.
    Ketemu hitungan ini memecahkan msalah saya.
    Makasih buat solusinya!

  25. Rodion said...

    Thanks for the code — it helped a lot and saved me lots of time. I ported it to PHP and now I can get Google Static Maps with an appropriate zoom level.

  26. Testerli said...

    Thanks a lot for your code. Worked almost perfectly.

  27. john alex said...

    nice write up.Calculate area of any building with Google maps.

Post a Comment