# Determining Best Map View for an array of locations

In the past it has been useful to be able to determine the best map view to display an array of locations. In the AJAX control there is a method call SetMapView which determines the best map view for an array of coordinates. The VEWS and Silverlight control do not have this functionality. A long time ago someone wanted to know how to determine the best map view before loading the map. This required us to calculate out the best map view ourselves using map scale information. I later implemented the same method when working with the VEWS so that I could geo-reference images from the Imagery service (http://rbrundritt.spaces.live.com/blog/cns!E7DBA9A4BFD458C5!488.entry). The method worked fairly well but I knew there was a better way to do this. When working with the Silverlight control I came across a situation where I needed this functionality again so I decided to create the updated method for determining the best map view using similar math that is used for the tiling system. This eliminated the need to maintain a list of scales for each zoom level and also reduce the amount of calculations that needed to be performed. Below is the updated algorithm for determining the best map view for a list of locations:

 /// /// Calculates the best map view for a list of locations for a map/// /// List of location objects/// Map width in pixels/// Map height in pixels/// Width in pixels to use to create a buffer around the map. This is to keep pushpins from being cut off on the edge/// Returns a MapViewSpecification with the best map center point and zoom level for the given set of locationspublic static MapViewSpecification BestMapView(IList locations, double mapWidth, double mapHeight, int buffer){    MapViewSpecification mapView;    Location center = new Location();    double zoomLevel = 0;     double maxLat = -85;    double minLat = 85;    double maxLon = -180;    double minLon = 180;     //calculate bounding rectangle    for (int i = 0; i < locations.Count; i++)    {        if (locations[i].Latitude > maxLat)        {            maxLat = locations[i].Latitude;        }         if (locations[i].Latitude < minLat)        {            minLat = locations[i].Latitude;        }         if (locations[i].Longitude > maxLon)        {            maxLon = locations[i].Longitude;        }         if (locations[i].Longitude < minLon)        {            minLon = locations[i].Longitude;        }    }     center.Latitude = (maxLat + minLat) / 2;    center.Longitude = (maxLon + minLon) / 2;     double zoom1=0, zoom2=0;     //Determine the best zoom level based on the map scale and bounding coordinate information    if (maxLon != minLon && maxLat != minLat)    {        //best zoom level based on map width        zoom1 = Math.Log(360.0 / 256.0 * (mapWidth – 2*buffer) / (maxLon – minLon)) / Math.Log(2);        //best zoom level based on map height        zoom2 = Math.Log(180.0 / 256.0 * (mapHeight – 2*buffer) / (maxLat – minLat)) / Math.Log(2);    }     //use the most zoomed out of the two zoom levels    zoomLevel = (zoom1 < zoom2) ? zoom1 : zoom2;     mapView = new MapViewSpecification(center, zoomLevel);     return mapView;}

## 17 thoughts on “Determining Best Map View for an array of locations”

1. HI There: First this algorithim is working beautifully for many shapes (Country polygon) drawn, However when Im plotting only the United States The map is panned to the side (the US is not in the center)… Why is that?

• It’s likely centered to the left of the USA as Hawii and Alaska are off that way.

2. Anonymous says:

If only one location is to be plotted, can we set a default zoom level or is there some calculation?

• You could add simple logic that sets a default zoom level if only one location is provided.

• Anonymous says:

It has to be calculated as the width and height of the map can vary. Can the above code be changed for that?

• Simply use events to determine when the map dimensions change and recall this method. This method only calculates the best map view for the map at a single instance. It doesn’t do any monitoring.

3. Anonymous says:

When the above logic is used to calculate for pushpins, I get a zoom value of 11 and one of the pushpin is not appearing in the image. But when the zoom is 10 all of them appears.
check the link below. Am I doing something wrong?
http://dev.virtualearth.net/REST/v1/Imagery/Map/road/33.0997,-96.6821/10?pushpin=33.0997,-96.6821;1;1&pushpin=33.121754,-96.662309;1;2&pushpin=33.1286,-96.7298;1;3&pushpin=33.0376,-96.7077;1;4&pushpin=33.1048,-96.8123;1;5&v=1&mapsize=350,400&o=xml&key=bingKey

• You need to provide a buffer value into the calculation. The buffer value should be the half the width of the pushpin. This ensures that the pushpin shows up. Based on what I see I would recommend a buffer of 20 pixels.

• Anonymous says:

How to determine the width of pushpin?

• You have to approximate this as there is no way to determine this unless you are using a custom pushpin and another workaround I created. As I said before use a buffer of 20 pixel which is approximately the width of the pushpin in the example provided.

4. Dude, thanks a lot for this code, I was looking for a way to calculate the zoom for some bounds and you just saved my live, I ported this to JavaScript and works awesome!

5. Madhusuhan says:

Hi,

I found this as a handy article.

But, I did struggle to understand the zoom formula:

Math.Log(180.0 / 256.0 * (mapHeight – 2*buffer) / (maxLat – minLat)) / Math.Log(2);

It would be great if you can describe each constants being used in the formula and how did you derive formula.

Thanks in advance for the help.

• The math behind this is actually pretty straight forward. This calculation determines the best zoom level based on the height of the map. In the code sample I also do the same based on the width of the map and then take the most zoomed out value of the two. The Log(x)/Log(2) where x is the rest of the math is the opposite of 2^x. Basically the with and height of the map in pixels at any zoom level is equal to 256 pixels * 2^zoom. The buffer simply accounts for a pixel sized buffer around the map and is used to account for the size of pushpin icons as the calculation itself without the buffer only accounts for the single pixels of the coordinates and does not account for the pushpin icon size. A lot of the math is based on this article: http://msdn.microsoft.com/en-us/library/bb259689.aspx

• Anonymous says:

Thanks a bunch for the detailed reply.

6. Faheem Amjad says:

This is best solution for map zoom based on pins
crowbarsolutions.com/adjusting-zoom-level-to-add-padding-to-map-bounding-boxes-bing-maps-v7/

• This algorithm is good for any platform and uses pixel buffering which is more accurate. The version of Bing Maps in the post you mention is deprecated. In Azure Maps you can do the following:

`var bounds = atlas.data.BoundingBox.fromPositions(locations);`

``` //Or if you have shapes. //var bounds = atlas.data.BoundingBox.fromData(shapes); ```

```//You can then pass a padding value when setting the map camera. map.setCamera({ bounds: bounds, padding: 30 });```

If you simple want to zoom into clusters, this sample shows how to do that in Azure Maps.
https://azuremapscodesamples.azurewebsites.net/index.html?sample=Point%20Clusters%20in%20Bubble%20Layer