Rotating Bing Maps

The question of how to “rotate” a Bing Map comes up a surprising number of times on the MSDN Bing Maps forums.

The Bing Maps Silverlight Control has a Heading property, which, according to the documentation: “when overridden in a derived class, gets or sets the directional heading of the map”. However, I certainly can’t get it to have any effect, and it seems I’m not the only one.

image
map.Heading = 0;
image
map.Heading = 180;
(Notice the difference? Nope, me neither.)

The Bing Maps AJAX v7 control also has a heading property, which is described here as “The directional heading of the map. The heading is represented in geometric degrees with 0 or 360 = North, 90 = East, 180 = South, and 270 = West”. What the documentation doesn’t mention is that the heading is only taken into account when using Birdseye view. So, in the examples below you can see four different aspects of Norwich castle in Birdseye view by changing the “heading” to represent north, east, south, and west:

image
map.setView( { heading:0 } );
image
map.setView( { heading:90 } );
image
map.setView( { heading:180 } );
image
map.setView( { heading:270 } );

However, you can choose from these four headings only in Birdseye view. If you’re using the aerial or road map style then the “heading” property, as in the Silverlight control, has no effect.

image
map.setView( { heading:180 } );
image
map.setView( { heading:270 } );

So, how can you create an aerial or road Bing Map with an arbitrary rotation, oriented so that “up” was southwest, or 40°, say?

Rotating the Bing Maps Silverlight control

If you’re using the Silverlight control you can apply a RotateTransform to the Map element. The basic XAML syntax is as follows:

<UserControl x:Class="BingMapsSilverlightRotation.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl">

  <Grid x:Name="LayoutRoot">
    <m:Map CredentialsProvider="{StaticResource MyCredentials}">
      <m:Map.RenderTransform>

        <RotateTransform Angle="15" />

      </m:Map.RenderTransform>
    </m:Map>
  </Grid>
</UserControl>

The map control (and all the elements contained within it) will then be rotated clockwise by the Angle specified in the RotateTransform. The result in this case is:

image

Note that, as for any of the techniques described here, both the background map image and the labels will be rotated. This is unavoidable because the labels are hard-baked into the tile images themselves (though you could of course use one of the unlabelled map styles and then add your own map labels from OpenStreetMap, say).

Rotating the Bing Maps AJAX v7 control

To rotate the Bing Maps AJAX control, you can use the CSS3 transform property. Unfortunately (as is so often the case with web development), there is little standardisation between how different browsers implement the transform feature, and you’ll have to apply a range of variations on the theme to create a cross-browser solution. For example, the CSS styles required to rotate any element by 15 degrees clockwise across different browsers are as follows:

transform:rotate(15deg); /* CSS3 "standard", but not actually used by any mainstream browser! */
-ms-transform:rotate(15deg); /* Internet Explorer */
-moz-transform:rotate(15deg); /* Firefox */
-webkit-transform:rotate(15deg); /* Safari and Chrome */
-o-transform:rotate(15deg); /* Opera */

You can apply these transforms directly onto the div element containing the map. The problem is that, as shown below, this will not only rotate the map image, but also the navbar, scalebar, and copyright notices:

image

To rotate only the map tiles, you need a more specific CSS selector to target those elements that should be rotated. Unfortunately, the various elements of the Bing Map control generally do not have unique IDs or classes, so you have to rely on child selectors. Fortunately, the navbar itself does have a class (MicrosoftNav), so you can ensure this is not rotated by using the not() selector. As at the time of writing, the following CSS selector targets all the divs that contain image tiles in a Bing Maps control created in the “mapDiv” div:

#mapDiv > div.MicrosoftMap > div:not(.MicrosoftNav)

Usual caveats apply – this may break at any time in the future if the Bing Maps control gets updated yada, yada… but right now it works, as demonstrated in the code listing below tested in IE9, Firefox 11 and Chrome 17:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html  xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Bing Maps Rotation</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <style type="text/css">
    #mapDiv > div.MicrosoftMap > div:not(.MicrosoftNav)
    { 
      transform:rotate(15deg);
      -ms-transform:rotate(15deg); /* IE 9 */
      -moz-transform:rotate(15deg); /* Firefox */
      -webkit-transform:rotate(15deg); /* Safari and Chrome */
      -o-transform:rotate(15deg); /* Opera */
    }
  </style>
  <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
  <script type="text/javascript">
    function GetMap() {
      var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
              { credentials: "AtGUpcoIpD5G3ty3r0wnfr!ggingk3yjg779XlZPsKWfhP",
                center: new Microsoft.Maps.Location(54, -4),
                mapTypeId: Microsoft.Maps.MapTypeId.aerial,
                zoom: 4
               });
    }
  </script>
</head>
<body onload="GetMap();">
  <div id="mapDiv" style="position:relative; width:400px; height:300px;" />    
</body>
</html>

Some further examples:

image image
image image
This entry was posted in Bing Maps, Spatial and tagged , , . Bookmark the permalink.