Monday, May 07, 2012

Windows Phone development: an alternative to zooming all your map locations into view

When you’re using the Maps control to layout your items it’s always nice if you give the user the possibility to zoom/scale to show all items, this however can be a pain. While I’ve seen a few different approaches to solving this, like diving deep into projection/delta and more I thought I’d share a different (and a lot easier) approach.

Often it’s sufficient enough to just create a LocationRect based on the current GeoCoordinates and add a little “padding” to it, then call the SetView method of the map with that LocationRect.

Here’s a sample:

image

in the image above we’re fairly zoomed down to a level where a lot of items are simply out of view. That helicopter button in the application bar does the following when clicked:

            // simple collection later used for the LocationRect..
            List<GeoCoordinate> coords = new List<GeoCoordinate>();

            // add current location (yeah, we wanna be in the picture as well)
            coords.Add(viewModel.CurrentLocation);
            
            // transform any location-aware item collections into simple GeoCoordinate lists, then add that to the coords list..
            if (this.mapServiceUnits.Visibility == System.Windows.Visibility.Visible)
                coords.AddRange(viewModel.ServiceUnits.Select<Usoniandream.WindowsPhone.LocationServices.Models.Stockholm.Base.IServiceUnit, GeoCoordinate>(x => x.Location));
            if (this.mapNokiaPlaces.Visibility == System.Windows.Visibility.Visible)
                coords.AddRange(viewModel.NokiaPlaces.Select<Usoniandream.WindowsPhone.LocationServices.Models.Nokia.Places.Place, GeoCoordinate>(x => x.Location));
            
            // finally, use the GetLocationRect with a little "padding" to nicely fit the items in view. (mapLocations is the name of the map control in this example)
            mapLocations.SetView(MapExtensions.GetLocationRect(coords, 0.003));

and that leaves us with a map zooming out nicely to show all the items:

image

How was that accomplished? Basically all you need is the GetLocationRect extension method included in the code below:

//
// Copyright (c) 2012 Peter Drougge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.Phone.Controls.Maps;
using System.Device.Location;
using System.Collections.Generic;

namespace Usoniandream.WindowsPhone.Extensions
{
    public static class MapExtensions
    {
        public static LocationRect GetLocationRect(IEnumerable<GeoCoordinate> coords, double padding)
        {
            LocationRect rect = LocationRect.CreateLocationRect(coords);
            if (padding>0)
            {
                rect.West -= padding;
                rect.East += padding;
                rect.North += padding;
                rect.South -= padding;
            }
            return rect;
        }
    }
}

now, just to clarify I’m gonna show those images next to each other so you’ll see the difference:

imageimage

It might not be the most elegant solution, nor the most mathematically correct, but if you just want to make sure your items (at least the actual locations of them) are in view, well then I’m confident that little piece of code will suffice.

No comments: