Displaying static maps on the Windows Phone for performance and scenario wins
January 31, 2012
One of the nice visuals of 4th & Mayor is the animation and display of a simple area map whenever you view a place in the app.
Unfortunately, most map controls, such as the Bing Maps control included with the platform, are highly sophisticated: they let you have a bunch of pushpins, gather information about bounding boxes, etc. This awesome feature set can have a negative effect on performance.
2/1/2012 Update: Thanks to Tim Heuer, who just provided a pull request that adds an OpenStreetMap provider, MapQuest provider, offers the ability to add an authentication key optionally as a property on the control, and to specify the type of maps. I’ve updated NuGet to 1.1 with these contributions, thanks!
My static map control is simple but nice because it’s an easy replacement, can be used in Panorama/Pivots, and overall still has a great, high-speed experience that your users will enjoy.
A sample static Bing Map from 4th & Mayor: touching the map takes you to an interactive map view page allow for directions, panning, etc.
“JeffWilcox.Maps” Component
I’ve refactored one of the libraries used in my app to be general enough for others to use: it offers simple static map code in the form of a “StaticMap” control: just drop it into your XAML page and you’re mostly good to go.
The MapCenter property takes a GeoCoordinate, either data bind it or set the property as the page is navigated to.
Over time I’ll consider adding more of the functionality I’ve had to the library, including the interactive libraries.
Get the library
I’m using my favorite pair of deployment places for this library: GitHub for source, NuGet for binaries.
NuGet
The library is JeffWilcox.Maps
Source on GitHub
Fork the repo, wp-maps
Offering an interactive experience
To optimize the maps experience, I instead decided to use the static map REST APIs from Bing Maps for my mobile application: this lets me perform a HTTP request, grab the image, and data bind it into my display.
I then place it inside a borderless, retemplated Button control, so that touching the map takes you to a new page: an experience where I can show the real Bing Maps control, your current position, as well as the location of the place you are trying to go. By moving this to a separate assembly, I get great performance wins: the Bing Maps control and other code needed to offer the rich interactive experience is delay loaded and only there when needed.
Properties on the control
These properties are on the initial version of the control:
Foreground is supported and used for the implicit, centered point: it’s Black by default to match the Windows Phone’s “Maps” app, but I find that using {StaticResource PhoneAccentBrush} looks great in my opinion.
MapCenter takes a GeoCoordinate, this is a key property.
ZoomLevel sets the zoom level (default of 15 I think) for the map. 1 effectively shows a bunch of the world, and 21 shows street level sizes. The zoom levels for Goog and Bing are pretty similar.
MapCenterVisibility defaults to Visible, and if you decide you don’t want the center point to be on the view, just set this to Collapsed.
IsSensorCoordinate should be data bound, some APIs (like Google’s) require that the API call identify whether it’s a position from a sensor, or a database. In my case, sensor is used for any GeoCoordinateWatcher/LocationService code, while I set it to False for data from the Foursquare venues database where I get info about a place.
Provider sets the static map provider to use.
The height and width are automatically identified by the system, but many APIs limit the width and height to small numbers (typically <= 640 pixels in any direction), FYI.
Bing Maps API Key
If you’re using Bing Maps, you’ll need a Bing Maps API key and to make sure that your app is compliant with the requirements of its terms and conditions. This is the same key you use with the Bing Maps control.
For this first version you have to set the API key as a string resource inside your App.xaml file.
Here’s how you would go about this: add the namespace and set the string – I’ve put a comment where your key should go in App.xaml:
<Application x:Class="StaticMapSample.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:core="clr-namespace:System;assembly=mscorlib"> <!--Application Resources--> <Application.Resources> <core:String x:Key="BingMapsKey"><!-- Place your Bing Maps API key here--></core:String> </Application.Resources> <Application.ApplicationLifetimeObjects> <!--Required object that handles lifetime events for the application--> <shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated"/> </Application.ApplicationLifetimeObjects> </Application>
I haven’t decided if this is better or worse than just exposing an API key property for you to bind or set on the page, but I really like just having one central place in an app to put the key.
Static map providers
The initial implementation has a simple enum for chosing between two provider choices, Bing Maps and Google Maps. I’ve decided to include Google Maps because it turns out that in some parts of the world, Google Maps are much better, and I’ve had hundreds of app users ask for a setting to instead use Google Maps. There are slightly different requirements for its API, such as exposing an “open in web browser” function so that the user could decide to open the same map view in the browser on the phone.
Just set the Provider property on the StaticMap to either Bing or Google. The default is Bing, as it should be!
Here’s a screenshot of the sample app I’ve included in the GitHub repo (though if you use it, remember to put your Bing Maps API key inside of the App.xaml file first!) – it has both Bing and Google Maps, and the application bar is hooked up to events to open the Maps app on the phone or to open the browser with the appropriate map page. Take a look.
On the right, the expanded app bar: your app may need to expose the “open in browser” option to comply with the terms and conditions that you interpret on the maps API of your choice. Also, the “open in maps app” is a nice function to provide users who want to open the location in the main OS’s Maps app.
Design note: flush maps
One design technique that I use in my app, as does the “Local Scout” app in Mango, is having a “flush” map experience: the map extends to the edge of the phone, instead of the standard spacing with margins from the edges of the phone.
This visual effect looks great, and can in general be created by setting the Margin of the control to “-12,0,-12,0”.
Hope this helps.