# How to calculate the optimal zoom-level to display two or more points on a map

We want to display several markers on a static map and want to calculate the optimal zoom-level like Google Maps does. We already calculated the bounding rectangle and the centerpoint of the map but now we have a hard time to calculate the correct zoomlevel to display the whole bounding rectangle. Can someone please point us into the right direction?

-
It's not very sophisticated, but why not just multiply the MBR by 120% and zoom to that? Anything else depends on your definition of "optimal", doesn't it? – ThomM Feb 2 '12 at 0:06
+1 to ThomM's idea. This is exactly what ArcGIS does. – Ragi Yaser Burhum Feb 2 '12 at 0:17
Sorry, but what is this MBR? – Rodrigo Feb 11 '15 at 23:52

To get the zoom level, you'll need to know the pixel dimensions of your map. You'll also need to do your math in spherical mercator coordinates.

1. Convert latitude, longitude to spherical mercator x, y.
2. Get distance between your two points in spherical mercator.
3. The equator is about 40m meters long projected and tiles are 256 pixels wide, so the pixel length of that map at a given zoom level is about 256 * distance/40000000 * 2^zoom. Try zoom=0, zoom=1, zoom=2 until the distance is too long for the pixel dimensions of your map.
-
Hope I've remotely understood what you're actually asking. =\ – Michal Migurski Feb 2 '12 at 1:54
Found this question while looking for this answer, thanks. – BenjaminGolder May 17 '12 at 9:32
@MichalMigurski can you explain how to calculate the distance between 2 points in spherical mercator? specially the x coordinates... i'm stucked thanks. – otmezger Dec 18 '13 at 18:19

This is the C# code I use in Maperitive:

``````    public void ZoomToArea (Bounds2 mapArea, float paddingFactor)
{
double ry1 = Math.Log((Math.Sin(GeometryUtils.Deg2Rad(mapArea.MinY)) + 1)
double ry2 = Math.Log((Math.Sin(GeometryUtils.Deg2Rad(mapArea.MaxY)) + 1)
double ryc = (ry1 + ry2) / 2;

double resolutionHorizontal = mapArea.DeltaX / Viewport.Width;

double vy0 = Math.Log(Math.Tan(Math.PI*(0.25 + centerY/360)));
double vy1 = Math.Log(Math.Tan(Math.PI*(0.25 + mapArea.MaxY/360)));
double viewHeightHalf = Viewport.Height/2.0f;
double zoomFactorPowered = viewHeightHalf
/ (40.7436654315252*(vy1 - vy0));
double resolutionVertical = 360.0 / (zoomFactorPowered * 256);

double resolution = Math.Max(resolutionHorizontal, resolutionVertical)
double zoom = Math.Log(360 / (resolution * 256), 2);
double lon = mapArea.Center.X;
double lat = centerY;

CenterMapOnPoint(new PointD2(lon, lat), zoom);
}
``````
• `mapArea`: bounding box in long/lat coords (x=long, y=lat)
• `paddingFactor`: this can be used to get the "120%" effect ThomM refers to. Value of 1.2 would get you the 120%.

Note that in my case `zoom` can be a real number. In the case of Web maps, you need a integer zoom value, so you should use something like `(int)Math.Floor(zoom)` to get it.

Of course, this code only applies to Web Mercator projection.

-
Thanks for this. Is the code for CenterMapOnPoint available? – mcintyre321 May 6 '14 at 14:54

If you are using OpenLayers then `Map.getZoomForExtent` will calculate the highest zoom level that can fit the entire extent on the map. The `extent` needs to be in the map's projection. You can also use a `fill_factor` to avoid displaying points on the edge of the map, and `max_zoom` to limit the possible zoom:

``````extent = extent.scale(1/fill_ratio);
var zoom = Math.min(map.getZoomForExtent(map_extent), max_zoom);
map.setCenter(extent.getCenterLonLat(), zoom);
``````
-