As I write this, we are less than 25 hours away from the moment the first Windows Phone 7 devices are released into the wild – in the Netherlands, that is. The marketplace is filling up nicely already. Some things are pretty obviously missing. And you wonder why, because they would be quite easy to make.
I hereby dare Google to publish a Google Maps application in the Windows Phone 7 Marketplace. Why? Because if they don’t do it, someone else probably will, and probably pretty fast, too. See the screenshot to the left. I assure you – this is no fake. What you see here is the Google Maps satellite layer with the Street layer on top of it, with a 40% opacity, showing a piece of the city center of Amersfoort, Netherlands. It took me about 90 lines of code and 18 lines of XAML.
Setting up a basic Bing Map control is easy as cake. You find the grid “Contentpanel”, and you plonk a Map in it, preferably using Blend:
<Microsoft_Phone_Controls_Maps:Map x:Name="map" CredentialsProvider="your_credentials" Mode="Road"> </Microsoft_Phone_Controls_Maps:Map>
You can change “Road” into “Aerial” and then you have Bing Satellite imagery. What’s less known is that you can actually attach your own tile layers to it. A tile is an image of 256x256 defined by it’s X and Y position in the grid forming the map of the world on a specific zoom level. All you have to to is write a little class that descends from Microsoft.Phone.Controls.Maps.TileSource in which you only have to override the following method:
Uri GetUri(int x, int y, int zoomLevel)
in which you tell which x/y/zoomlevel combination translates to which URI. For Google Maps, this turns out to be pretty easy. All information needed for can be found in the Deep Earth source code – a wee bit adapted for for the Bing Map Control. First, I made an enum that defines all the layers that Google provides
namespace LocalJoost.TileSource
{
public enum GoogleTileSourceType
{
Street,
Hybrid,
Satellite,
Physical,
PhysicalHybrid,
StreetOverlay,
WaterOverlay
}
}
Then, the actual tile calculating class:
using System;
namespace LocalJoost.TileSource
{
public class GoogleTileSource : Microsoft.Phone.Controls.Maps.TileSource
{
public GoogleTileSource()
{
UriFormat = @"http://mt{0}.google.com/vt/lyrs={1}&z={2}&x={3}&y={4}";
TileSourceType = GoogleTileSourceType.Street;
}
private int _servernr;
private char _mapMode;
private int Server
{
get
{
return _servernr = (_servernr + 1) % 4;
}
}
private GoogleTileSourceType _tileSourceType;
public GoogleTileSourceType TileSourceType
{
get { return _tileSourceType; }
set
{
_tileSourceType = value;
_mapMode = TypeToMapMode(value);
}
}
public override Uri GetUri(int x, int y, int zoomLevel)
{
{
if (zoomLevel > 0)
{
var url = string.Format(UriFormat, Server, _mapMode, zoomLevel, x, y);
return new Uri(url);
}
}
return null;
}
private static char TypeToMapMode(GoogleTileSourceType tileSourceType)
{
switch (tileSourceType)
{
case GoogleTileSourceType.Hybrid:
return 'y';
case GoogleTileSourceType.Satellite:
return 's';
case GoogleTileSourceType.Street:
return 'm';
case GoogleTileSourceType.Physical:
return 't';
case GoogleTileSourceType.PhysicalHybrid:
return 'p';
case GoogleTileSourceType.StreetOverlay:
return 'h';
case GoogleTileSourceType.WaterOverlay:
return 'r';
} return ' ';
}
}
}
As you can see, this is not quite rocket science. To make the Bing Maps control use this, you need to expand your XAML a little. First, you have to add two namespaces to your MainPage.Xaml:
xmlns:MSPCMCore="clr-namespace:Microsoft.Phone.Controls.Maps.Core;assembly=Microsoft.Phone.Controls.Maps" xmlns:LJTileSources="clr-namespace:LocalJoost.TileSource;assembly=LocalJoost.TileSource"
Then, you have to use a third mode for the Bing Map – Mercator. This basically only tells the map to operate in Mercator mode, but not to attach any default imagery. And here we go:
<Microsoft_Phone_Controls_Maps:Map x:Name="map" CredentialsProvider="your credentials" > <Microsoft_Phone_Controls_Maps:Map.Mode> <MSPCMCore:MercatorMode></MSPCMCore:MercatorMode> </Microsoft_Phone_Controls_Maps:Map.Mode> <Microsoft_Phone_Controls_Maps:Map.Children> <Microsoft_Phone_Controls_Maps:MapTileLayer> <Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources> <LJTileSources:GoogleTileSource TileSourceType="Satellite"/> </Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources> </Microsoft_Phone_Controls_Maps:MapTileLayer> </Microsoft_Phone_Controls_Maps:Map.Children> </Microsoft_Phone_Controls_Maps:Map>Presto. Google Maps for Windows Phone 7. And oh, if you want to project another layer on top of it, for instance Google Streets, like I did, you just add more tilelayers:
<Microsoft_Phone_Controls_Maps:Map x:Name="map" CredentialsProvider="your credentials" > <Microsoft_Phone_Controls_Maps:Map.Mode> <MSPCMCore:MercatorMode></MSPCMCore:MercatorMode> </Microsoft_Phone_Controls_Maps:Map.Mode> <Microsoft_Phone_Controls_Maps:Map.Children> <Microsoft_Phone_Controls_Maps:MapTileLayer> <Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources> <LJTileSources:GoogleTileSource TileSourceType="Satellite"/> </Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources> </Microsoft_Phone_Controls_Maps:MapTileLayer> <Microsoft_Phone_Controls_Maps:MapTileLayer> <Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources> <LJTileSources:GoogleTileSource TileSourceType="Street"/> </Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources> </Microsoft_Phone_Controls_Maps:MapTileLayer> </Microsoft_Phone_Controls_Maps:Map.Children> </Microsoft_Phone_Controls_Maps:Map>
The Bing Maps control makes you able to zoom and pan trough all this. Okay, Google Maps does a little more than this, but this shows pretty well how darn easy it is to make a good looking, pretty fully functional mapping application showing totally different imagery.
Conclusion: using the Bing Maps Control for showing raster maps is so bloody easy that I almost start to wonder if it’s still justified to feel proud ‘being a GIS guy’. Almost ;-)
19 comments:
*Great* post.
So... Bing Maps control as a ready map slippy map, huh? (Or I possibly misread this article; I'm hacking a bit of WP7 myself while watching some TV...)
If so it should be much easier than I thought to be able to use Open Street Map tiles in a WP7 application: just the right x/y/zoom to tile URL map.
Cool!
Interesting solution. What does the Google Maps API terms of service say about using it in this manner? :)
@nzben I am pretty sure the Google TOS does not allow this. But now it's so easy now use their data in a Silverlight/Windows Phone 7 app they better start doing something or else someone ELSE will make Google Maps for Windows Phone 7. Possibly me ;-)
@peSHir using OpenStreetMaps is just as easy. Maybe I'll get around to post code for that as well, have it around somewhere, just needs a little adaptation for the Bing Map Control. I thought using Google Maps a bit more spectacular ;-)
Great that you are mentioneed on wpcentral.com.
Signed up for an account there to comment on the article by Daniel Rubino (well, his footnote), but I still can't seem to log on. So I'll just dump that here for now if you don't mind?
I'm curious; is there anything in the Bing maps control that gives T&Cs fro what map data you can use it to consume?
Here is another requestto use OpenStreetMap in the Bing Maps control :) Especially since Bing is using OpenStreetMap itself.
can you please tell me how could i place a layer having routes from Google map
@naveed First of all, the control I am using is BING maps, it only loads data from Google - courtesy of the flexibility Microsoft built into the control. Second - you could easily add a second raster layer with route data - if you have the backend power to generate something like that. If you have not, you will have to go into vector layers. I am still looking into that one myself. The hard part is getting the data. If you have an API somewhere that can give you a string of lat/lon waypoints as return value, then showing a route on top of the map is pretty easy. I will blog about that some day.
And another use of the Bing Maps controls: Google Sky tile source example at http://www.scottlogic.co.uk/blog/colin/2011/02/google-sky-on-windows-phone-7
i understand how 2 use the map but how can i request to begin in a certin coordinate?
when i ask for it it keeps sending me to the same location with no regard to what coordinates i give it
when i use the line:
UriFormat = @"http://maps.google.com/maps/api/staticmap?center={0:0.000000},{1:0.000000}&zoom={2}&size=1000x1000&sensor=false";
instead of using the original u gave with your code for some reason instead of giving me the map i need it shows me 4 copys of the same map i requested
any idea of how i can solve this?
@meir Like you said yourself - you use the static Google API. I don't do that, and I have no idea how that static api works.
Great work! You saved me a lot of time. :)
nice info..
by the way, can we add pushpin like in bing maps? can you give example..
How do I modify this to return my own map tiles located in local storage? thanks.
@hybriddriver I wish I new. I know it can be done.
This is against the Bing Maps and Google Maps terms of use. Any application found to use Google Maps in a Bing Maps control will be removed from the Windows Phone Marketplace.
@rbrundritt Correct! This is ment to be a challenge to Google. They did not respond. In the mean time, you can find various apps in the Windows Phone Marketplace showing Google Maps tiles. Now I wonder where they find the code to do that ;-)
Post a Comment