I add a number of pushpins to a map and then "rightsize" or "right zoom" it so that all the pushpins show but so that the ones on the far edges are barely within the boundaries, like so:
However, if there is only one pushpin (as in the following case with Iowa, which only had the one civil war battle), rather than zero in on that as close as possible, it zooms out all the way to Skylab, like so:
This is the code I use to "right size" the map:
private void RightsizeZoomLevelForAllPushpins()
{
try
{
// Set the view so that all pushpins are displayed, with a bit of a margin around them
// from https://stackoverflow.com/questions/65779504/how-to-set-the-zoom-level-of-bing-map-to-just-wide-enough-to-display-all-pushpin/65781319#65781319
var map = this.userControl11.myMap;
var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);
//Margin
var w = new Pushpin().Width;
var h = new Pushpin().Height;
var margin = new Thickness(w / 2, h, w / 2, 0);
//Set view
map.SetView(locations, margin, 0);
currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
UncheckAllZoomLevelToolstripMenuItems();
SetZoomMenuItem();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
How can I get a one-pushpin map to not only center, but also zoom in as far as possible?
After adding parens to both references to Count, and adding an "if" in the else block so that it would compile, I still get two errors with this code:
private void RightsizeZoomLevelForAllPushpins()
{
try
{
// Set the view so that all pushpins are displayed, with a bit of a margin around them
var map = this.userControl11.myMap;
var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);
if (locations.Count() == 1)
{
map.setView(locations[0], singlePinZoom);
}
else if (locations.Count() > 1)
{
//Margin
var w = new Pushpin().Width;
var h = new Pushpin().Height;
var margin = new Thickness(w / 2, h, w / 2, 0);
//Set view
map.SetView(locations, margin, 0);
}
currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
UncheckAllZoomLevelToolstripMenuItems();
SetZoomMenuItem();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
They are:
1>C:\Users\bclay\source\repos\MyMaps\MyMaps\Form1.cs(155,33,155,45): error CS0021: Cannot apply indexing with [] to an expression of type 'IEnumerable<Location>'
1>C:\Users\bclay\source\repos\MyMaps\MyMaps\Form1.cs(155,25,155,32): error CS1061: 'Map' does not contain a definition for 'setView' and no accessible extension method 'setView' accepting a first argument of type 'Map' could be found (are you missing a using directive or an assembly reference?)
BTW, I'm not seeing any errors anymore in Visual Studio until I compile the project (it stopped finding errors as they were entered). I don't know why ... I changed no settings...
This is the code I'm using now, which does not take just one pushpin into account, but does work (note that "SetView" doesn't throw an exception here):
private void RightsizeZoomLevelForAllPushpins()
{
const int LEFT_TOP_RIGHT_MARGIN_ADDITION = 16;
const int BOTTOM_MARGIN_ADDITION = 48;
try
{
// Set the view so that all pushpins are displayed, with a bit of a margin around them
// from https://stackoverflow.com/questions/65779504/how-to-set-the-zoom-level-of-bing-map-to-just-wide-enough-to-display-all-pushpin/65781319#65781319
var map = this.userControl11.myMap;
var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);
//Margin
var w = new Pushpin().Width;
var h = new Pushpin().Height;
var margin = new Thickness((w / 2) + LEFT_TOP_RIGHT_MARGIN_ADDITION,
h + LEFT_TOP_RIGHT_MARGIN_ADDITION,
(w / 2) + LEFT_TOP_RIGHT_MARGIN_ADDITION,
0 + BOTTOM_MARGIN_ADDITION);
//Set view
map.SetView(locations, margin, 0);
currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
UncheckAllZoomLevelToolstripMenuItems();
SetZoomMenuItem();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
The Bing Maps website has this feature: on the map canvas, right click or tap and hold, then click or tap Measure Distance (can be used for lines and areas).
Each of the Bing Maps services uses a projected coordinate system called Mercator Auxiliary Sphere, which uses GCS_WGS_1984 as its geographic coordinate system. The Bing Maps web service projects on the fly and can be transformed to match your data precisely in the same way as any other data source.
Bing Maps aerial and satellite imagery is among the best available for online mapping platforms, with global coverage imagery up to 30cm/pixel resolution.
Sign in to the Bing Maps Dev Center. Click Update or view account details to view your account details, and then click Edit. Make your changes to the account information, and then click Save.
There is no single zoom level for a single pin, the best zoom level would depend on your scenario or what the pin is meant to represent, as well as the size of the map since both zoom and map size determine the viewable area. For example, if your pin represented a house you may want the map to be zoomed in more than if it represented a city.
That said, here is a modified version of your code that will handle the single pin scenario and use a static zoom level of your choosing:
private double singlePinZoom = 15;
private void RightsizeZoomLevelForAllPushpins()
{
try
{
// Set the view so that all pushpins are displayed, with a bit of a margin around them
var map = this.userControl11.myMap;
var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);
if(locations.Count() > 0) {
//Margin
var w = new Pushpin().Width;
var h = new Pushpin().Height;
var margin = new Thickness(w / 2, h, w / 2, 0);
//Set view
map.SetView(locations, margin, 0);
} else(locations.Count == 1) {
map.setView(locations[0], singlePinZoom);
}
currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
UncheckAllZoomLevelToolstripMenuItems();
SetZoomMenuItem();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
The answer in the other post shares the idea, but unfortunately is has(had) some syntax errors, and the logic of the if/else is wrong. As I mentioned in the comments, these are some points to which you should pay attention:
locations
in your code is IEnumerable<Location>
and it doesn't have Count
property, instead, you can use Count()
extension method on it.locations
doesn't have indexer like arrays and you cannot use locations[0]
to get the first element, instead you need to use locations.First()
.Count()>0
, then Count()==1
will never hit. So you need to change the conditions, for example first locations.Count() ==1
and then locations.Count() >1
.useing System.Linq;
so you can use Count()
and First()
methods.Here is the modified version of your code:
private void RightsizeZoomLevelForAllPushpins()
{
try
{
var map = this.userControl11.myMap;
var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);
if(locations.Count()==1)
{
//Your preferred zoom level
var zoomLevel = 12;
//Set view
map.SetView(locations.First(), zoomLevel );
}
else if (locations.Count()>1)
{
//Margin
var w = new Pushpin().Width;
var h = new Pushpin().Height;
var margin = new Thickness(w / 2, h, w / 2, 0);
//Set view
map.SetView(locations, margin, 0);
}
else
{
//Not necessary
System.Windows.Forms.MessageBox.Show("No pushpin.");
}
currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
UncheckAllZoomLevelToolstripMenuItems();
SetZoomMenuItem();
}
catch (Exception ex)
{
//Not necessary
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With