In usability we trust

Bounding Box in Google Maps

Normally when you initialize a new Google map you set the coordinates for the center of the map and manually specifies the initial zoom level. Sometimes, however, there’s a need to dynamically calculate the center point and zoom level for certain content to fit into the viewport.

Let’s say that you have a number of markers on a map and you want the map to be displayed so that they all fit inside the viewport. You could of course experiment with center point and zoom levels to get it right. But what if the markers are put there dynamically so you don’t know beforehand where they’ll show up?

That’s where this trick will come in handy.

Using a Bounding Box

First you have to calculate the bounding box. That is, the coordinate for the south-west and north-east corners. In this case the coordinates for the marker that’s most south and the marker that’s most west provides the coordinates for the south-west corner. And vice versa for the north-east corner.

Now that you know the coordinates you just have to create a GLatLngBounds object, define it’s coordinates and serve it to GMap2.setCenter().

GLatLngBounds takes two optional arguments. A GLatLng for the south-west corner and a GLatLng for the north-east corner.

GMap2.getBoundsZoomLevel() calculates the appropriate zoom level to fit the bounding box in the available viewport. It also adds some extra padding around the box.

map = new GMap2(document.getElementById("map"));

// Define the two corners of the bounding box
var sw = new GLatLng(59.0, 13.12);
var ne = new GLatLng(60.35, 16.90);

// Create a bounding box
var bounds = new GLatLngBounds(sw, ne);

// Center map in the center of the bounding box
// and calculate the appropriate zoom level
map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));

Watch the live demo

I was shown this technique by my good friend Fredrik Jonsson, who writes about programming on freddes.se.

Share this article

  • del.icio.us
  • Twitter
  • Facebook
  • LinkedIn
  • Digg
  • StumbleUpon
  • Google Bookmarks
  • Mixx
  • Print

Comments

RSS feed for comments on this post

1. November 24th, 2008 at 3.15 by Mathias

Thank you so much I been looking for this for a looong time :)

2. January 15th, 2009 at 5.11 by Alan

Wait a minute – where did you get the values for sw and ne from? Wasn’t the point of the article to show how to create a box around a _dynamic_ set of points?

3. January 15th, 2009 at 7.17 by Gabriel Svennerberg | Author comment

Alan: Yes that’s right, but for the sake of simplicity in the example, I have explicitly defined the corners of the bounding box. In a real-world implementation I would naturally calculate sw and ne from the data that I’m showing.

4. January 16th, 2009 at 9.33 by Alan

Can you explain a good way to determine the sw and ne from the data?

I can imagine doing a minimum and maximum loop thru all the data, but it seems like there should be an easier way to get via an api call of some sort.

5. January 19th, 2009 at 10.19 by Gabriel Svennerberg | Author comment

Alan: There are several ways to do it servers-side depending on which language you use. In a solution I’m currently working on where we use C# and SQL Server 2008 I use the SqlGeometry object to handle GEO data. I get the data that I want to display on the map as a SqlGeometry object and on that object I then call the method STEnvelope() which returns a Bounding Box for the GEO data.

In the Google Maps API there’s the GLatLngBounds class which is a representation of a BoundingBox. Some overlays such as GPolyLine and GPolygon has a getBounds() method that returns a GLatLngBounds. In the case of markers I don’t know of any easy way to do it. I guess one have to do as you suggest and loop through them all to extract min and max values.

6. January 28th, 2009 at 12.52 by Aiska

Actually you don’t have to Define the two corners of the bounding box because it can assign later by using extend.

var bounds = new GLatLngBounds();
bounds.extend(GLatLng(lat:Number, lng:Number));

so you have to assign all marker by using this code
bounds.extend(GLatLng(lat:Number, lng:Number));

but sometimes the function of :
map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
didn’t work properly and will returns an incorrect zoom level. until now i can’t figure out this problem.

7. January 28th, 2009 at 13.28 by Gabriel Svennerberg | Author comment

Aiska: Cool! I never thought of that, but naturally that’s one way to do it. Thanks!

I have never encountered the error you’re talking about myself. Could be a bug in the API?

8. January 29th, 2009 at 11.32 by Aiska

Gabriel Svennerberg: yeah that’s right maybe this is bugs in API.

I found new method how to set zoom level of a google map base on markers.

maybe you can check this out for your reference. Thanks

Set zoom level of a google map base on markers

9. January 29th, 2009 at 14.59 by Gabriel Svennerberg | Author comment

Aiska: After looking at your code again it occurred to me that there’s a problem in it and that is in how you extend the bound. You don’t use the new keyword when you create a new GLatLng. It should be:

bounds.extend(new GLatLng(lat, lng));

Maybe that’s the reason it doesn’t work properly?

I haven’t looked at your new method yet.

10. February 22nd, 2009 at 13.59 by Alex O'Byrne

If you’re getting the lat and long from a collection of Ruby objects.

Here’s the method:

# returns a hash of top right and bottom left bounds
def self.bounds(collection)
top = 0
bottom = 0
right = 0
left = 0
initially_set = false
collection.each do |point|
if point.lat and point.long
if !initially_set or point.long > top
top = point.long
end
if !initially_set or point.long right
right = point.lat
end
if !initially_set or point.lat < left
left = point.lat
end
initially_set = true
end
end
# you could add 10% to each value here
# if your map is correct portioned (otherwise)
# your centre will be skewed
# now create the hash
result = Hash.new
result[:top] = top
result[:bottom] = bottom
result[:right] = right
result[:left] = left
return result
end

And then in the map definition…

// if we have a collection of items, set the map to fit them all
// Define the two corners of the bounding box
var sw = new GLatLng(, );
var ne = new GLatLng(, );
var bounds = new GLatLngBounds(sw, ne);

11. February 22nd, 2009 at 14.01 by Alex O'Byrne

OK that didn’t post directly… I’ll reformat it and post again later.

12. June 5th, 2009 at 12.00 by gopi

Here This bounded rectangle is not working in all the cases
when we move the map at some zoomlevel

NorthEast (topRight) points (70.495574, -102.304688)
topRight[0] = 70.495574;
topRight[1]= -102.304688;

SouthWest(BottomLeft) points (-59.712097, 47.109375)
BottomLeft[0] =-59.712097;

and my point is under this getBounds

we have a condition like

if(lat > bottomLeft[0] and lat BottomLeft[1] and lng < TopRight[1])
{}
this condition falils in some points even though its under that Bounded Rectangle
and the actual point is (30.145127,75.234) between those top and bottom points

13. November 17th, 2009 at 18.32 by Toleti S

We have an image with two points in the middle and the bound area in pixels only and two reference points in the image with their pixel coordinates. We can get a zoom/scale for the image based on the above data.

We also know the latlng for the above two reference points.

How do I set the box north-east and south-west corners so that I can place it on the map.

Appreciate any help/pointers.

Thanks

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>