Quantcast
Channel: Maps Blog
Viewing all 102 articles
Browse latest View live

ESRI Shapefiles and Bing Maps WPF

$
0
0

In last week’s blog posts I talked about several different ways of overlaying ESRI shapefile data onto Bing Maps. In this post, I will walk through how to develop a simple application for loading a locally store shapefile onto the Bing Maps WPF control using the ESRI Shapefile Reader CodePlex project.

Creating the project

First, you will need to download the ESRI Shapefile Reader project. Once this completes, you can unzip and run the Visual Studio project. You will notice there are two libraries in the project. The first is called Catfood.Shapefile; this is the main library that has the logic for reading and parsing Shapefiles. The second is just a basic application for reading some metadata from a shapefile. We are really only interested in the first project.

Open up Visual Studios and create a new WPF application call BingMapsShapefileViewer. Next, right click on the solution and add an Existing project. Locate and add the Catfood.Shapefile project. Next, right click on the References folder of the BingMapsShapefileViewer project and add a reference to the Catfood.Shapefile project. Your solution should look like this:

ESRI solution image

Adding the Map

Adding a map to the WPF control is pretty straight forward. You will first need to add a reference to the WPF Map control library (Microsoft.Maps.MapControl.WPF.dll), which is usually located in the C:\Program Files (x86)\Bing Maps WPF Control\V1\Libraries directory.

Now that you have a reference to the map control in your project we can go ahead and add a map in the xaml of the MainWindow.xaml file. While we’re at it, let’s add a MapLayer for the shapefile data as a child of the map control and add two buttons: one to load in a shapefile and another to clear the map. Your xaml should look like this:

<Window x:Class="BingMapsShapefileViewer.MainWindow"

        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.WPF;assembly=Microsoft.Maps.MapControl.WPF"

        Title="MainWindow" Height="350" Width="525">

    <Grid>

        <m:Map Name="MyMap" CredentialsProvider="YOUR_BING_MAPS_KEY">

            <m:Map.Children>

                <m:MapLayer Name="ShapeLayer"/>

            </m:Map.Children>

        </m:Map>

 

        <StackPanel HorizontalAlignment="Right">

            <Button Content="Load Shapefile" Click="LoadShapefile_Clicked"/>

            <Button Content="Clear Map" Click="ClearMap_Clicked"/>

        </StackPanel>

    </Grid>

</Window>

 

If you build the project you should see a map with two buttons on it like this:

ESRI map with buttons

Reading a Shapefile

Now that we have our base application created we can add the logic to read in a shapefile when a user clicks the “Load Shapefile” button. To keep things easy we will only support shapefiles that are in the proper projection, WGS84, as re-projecting the data would make this much more complex and best covered in a future blog post.

We will use an OpenFileDialog to allow us to easily select the shapefile we wish to load to the map. Once a file is selected we can pass the file path into the Shapefile class from our Shapefile Reader library. Your code will look like this:

privatevoid LoadShapefile_Clicked(object sender, RoutedEventArgs e)

{

    ShapeLayer.Children.Clear();

 

    OpenFileDialog dialog = newOpenFileDialog();

    dialog.Title = "Select an ESRI Shapefile";

    dialog.Filter = "ESRI Shapefile (*.shp) |*.shp;";

 

    bool? valid = dialog.ShowDialog();

 

    if (valid.HasValue && valid.Value)

    {

        using (Shapefile shapefile = newShapefile(dialog.FileName))

        {

            //Logic to Process Shapefile

        }

    }

}

 

You can now loop through each shape in the shapefile and convert each shape in the shapefile into a Bing Maps shape and then add it to the map. When this is all put together, we end up with the complete source code for the MainWindow.xaml.cs file.

using System.Windows;

using System.Windows.Media;

using Catfood.Shapefile;

using Microsoft.Maps.MapControl.WPF;

using Microsoft.Win32;

 

namespace BingMapsShapefileViewer

{

    ///<summary>

    /// Interaction logic for MainWindow.xaml

    ///</summary>

    publicpartialclassMainWindow : Window

    {

        #region Constructor

 

        public MainWindow()

        {

            InitializeComponent();

        }

 

        #endregion

 

        #region Private Methods

 

        privatevoid LoadShapefile_Clicked(object sender, RoutedEventArgs e)

        {

            ShapeLayer.Children.Clear();

 

            OpenFileDialog dialog = newOpenFileDialog();

            dialog.Title = "Select an ESRI Shapefile";

            dialog.Filter = "ESRI Shapefile (*.shp) |*.shp;";

           

            bool? valid = dialog.ShowDialog();

 

            if (valid.HasValue && valid.Value)

            {

                using (Shapefile shapefile = newShapefile(dialog.FileName))

                {

                    //Set the map view for the data set

                    MyMap.SetView(RectangleDToLocationRect(shapefile.BoundingBox));

 

                    foreach (Shape s in shapefile)

                    {

                        RenderShapeOnLayer(s, ShapeLayer);

                    }                                      

                }

            }

        }

 

        privatevoid ClearMap_Clicked(object sender, RoutedEventArgs e)

        {

            ShapeLayer.Children.Clear();

        }

 

        #region Helper Methods

 

        privateLocationRect RectangleDToLocationRect(RectangleD bBox)

        {

            returnnewLocationRect(bBox.Top, bBox.Left, bBox.Bottom, bBox.Right);

        }

 

        privatevoid RenderShapeOnLayer(Shape shape, MapLayer layer)

        {

            switch (shape.Type)

            {

                caseShapeType.Point:

                    ShapePoint point = shape asShapePoint;

                    layer.Children.Add(newPushpin()

                    {

                        Location = newLocation(point.Point.Y, point.Point.X)

                    });

                    break;

                caseShapeType.PolyLine:

                    ShapePolyLine polyline = shape asShapePolyLine;

                    for (int i = 0; i < polyline.Parts.Count; i++)

                    {

                        layer.Children.Add(newMapPolyline()

                        {

                            Locations = PointDArrayToLocationCollection(polyline.Parts[i]),

                            Stroke = newSolidColorBrush(Color.FromArgb(150, 255, 0, 0))

                        });

                    }

                    break;

                caseShapeType.Polygon:

                    ShapePolygon polygon = shape asShapePolygon;

                    if (polygon.Parts.Count > 0)

                    {

                        //Only render the exterior ring of polygons for now.

                        for (int i = 0; i < polygon.Parts.Count; i++)

                        {

                            //Note that the exterior rings in a ShapePolygon have a Clockwise order

                            if (!IsCCW(polygon.Parts[i]))

                            {

                                layer.Children.Add(newMapPolygon()

                                {

                                    Locations = PointDArrayToLocationCollection(polygon.Parts[i]),

                                    Fill = newSolidColorBrush(Color.FromArgb(150, 0, 0, 255)),

                                    Stroke = newSolidColorBrush(Color.FromArgb(150, 255, 0, 0))

                                });

                            }

                        }

                    }

                    break;

                caseShapeType.MultiPoint:

                    ShapeMultiPoint multiPoint = shape asShapeMultiPoint;

                    for (int i = 0; i < multiPoint.Points.Length; i++)

                    {

                        layer.Children.Add(newPushpin()

                        {

                            Location = newLocation(multiPoint.Points[i].Y, multiPoint.Points[i].X)

                        });

                    }

                    break;

                default:

                    break;

            }

        }

 

        privateLocationCollection PointDArrayToLocationCollection(PointD[] points)

        {

            LocationCollection locations = newLocationCollection();

            int numPoints = points.Length;

            for (int i = 0; i < numPoints; i++)

            {

                locations.Add(newLocation(points[i].Y, points[i].X));

            }

            return locations;

        }

 

        ///<summary>

        /// Determines if the coordinates in an array are in a counter clockwise order.

        ///</summary>

        ///<returns>A boolean indicating if the coordinates are in a counter clockwise order</returns>

        publicbool IsCCW(PointD[] points)

        {

            int count = points.Length;

 

            PointD coordinate = points[0];

            int index1 = 0;

 

            for (int i = 1; i < count; i++)

            {

                PointD coordinate2 = points[i];

                if (coordinate2.Y > coordinate.Y)

                {

                    coordinate = coordinate2;

                    index1 = i;

                }

            }

 

            int num4 = index1 - 1;

 

            if (num4 < 0)

            {

                num4 = count - 2;

            }

 

            int num5 = index1 + 1;

 

            if (num5 >= count)

            {

                num5 = 1;

            }

 

            PointD coordinate3 = points[num4];

            PointD coordinate4 = points[num5];

 

            double num6 = ((coordinate4.X - coordinate.X) * (coordinate3.Y - coordinate.Y)) -

                ((coordinate4.Y - coordinate.Y) * (coordinate3.X - coordinate.X));

 

            if (num6 == 0.0)

            {

                return (coordinate3.X > coordinate4.X);

            }

 

            return (num6 > 0.0);

        }

 

        #endregion

 

        #endregion

    }

}


Here are a few screen shots of the application loading in some different shapefiles.

Example of all the interstate highways in the USA:

ESRI map with HWY bounds

Example with county boundaries being rendered:

ESRI map with country bounds

Getting Data

Here are a couple of good sources for ESRI Shapefiles to test with:

*Note: this data is in OSGB36 projection and need to be re-projected before being used with Bing Maps. These can easily be re-projected using a free tool is called the Geospatial Data Abstraction Library. Here is a quick example of the command needed for converting these files to WGs84 projection:

ogr2ogr -s_srs EPSG:27700 -t_srs EPSG:4326 outputFileInWGS84.shp inputFileInOSGB36.shp

- Ricky Brundritt, EMEA Bing Maps Technology Solution Professional


Golden Spike Event: Team Photo

$
0
0

To celebrate the US completion of the Global Ortho project, the team flew one last commemorative mission which we've called our “Golden Spike” flight. Check out the full post: Global Ortho & 17 Million SqKm of New Satellite Imagery.

golden spike numbered (550)

1

Brad Clark

2

Mike Gilbert

3

Robert Waterman

4

Jeff Collins

5

David Buckner

6

Bill Evans

7

Rob Ledner

8

Chris Simison

9

Kim Wasilewski

10

Jill Downing

11

Jason Szabo

12

Scott Short

13

Michael Harrell

14

Marcus Eisen

15

Joel Snow

16

Ryan Tracy

17

Tom Barclay

18

Cody Keawe Yancey

19

Amit Dekate

20

James Undery

21

Taehun Yoon

22

Aaron Rogan

23

Brian Wahlert

24

Anthony Thorpe

25

Yuxiang Liu

26

Jos Dijkstra

28

Jesse Wright

29

Gabor Papp

30

Mike Voelkelt

30

Mike Voelkelt

32

Wimm Vadakan

33

Jerry (Zhiyuan) Zhao

34

Christian Ameling

35

Amber Britton

36

George Robinson

37

Stephen Shiller

38

Mark Barkmeier

39

Said Parirokh

40

Jeremy Dunn

41

Tim Mohatt

42

Charlie Peterson

43

Nathan Kling

44

Steve Stanzel

45

Peter Zhang

46

Cody Kline

47

Khom Kaowthumrong

48

Kartik Muktinutalapati

49

Maksim Lepikhin

50

Chris Lesher

51

Keith Seifert

52

David Wendt

53

Ricky Walker

54

Sunlight Yang

55

Zhaoqiang Bi

56

Wolfgang Schickler

57

Steve Schroeder

58

Thaxton Beesley

59

Raj Bakam

60

Jason Setzer

62

Kristian Kerr

63

Wendy Luck

64

Nathan Conwell

65

Jerry Skaw

66

Eric Yeisley

67

Danielle Russell

68

Michael Hester

69

Carmen Jacobe

70

Erik Bostrom

71

Carolyn Peterson

72

Michael Wright

73

Adam Satushek

74

Ken Potter

75

Allison Lohne

76

Leon Rosenshein

77

Richard Ashe

78

Vladimir Lyapunov

79

Jake Zmrhal

80

Trent Youngwirth

81

Joyce Snowden

82

Sean Quinn

83

Chris Messer

84

David Parter

85

Benjamin Kadlec

86

Carl Smith

87

Adam Wilbur

88

Erik Kressner

Global Ortho & 17 Million SqKm of New Satellite Imagery

$
0
0

In a recent post, we announced the completion of the Global Ortho (GO) program in the United States.  GO for Western Europe is on schedule to be completed by the end of CY 2012.

Also new this month, Bing Maps adds nearly 17 Million SqKm of new satellite imagery!

Global Ortho

New Satellite Imagery

Boulder, Colorado - See it Live!

Paparahandi, India - See it Live!

1 indiaP

Go to the corners of the Earth, including Paparahandi, India in a click of a button with the help of Bing Maps new satellite imagery!

As part of the Global Ortho project, BITs has acquired 100% of the USA

We've wrapped up the Global Ortho project for the US with the release of 800,133 SqKm! Be sure to check out  our imagery commemorating this exciting milestone.

3

There are two places where we could not collect photos: Area 51 and the Vandenberg Air Force Base. However, the United States allowed the Global Ortho aircraft everywhere else, and Microsoft captured astonishing imagery. Visit Bing Maps World Tour App to view full coverage.

After two years of acquiring imagery, the Bing Imagery Technology  (BITs) team is excited to reveal the completion of aerial coverage in the U.S.A. That means every square inch of the continental U.S.A. has been photographed, bringing Bing Maps consistent quality and high resolution imagery.

Davis-Monthan AFB
Tucson, Arizona

Red Rocks Amphitheatre
Morrison, Colorado

clip_image002[5]

Red Rocks Amphitheatre Morrison, CO

DSC Logistics Park
Berkeley, Illinois

Microsoft Campus
Redmond, Washington

clip_image005[1]

clip_image006[1]

MORE HIGHLIGHTS:

This imagery was collected at a 30cm resolution (1 foot = 1 pixel). While many areas of the country have been photographed at higher resolution, Bing Maps covered the entire country at this high resolution.  Some parts of the United States have never before been aerially photographed in such detail! This photography project yielded a staggering amount of data.  To get a sense of the size, imagine lining up all the GO pixels end to end. So laid out, those pixels would reach around the earth 994 times, to the moon 104 times, and all the way to Venus (with an extra trillion pixels to spare.)

Here are a few news clips of the Bing Maps Global Ortho project:

BITs Golden Spike Event: Time to Celebrate!

8

See the Golden Spike Event Team Photo blog post for a list of the individuals in the Bing Maps Global Ortho Golden Spike photo.

To celebrate the US completion, the team flew one last commemorative mission which we've called our “Golden Spike” flight. Golden Spike hearkens back to the spike that was driven to commemorate the joining of the first transcontinental railroad in the U.S. For our Golden Spike celebrating the largest aerial photography project ever undertaken, Bing Maps invited local Colorado chalk artist Jennifer Mosquera to create the biggest Bing logo ever made!  At over 200’ by 90’, the logo may indeed be the biggest Bing ever.  As luck would have it, the ideal spot for the logo in the Golden Spike flight was the top of the parking garage just north of the Bing Maps Imagery Team’s building in downtown Boulder, CO.

The BITs team made two videos of the Golden spike event.  The first video documents the artists making the biggest Bing ever, and the second video narrates the day of the final Global Ortho flight.

Video 1: Microsoft Bing Maps - Global Ortho Golden Spike - Logo Creation (5:41)

Video 2:  Bing Maps Global Ortho Golden Spike - Day of the Flight (3:48)

Brand New Imagery over Manhattan!

We’ve acquired new 15cm imagery over Manhattan including a view of the Space Shuttle Enterprise. The Enterprise was the first Space Shuttle Orbiter built for NASA and now resides at the Intrepid Sea, Air and Space Museum.

Intrepid Sea, Air & Space Museum
Manhattan, New York, USA

9

MORE NY ATTRACTIONS:

BITS Publishes New Satellite Imagery to Bing Maps!

The BITs team is pleased to announce a new publication of satellite imagery totaling 85 terabytes and covering nearly 17 million SqKm (16,915,916 SqKm, to be exact!)

Faulkland Island Burning
Off the coast of South America

Al Mazyunah
Oman

10

11

Farm Circles
Saudi Arabia

San Cristobal
Nicaragua

12

13

MORE HIGHLIGHTS:

We've updated coverage across the globe. South America, southern Asia, Africa, and Australia make up the largest amount of this month's release. Check out Mexico, Russia, and Canada for additional updated imagery!

14

Total coverage of new satellite imagery currently live on Bing Maps! Visit Bing Maps World Tour App to view full coverage.

eXtremeCRM 2012 Conference & Bing Maps

$
0
0

Calling all partners!! Who’s plugged in to Dynamics CRM & Bing Maps?

For those of you that are new to the CRM space, the eXtremeCRM Conferenceis the hub where Microsoft Dynamics CRM partners come together to forge business relationships, gain knowledge from real-world experiences and dive deep into current and future technologies.  This year’s conference will be in Las Vegas (Sept 30 – Oct 3) and we’re really excited to have Geoff Innis, a Bing Maps Technical Specialist, present a session on visualizing Dynamics CRM data in Bing Maps.

The visualization of business data using Bing Maps enables deeper business insights to enhance productivity and optimize business decisions. This session will provide a deep-dive code review of the integration of Bing Maps into Dynamics CRM via Web Resources and the Dynamics CRM REST endpoint, and will cover scenarios such as field visit planning and optimization, and heat-mapping and thematic mapping of CRM entity data for trend visualization and decision making.

 

Session Details:


Deeper View: Visualizing Dynamics CRM data in Bing Maps through Web Resources

Date: Tuesday, October 2nd 2012

Time: 1:30p - 3:00p

E111

Extend Track

Level 300

Viewing Census Data on Bing Maps

$
0
0

CensusLogoEvery ten years the US Bureau of the Census counts the people in the US and collects a number of other household metrics. The last census was compiled in 2010 and the Census Bureau sent hundreds of thousands of people door to door to count the population. The Census Bureau makes this data available but to ensure the privacy of individuals it groups this data into census blocks.

Census data can be extremely useful in business. Being able to visualize demographic data on a map is something that many companies do within their business intelligence tools. This gives them insight into areas such as income, population, race, even the types of industry people work in. This kind of information can prove vital when trying to research new sales regions or putting together targeted marketing campaigns. Another interesting use for this data is to compare the census data to the election polls.

As I mentioned before the Census Bureau makes this data available to the public. One of the most commonly used data is the boundaries information. This information traditionally has been made available in Tiger format but in recent years has been made available in more common formats such as ESRI Shapefile and KML format. In addition to the boundary data there is tons of demographic data that is related to each boundary. Needless to say there is a massive amount of data available from the Census Bureau; there is several gigabytes worth of data in boundary information alone.

With the elections around the corner one common site used by those who follow the elections is Ballotpedia. This site has made use of CensusViewer to provide voter data for the Congressional districts of New York. These publicly accessible maps show registered voter counts inside of Bing Maps. Visitors can zoom in on any area of the state and compare old and new districts projected on the map. Check it out for yourself here; NY US Congress: Census 2001, Census 2011; NY State Senate: Census 2001, Census 2011; NY State House: Census 2001, Census 2011. Here is a screen shot of the NY State Senate data from 2001.

CensusViewer2

What is CensusViewer?

CensusViewer is an online application built by Moonshadow Mobile. This application gives you access to the 2010 and 2000 Census “Summary File 1” data from the U.S. Census Bureau as well as the selected American Community Survey (ACS) data and extensive data including registered voters and frequently updated commercial data sources. It is an excellent online tool for demographic analysis of the U.S. population. With CensusViewer you can navigate the census data from within the familiar Bing Maps interface coupled with Moonshadow’s cutting-edge database technology, to provide an intuitive platform for accessing and analyzing the data. Now, there are a couple different versions which give you access to different levels of data. If you want to try it out yourself, you’re in luck because there’s a free version. Here is a heat map created using this tool of the US population that is at or below the poverty level.

CensusViewer

Integration with Bing Maps

Integrating census data with Bing Maps is something that I come across on a fairly regular basis. One common issue many developers come across is that the boundary data and the demographic data are two separate data sets. It’s up to the developer to connect the two. This isn’t overly difficult as there are census track ID’s that tie everything together, but the real issue comes with figuring out how to link the data programmatically.

So how do we do it? Using the data in KML format may be tempting as it is in an easy human readable format. However, a single KML file that has the boundaries for a single county in the US is roughly 3MB in size. If you try loading in the entire boundary dataset as KML format it won’t take long before you run into performance issues. In addition to this you would have to write a lot of code to link the demographic data to the boundary information. All of this can be done but there is a much better way.

I personally prefer working with the ESRI Shapefiles over KML. One big benefit is that it’s rather easy to upload an ESRI Shapefile into SQL Server as I described in a recent blog post. Once this data is in SQL Server linking it up with the demographic data is rather simple due to the relational nature of SQL. Once you have the data in SQL Server you are half way to visualizing it on a map. In fact if you want to quickly view this data you can simply do queries inside of SQL Management studio to see what it looks like without a map. You can take it a step further and install SQL Report Builder which can easily overlay your spatial data on top of a static Bing Maps image. Note that SQL Server 2008, 2012 and Azure all support spatial data.

Being able to see the data in SQL Reports is a good start but let’s be honest, we want view it using an interactive map. There is a couple of ways to go about this. One method is to create a web service for exposing your data to your map. This method works well with small data sets but not so much for larger data sets. Ideally you don’t want your users having to download all the census data to their maps. This would not make for a very good user experience and would likely be too much data for the browser. One option is to make use of the spatial tools in SQL Server and reduce the resolution of the data based on zoom level. This method can significantly reduce the size of the data while keeping the data interactive.

Another approach is to convert your spatial data into an image and overlay that on the map. Using this approach the user only has to download a small image which will make for fast loading on the map. This drastically improves performance. Now you might be thinking “how do you interact with the data if it’s an image?” Well you can add a click event to the map and when the user clicks the map, send the coordinates through a web service to your database and query any data that intersects with your coordinates. This is a rather simple query with the spatial tools in SQL Server. You can then return the data and represent to the user. I have had great success using this approach in a number of projects.

So how do you turn your data into an image? Well I actually wrote a blog posts on this topic in the past. Since then one of our Bing Maps partners, OnTerra, has create an open source project called AJAX Map DataConnector. This tool uses the MVC framework to expose spatial data in SQL Server to the Bing Maps AJAX control. In addition to this it also has several common spatial queries built into it and the ability to render the data on the map as either interactive data or as an image. This tool is a great place to start if you want to develop something yourself. OnTerra also has a commercially supported version of this tool called GeoSavvy.

GeoSavvy

Now so far all of these solutions require you to manage the data and do some development. What if you just want to visualize the data on Bing Maps without all the hassle of developing an application? Well CensusViewer is the solution for you!

Bing Maps Platform Webcast Series for Fall 2012

$
0
0

Who’s in for some free geospatial insight?! Learn how your organization can take advantage of Bing Maps to enhance your line of business solutions and provide a deeper insight into your business data.

Up next…

Bing Maps Platform in the Enterprise: Experience the Value (EPG339CAL)

In this session, Mark and Kevin will talk through solutions that integrate Bing Maps to help organizations plan their resources, take advantage of best opportunities, make smarter operational decisions that enhance efficiency, and lower costs. You’ll learn what’s included in the Bing maps platform, and how to best take advantage of the data services & imagery and incorporate them into line of business operations within your organization. We will explore the development options with the platform and how to get you started developing.

Date/Time:Thu Oct 4, 2012, 11:00 AM, USA Pacific
Duration:1 Hour
Presenters:Mark Merchant, Bing Maps Technical Solution Professional
 Kevin Adler, Enterprise Geospatial Business Manager

Bing Maps for Windows Store App JavaScript Development (EPG341CAL)

In this webcast we will take a look at the tools available for developing Bing Maps for Windows Store Apps using JavaScript. We will go through the complete process from start to finish on adding Bing Maps to your App. We will also take a look at some migration tips for those who have existing applications developed on the Bing Maps V7 AJAX Web control.

Date/Time:Tue Oct 16, 2012, 8:00 AM, USA Pacific
Duration:1 Hour
Presenters:
Ricky Brundritt, EMEA Bing Maps Technology Solution Professional

Native Bing Maps for Windows Store App Development (EPG342CAL)

In this webcast we will take a look at the tools available for developing Bing Maps for Windows Store Apps using Native code (C#, VB, C++). We will go through the complete process from start to finish on adding Bing Maps to your App. We will also take a look at how to tie into the Location Services in Windows 8 and also how to access the Bing Maps REST services from code.

Date/Time:Tue Nov 6, 2012, 8:00 AM, USA Pacific
Duration:1 Hour
Presenters:
Ricky Brundritt, EMEA Bing Maps Technology Solution Professional

Microsoft's Geospatial Tool Kit – Bing Maps & SQL Server (EPG340CAL)

Attend this session to learn how Microsoft’s geospatial tools enable customers to save money and resources over traditionally “heavy” GIS systems. Creating, maintaining and displaying geospatial data has never been simpler…and we’ll show you how to do this with the software that you may already own or readily have access to. Regardless of if you’re building with SQL Server or SQL Azure, maintaining your data in an easy to manage toolset is fast and it easily scales. Combined with the Bing Maps Platform, displaying your points, lines and polygons to your users - regardless if it’s 1 or 10 million - just works! While all are invited to attend, this webcast will focus more on the development aspect of Bing Maps when combined with SQL Server.

Date/Time:Tue Nov 13, 2012, 11:00 AM, USA Pacific
Duration:1 Hour
Presenters:Mark Merchant, Bing Maps Technical Solution Professional
 Kevin Adler, Enterprise Geospatial Business Manager

“Carmaggedon II”: Bing Maps is Your Ben Affleck

$
0
0

I was pinged late yesterday by the Los Angeles County Metropolitan Transportation Authority about this whole “Carmaggedon” nightmare going on in LA this weekend. Being a SoCal native, I empathized with just how horrible this is going to be. Seriously…horrible. Meanwhile, in Seattle, I’m smiling since I don’t have to deal with it; but, that’s neither here nor there. I digress. Empathy reigned and I reached out to my Bing Maps Dev team to see what it would take to create a road closure and detour to guide my long, Lost Angels through the weekend. And, just like that I’m happy to say that Bing Maps is now able to provide routing guidance around the Carmaggedon II. Yay!

Carmaggedon

Notice the route on the left routes you on 405, whereas the route on the right routes you down Sepulveda. You’ll need to select the “View Route Based on Traffic” feature (default on Windows Phone). Our route around solutions will last through the weekend while the freeway is closed.

^CP

Bing Maps SDKs for Windows Store Apps Now Available

$
0
0

Windows8ControlsToday we are announcing the availability of the Bing Maps SDKs for Windows Store apps. These SDKs will allow you to bring the power of Bing Maps to your Windows Store apps with support for C#, C++, Visual Basic and JavaScript based applications.

Please be aware that this release is the only version (1.1.20120927.0) of Bing Maps which will be supported for apps submitted to the Windows Store. If you are running any prior version (or BETA) you must upgrade and rebuild your app with this build to pass the Windows app Certification Kit (WACK) process. This process is required to submit all apps to the store and checks for the latest version of all dependencies to be approved. In most cases this should be as easy as downloading the latest version of the Bing Maps for Windows Store Apps API and recompiling your app.

Depending on the type of application you want to build and how you intend to use maps, we offer two options:

Bing Maps for JavaScript

For those of you familiar with our AJAX web control, building apps with the JavaScript SDK should be a snap. There are a few differences in how you load modules locally and some restrictions in certain markets but otherwise it has the same features and functionality as its web counterpart. With some tweaks, you should be able to port over your existing web experience using maps into the Windows Store and its rapidly growing user base.

If you’re new to Bing Maps, you can head over to our iSDK site which allows you to test drive the APIs and get a feel for how the web control works for Windows Store apps as well.

Bing Maps for C#, C++, and Visual Basic

Our ‘Native’ SDK is our first SDK specifically targeting application developers that takes advantage of the Windows Application Store environment. In this release, we provide the basic functionality to get maps integrated into your app. Specific to this version; we added support for pushpins/polylines/polygons, landmarks, venue maps, traffic and Synth view map style. You can still use the Bing Maps REST services to add additional functionality such as search and driving directions. And with our own client renderer, the SDK takes advantage of the Windows 8 platform to provide an amazingly smooth and responsive map experience on x86, x64 or ARM platforms.

New Keys and Terms of Use

Along with this release, we have created a new Bing Maps key type called ‘Windows Store app.’ You should use this key type when building new apps with the Bing Maps for Windows Store Apps API. You can get a new Bing Maps key over at our Bing Maps Account Center. If you created a ‘Windows Metro style app (BETA)’ key that was converted to a Windows Store app Trial key, your key will expire on Jan 15th, 2013 If you already have a non-trial ‘Windows Metro style app’ key, these will automatically be switched over to the new name. Keep in mind that all Trial Windows Store App Keys created after July 26th 2012 are hardcoded and will expire after 90 days. If your application meets the requirements for limited free use (please read our governing TOU), you should get a Basic Windows Store App Key. Check out Chris Pendleton’s blog about the new Bing Maps key changes. While most applications using the Windows Store app environment will use the new basic key for Windows App Store an Enterprise key will be required if you’re building an app that is not available to consumers or doesn’t meet the requirements for limited free use. An Enterprise key also requires a valid separately executed Bing Maps agreement – please read through our TOU for more information.

Links

Below are some useful links to get more information and provide feedback:

Jamie Lang
Senior Program Manager
Microsoft Corporation : Bing Map Controls


Getting started with Bing Maps Windows Store Apps (JavaScript)

$
0
0

If you follow this blog regularly, there is a strong chance that you are familiar with Bing Maps and all the greatness it brings to the web. And, with Windows 8, you can add that same greatness directly into your applications using the Bing Maps Windows Store App controls. When developing with the Bing Maps Windows Store App control, you have the option of using JavaScript or Native code (C#, VB or C++). The Bing Maps Windows Store App JavaScript control is based on the Bing Maps V7 AJAX web control. This is an excellent control with a large array of features. In addition to this, there are a ton of resources from the Bing Maps V7 control that can be used with the Bing Maps Windows Store App JavaScript control. However, as close as these two map controls may be, there are some slight differences; so don’t assume you will have 100% parity between the two.

In this blog post, we are going to look at how to create a simple application by using the Bing Maps Windows Store App JavaScript control while using the location services available in Windows 8. In addition to this, we will also take a look at testing our app on another device that doesn’t have Visual Studios installed.

Setting up your development environment

To get started developing a Bing Maps Windows Store application you will need the following installed:

You will also need a Bing Maps account and key. If you intend to create a non-trial application, you should create a Basic key for your Windows Store App and read the governing TOU that defines your usage limits.

Setting up the project

To set up the project, open Visual Studios 2012 and create a new project. In the window that opens, select JavaScript -> Windows Store. Select the Blank App template, call the application BingMapsJSIntro and press OK.

image

A simple project will be created and contain a web page called default.html along with folders for JavaScript, CSS, and image files. The default.js file contains the logic for handing the different states of the application. Windows Store applications have three states: not running, running, and suspended. When the state changes, an event is fired, triggering the code in this file. We will not worry about handling the different states in this blog post, but it is good to take note of it as it will become useful later.

We could append the code we need for the map to this file but instead, we will keep things clean and create a separate JavaScript file for our code. To do this, right click on the js folder and select Add -> New Item. Create a new JavaScript file called bingMapsIntro.js. At this point, your Solution should look something like this:

image

Adding Bing Maps to the App

To get started, we will need to add a reference to the Bing Maps JavaScript library. First, right click on the References folder and press Add Reference. Select Windows -> Extensions, and then select Bing Maps for JavaScript. If you do not see this option, be sure to verify that you have installed the Bing Maps SDK for Windows 8 style apps.

image

Now, open the default.html file. You should see some references to all the CSS and JavaScript files already there. At this point, wherever we plan to put our Bing Maps code, we will need to add references to the Bing Maps SDK and the JavaScript file. We will also need to add a div for where we want the Bing Maps control to be loaded.

<!DOCTYPEhtml>

<html>

<head>

    <metacharset="utf-8"/>

    <title>BingMapsJSIntro</title>

 

    <!-- WinJS references -->

    <linkhref="//Microsoft.WinJS.1.0/css/ui-dark.css"rel="stylesheet"/>

    <scriptsrc="//Microsoft.WinJS.1.0/js/base.js"></script>

    <scriptsrc="//Microsoft.WinJS.1.0/js/ui.js"></script>

 

    <!-- BingMapsJSIntro references -->

    <linkhref="/css/default.css"rel="stylesheet"/>

    <scriptsrc="/js/default.js"></script>

 

    <!-- Bing Maps references -->

    <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

 

    <!-- Our Bing Maps JavaScript Code -->

    <scriptsrc="/js/bingMapsIntro.js"></script>

</head>

<body>

     <divid="myMap"></div>

</body>

</html>

Next, we will need to add our logic to load the Bing Maps control. If you have used the Bing Maps V7 AJAX control before, you may already be familiar with modules. If not, modules are blocks of JavaScript code that can be used to extend the Bing Maps control by adding useful functionalities. A key benefit to using modules is that the modules fire an event when loaded. If you created your own module, you have a JavaScript file with your logic; at the end of the JavaScript file, be sure to trigger the module loaded event. So, why am I bringing this up now? Well, the Bing Maps control itself is a module which is different from what we are used to when using the AJAX control on the web. As a module, we will need to load it and create a callback function that will initialize the map. If we try to initialize the map before the module is loaded we will end up with errors. In addition, we also want to wait until the document is fully loaded before we initialize the map; otherwise, we risk trying to create the map on a div element that is not yet created which will also throw an error. Now this might sound a bit complex, but it is actually rather straight forward. Open the bingMapsIntro.js file and add the following code:

var map;

 

function GetMap() {

    var mapOptions =

    {

        credentials: "YOUR_BING_MAPS_KEY",

        zoom : 2

    };

 

    map = new Microsoft.Maps.Map(document.getElementById("myMap"), mapOptions);

}

 

//Initialization logic for loading the map control

(function () {

    function initialize() {

        Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });

    }

 

    document.addEventListener("DOMContentLoaded", initialize, false);

})();

If you are not familiar with the last function, wrapped with brackets without a name, it is a common technique for limiting the scope of functions. By doing this, the initialize function is only made known to our event listener and therefore, not a global function. This is useful as we only need this function once.

If we run the application, we will end up with a Bing map that takes up the whole screen and looks like this.

WorldMap

Using Location Services

There are two ways to go about using the location services in Windows 8. The first method consists of using the Windows.Devices.Geolocation.Geolocator class and provides all the functionality needed to access the Location services on a Windows 8 device. This class has lots of features and options, but can be a bit more complex than needed.

The second method consists of using the GeoLocationProvider class, which is made available in the Bing Maps control. The benefit of using this class is that it really simplifies integration with the Location services and will also generate the accuracy circle on the map for us. We will use this approach for the sake of simplicity.

To start, we will open up the default.html file and add a checkbox to a floating div over the map to toggle the GPS (or Location services) feature. The following HTML can be added after the div for the map.

<divstyle="position:absolute;right:10px;top:10px;background-color:#808080;padding:5px;">

    <inputtype="checkbox"onclick="ToggleGPS(this);"/> GPS

</div>  

Next, we will need to open up the bingMapsIntro.js file and add a function called ToggleGPS. In this function, we will want to create an instance of the GeoLocationProvider class and then check to see if the checkbox has been checked or not. If it has been checked, we will want to call the getCurrentPosition method of our GeoLocationPorvider object and have a callback which adds a pushpin to the center of the returned location. The accuracy circle is drawn automatically and can be disabled through the options. If the checkbox is not checked, we will want to remove the accuracy circle and center pushpin. We will also want to cancel any outstanding requests to the GeoLocationProvider. To keep things clean, we will add an EntityCollection to the map. This is where we will add the center pushpin, versus adding the pushpin directly to the map. This will allow us to easily remove the center pushpin when we want it removed. Now we can add our ToggleGPS function and update the GetMap function in the bingMapsIntro.js file.

var map, geoLocationProvider, gpsLayer;

 

function GetMap() {

    var mapOptions =

    {

        credentials: "YOUR_BING_MAPS_KEY",

        zoom : 2

    };

 

    map = new Microsoft.Maps.Map(document.getElementById("myMap"), mapOptions);

 

    gpsLayer = new Microsoft.Maps.EntityCollection();

    map.entities.push(gpsLayer);

}

 

function ToggleGPS(args) {

 

    // Initialize the location provider

    if (!geoLocationProvider) {

        geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);

    }

 

    //Clear the GPS layer

    gpsLayer.clear();

 

    if (args.checked) {

        // Get the user's current location

        geoLocationProvider.getCurrentPosition({

            successCallback: function (e) {

                gpsLayer.push(new Microsoft.Maps.Pushpin(e.center));

            }

        });

    } else {

        //Remove the accuracy circle and cancel any request that might be processing

        geoLocationProvider.removeAccuracyCircle();

        geoLocationProvider.cancelCurrentRequest();

    }

}

Before we get too far ahead, we need to add the Location services to the capabilities in the package manifest; otherwise, we won’t be able to get any location information from the users device. To do this, simply double click on the package.appxmanifest file and select the Capabilities tab at the top. Under the Capabilities section, check the Location option.

image

At this point, we are ready to test the application. If you run the application, in the top right hand corner, you will see the check box. When clicked, the map should zoom into your location and display a pushpin on your location and a circle of accuracy.

GPSMap

Testing the App on a Local Machine

If you are like me, your primary development computer probably doesn’t have a touch screen. Although, maybe you have access to a touch device that has Windows 8 installed to test your app. I just happen to have an Acer Iconia Tab W500 with Windows 8. I haven’t installed anything else on it (like visual studios), so this makes for a perfect environment for testing the application. Now, how to get our newly developed app on to our other device? Well, there are a couple of ways to do this and some more complex than others. A good blog post on this can be found here. Since I created the app, and I’m deploying it onto my own machine, I’m not too concerned at this moment about security and properly signing my application. I’ll save that for when I’m ready to share it with others or deploy to the Windows Store.

So, here is an easy way to test your app. Right click on the BingMapsJSIntro project and select Store -> Create App Packages. You will be prompted with a question, “Do you want to build packages to upload to the Windows Store?” - select No and press Next. On the next screen, you can add version numbers and select the architecture to run the app on. We will leave all this as it is and press the Create button. This will generate a package for us and will provide us with a link to the folder to the package. Copy the package onto a USB drive. Next, go to your test device and plug in the USB drive. Inside the AppPackages folder, you should see a folder that has the name of our app and a version number. In that folder, you should find a PowerShell file called Add-AppDevPackage. Right click, or touch and hold so that the context menu opens up. In the context menu, click on Run with PowerShell.

image

Just follow the prompts that come up on the screen. When it is done, you can go to your Start screen and at the end, see your application. Now, since we haven’t added an image for the icon, our app tile is grey and has a box with an x in it. We can worry about making it look nice later.

image

If you click on your app it should load up. You can press the GPS and traffic checkboxes to see it work. Keep in mind that a lot more testing will be needed if you plan to deploy application to the Windows Store. For more information, take a look at this blog post.

-Ricky

REST Services in Bing Maps Windows Store Apps (Using JavaScript)

$
0
0

When using Bing Maps, you may find that you need to access a REST based web service from time to time. In Bing Maps there are many REST based services available that can be used to bring data into your app. The Bing Maps REST service provides functionalities such as Geocoding, Reverse Geocoding, Routing, Static Imagery, and Traffic Incident data. There is also the Bing Spatial Data Services that can be used to store your own location data and have it exposed as a REST based spatial service. We also provide NAVTEQ point of interest data through the Bing Spatial Data Services. Although integrating REST services into the Bing Maps JavaScript controls is fairly easy, there is a small change required when developing for the Windows Store App platform. In this blog post, we will walk through how to integrate the Bing Maps Traffic Incident REST service with the Bing Maps Windows Store App JavaScript control.


Setting up the project

To set up the project, open Visual Studios 2012 and create a new project. In the window that opens, select JavaScript -> Windows Store. Then, select the Blank App template, call the application BingMapsREST_WinRTJS and press OK.

In an effort to keep things more cleanly, we are going to create a separate JavaScript file for our application. To do this, right click on the js folder and select Add -> New Item, and create a new JavaScript file called BingMapsREST.js.

At this point, your Solution should look something like this:

clip_image002[3]

Next, you will want to add a reference to the Bing Maps JavaScript library. First, right click on the References folder and press Add Reference. Then, select Windows -> Extensions and then select Bing Maps for JavaScript. If you do not see this option, be sure to verify that you have installed the Bing Maps SDK for Windows 8 style apps.

Now, open up the default.html file and add references to the Bing Maps SDK along with a reference to our JavaScript file. The layout for our application will consist of a map and nothing more. The HTML for the default.html file should look like this:

<!DOCTYPEhtml>

<html>

<head>

    <metacharset="utf-8"/>

    <title>BingMapsREST_WinRTJS</title>

 

    <!-- WinJS references -->

    <linkhref="//Microsoft.WinJS.1.0/css/ui-dark.css"rel="stylesheet"/>

    <scriptsrc="//Microsoft.WinJS.1.0/js/base.js"></script>

    <scriptsrc="//Microsoft.WinJS.1.0/js/ui.js"></script>

 

    <!-- BingMapsREST_WinRTJS references -->

    <linkhref="/css/default.css"rel="stylesheet"/>

    <scriptsrc="/js/default.js"></script>

 

    <!-- Bing Maps references -->

    <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

    <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>

 

    <!-- Our Bing Maps JavaScript Code -->

    <scriptsrc="/js/BingMapsREST.js"></script>

</head>

<body>

    <divid="myMap"></div>

</body>

</html>


Loading the Bing Maps Control

Next, we will add the functionality to load the Bing Maps control to the BingMapsREST.js file. To start, we are going to create five global variables: map, infobox, dataLayer, sessionKey and trafficTypes. The trafficTypes will be an array of string that has the names of the different types of traffic. The array will be set up so that the index of the array matches the trafficType value which is a number.  We will now create a function called GetMap which will load the Bing Maps control for us. In this function, we will also add an entity collection to the map for our data, an Infobox for displaying information, and generate a session key to be used with the Traffic REST service (making those calls non-billable).  Once the session key is created, we will attach a throttled event to the map which will fire when the map has finished moving. When this event is triggered, a request for traffic data in the current map view will be made. The GetMap function will be loaded after the Microsoft.Maps.Map module has completed loading. Your code should look like this:

var map, infobox, dataLayer, sessionKey;

var trafficTypes = [null, "Accident", "Congestion", "Disabled Vehicle", "Mass Transit", "Miscellaneous", "Other News", "Planned Event", "Road Hazard", "Construction", "Alert", "Weather"];

 

function GetMap() {

    // Initialize the map

    map = new Microsoft.Maps.Map(document.getElementById("myMap"), {

        credentials: "YOUR_BING_MAPS_KEY",

        center: new Microsoft.Maps.Location(51.5, 0),

        zoom: 10

    });

 

    //Add a layer for pushpin data

    dataLayer = new Microsoft.Maps.EntityCollection();

    map.entities.push(dataLayer);

 

    //Add a layer for the infobox

    var infoboxLayer = new Microsoft.Maps.EntityCollection();

    map.entities.push(infoboxLayer);

 

    //Create a global infobox control

    infobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), {

        visible: false,

        offset: new Microsoft.Maps.Point(0, 20),

        height: 150,

        width: 300

    });

    infoboxLayer.push(infobox);

 

    map.getCredentials(function (c) {

        sessionKey = c;

 

        //Use a throttled event to reduce the number of unwanted events being fired.

        Microsoft.Maps.Events.addThrottledHandler(map, 'viewchangeend', MakePOIRequest, 250);

 

        //Make a request as the map to initially fill the map

        MakePOIRequest();

    });   

}

 

//Initialization logic for loading the map control

(function () {

    function initialize() {

        Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });

    }

 

    document.addEventListener("DOMContentLoaded", initialize, false);

})();


Adding the Application Logic

When the user moves the map, an event will be triggered and call a function named MakePOIRequest. This function will generate a REST URL for querying the Traffic Incident service by bounding box. This URL will then be used to request data. Since this service is a Bing Maps service, it does not sit in the same domain as your application, and as such, we need to make a cross domain request. Making this request in a standard JavaScript application can be made by using the XMLHttpRequest object. When developing for the Windows Store App platform, we should use the WinRT.xhr class. This class wraps the XMLHttpRequest object and makes a call to it asynchronously. We can then add a Promise function (callback or ‘then’ function) which we will call POICallback. This callback function will process the response. The MakePOIRequest function looks like this:

function MakePOIRequest() {

    var bbox = map.getBounds();

 

    //Create the request to the traffic incidents service.

    var poiRequest = "http://dev.virtualearth.net/REST/v1/Traffic/Incidents/" +

        bbox.getSouth() + "," + bbox.getWest() + "," + bbox.getNorth() + "," +

        bbox.getEast() + "?key=" + sessionKey;

 

    //Process the request and fire the callback

    WinJS.xhr({ url: poiRequest }).then(POICallback);

}


When the service responds and the POICallback function is fired, we will clear the map and verify that the request was successful. If successful, we will take the response text and parse it into a JSON object. Once the response is in the form of a JSON object we can loop through the results and render the data on the map. Since the traffic data has different severity levels, we will use different colored pushpins to display the locations on the map (as shown in the table below).

Pushpin

Severity

Description

green_pingreen_pin.png

1

Low Impact

yellow_pinyellow_pin.png

2

Minor

red_pinred_pin.png

3

Moderate

black_pinblack_pin.png

4

Serious


Add these pushpins to the images folder of the project. Your project should now look like this:

clip_image012[3]

We will also add a Title and Description property to the pushpins and add details for the incident in these fields. We will be able to retrieve these properties from the Infobox control. One of the properties of an incident is a date and time of the last time the incident information was updated. This is in the form of an OData date value. We will need to parse this date value into a nicely formatted date. Finally, as the pushpin is clicked, we will need to add the logic to display the infobox and fill the infobox with the Title and Description values that we added to the pushpin. Putting this all together, we end up with the following JavaScript code:

function POICallback(response) {
    dataLayer.clear();
    infobox.setOptions({ visible: false });

    if (response.status == 200) {
        //Parse JSON response
        var result = JSON.parse(response.responseText);

        if (result != null &&
            result.resourceSets != null &&
            result.resourceSets.length > 0 &&
            result.resourceSets[0].resources != null &&
            result.resourceSets[0].resources.length > 0) {
           
            var r = result.resourceSets[0].resources;

            //add the POI data to the map
            for (var i = 0; i < r.length; i++) {
                //Get coordinate of incident
                var location = new Microsoft.Maps.Location(r[i].point.coordinates[0], r[i].point.coordinates[1]);

                //Get custom icon based on severity
                var customIcon = '/images/';

                switch (r[i].severity) {
                    case 2: //Minor
                        customIcon += 'yellow_pin.png';
                        break;
                    case 3: //Moderate
                        customIcon += 'red_pin.png';
                        break;
                    case 4: //Serious
                        customIcon += 'black_pin.png';
                        break;
                    case 1: //Low Impact
                    default:
                        customIcon += 'green_pin.png';
                        break;
                }

                //Create a pushpin for the incident
                var pushpin = new Microsoft.Maps.Pushpin(location, { icon: customIcon });
                pushpin.Title = trafficTypes[r[i].type];

                //Generate the description HTML markup
                pushpin.Description = "<b>Last Update:</b> " + parseJsonDate(r[i].lastModified) +
                        '<br/><br/><b>Description:</b> ' + trafficTypes[r[i].type] + " " + r[i].description;

                //Add a click event to the pushpin
                Microsoft.Maps.Events.addHandler(pushpin, 'click', displayInfobox);

                //Add the pushpin to the data layer
                dataLayer.push(pushpin);
            }
        }
    }
}

function displayInfobox(e) {
    if (e.targetType == 'pushpin') {
        infobox.setLocation(e.target.getLocation());
        infobox.setOptions({ visible: true, title: e.target.Title, description: e.target.Description });
    }
}

function parseJsonDate(jsonDate) {
    var offset = new Date().getTimezoneOffset();
    var parts = /\/Date\((-?\d+)([+-]\d{2})?(\d{2})?.*/.exec(jsonDate);

    if (parts[2] == undefined)
        parts[2] = 0;

    if (parts[3] == undefined)
        parts[3] = 0;

    return new Date(+parts[1] + offset + parts[2] * 3600000 + parts[3] * 60000);
}


If you run the application you should see a bunch of different colored pushpins appear on the map. If nothing loads, you may be zoomed out too much, or there are no traffic incidents in the area you are viewing. Here is a screenshot of the application displaying traffic data for part of Europe and the infobox open for one of the incidents.

TrafficIncidentMap

For information on Traffic data availability, check out the Bing Maps Traffic Coverage page in MSDN.

- Ricky

Getting started with Bing Maps Windows Store Apps (Native)

$
0
0

If you follow this blog regularly, there is a strong chance that you are familiar with Bing Maps and all the greatness it brings to the web. And, with Windows 8, you can add that same greatness directly into your applications using the Bing Maps SDK for Windows Store Apps. When developing with the Bing Maps SDK for Windows Store Apps you have the option of using JavaScript or Native code (C#, VB or C++). The Native version of the Bing Maps SDK for Windows Store Apps is a new control developed from the ground up for the Windows Store App platform. The native control offers a lot more performance benefits than the JavaScript control. If you have ever used the Bing Maps Silverlight, WPF or Windows Phone controls you will find a lot of similarities between the SDK’s, however, do not assume there is 100% parity between them

In this blog post, we are going to look at how to create a simple application using the C# Bing Maps Windows Store App Native control while using the location services available in Windows 8. If you are looking for more information on the JavaScript control take a look at the Getting Started with Bing Maps Windows Store App (JavaScript) blog post.

Setting up your development environment

To develop Bing Maps Windows Store applications you will need the following installed:

You will also need a Bing Maps account and key. If you intend to create a non-trial application, you should create a Basic key for your Windows Store App and read the governing TOU that defines your usage limits.

Setting up the project

To set up the project, open Visual Studios 2012 and create a new project. In the window that opens, select Visual C# -> Windows Store. Select the Blank App template, call the application BingMapsIntro_WinRT_CS and press OK.

image

A simple project will be created that contains an App.xaml and a MainPage.xaml file along with folders for Assets, CSS, and common style files. The App.xaml.cs file contains the logic for handing the different states of the application. Windows Store applications have three states: not running, running, and suspended. When the state changes, an event is fired, triggering the code in this file. We will not worry about handling the different states in this blog post, but it is good to take note of it as it will become useful later.

Adding Bing Maps to the App

To get started, we will need to add a reference to the Bing Maps SDK. First, right click on the References folder and press Add Reference. Select Windows -> Extensions, and then select Bing Maps for C#, C++ and Visual Basic. If you do not see this option, be sure to verify that you have installed the Bing Maps SDK for Windows Store apps. While you are here, you can also add a reference to the Microsoft Visual C++ Runtime Package as this is required by the Bing Maps SDK when developing using C# or Visual Basic.

image

You may notice a little yellow indicator on the references that you just added. Bing Maps SDK requires that you set the Active solution platform in Visual Studio to one of the following options:

  • · C#, Visual Basic: ARM, x86 or x64
  • · C++: ARM, Win32 or x64

To do this, right click on the Solution folder and select Properties. Then, go to Configuration Properties -> Configuration. Locate your project and under the Platform column and set the target platform. For the purpose of this blog post, I’m going to select x86. Press Ok and the yellow indicator should disappear from your references.

image

At this point your application should look something like this:

image

Now we can add a map to our application. To do this, open the MainPage.xaml file and add the Bing Maps SDK as a namespace at the top of the file. Now we can add a Map object to the Grid control and add our Bing Maps key to the credentials properties of the map. We will also give the map a name of MyMap.

<Page

    x:Class="BingMapsIntro_WinRT_CS.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:m="using:Bing.Maps">

 

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

        <m:MapName="MyMap" Credentials="YOUR_BING_MAPS_KEY"/>

    </Grid>

</Page>

If we run the application, we will end up with a Bing map that takes up the whole screen and looks like this.

NativeMap

Using Location Services

We can make use of the Location Services functionality in Window 8 by using the Windows.Devices.Geolocation.Geolocator class. We will use this class to get access the user’s location information. To start, we will open up the MainPage.xaml file and add a checkbox that sits on top of the map to toggle the GPS (or Location services) feature on and off. The XAML for this file should now look like this:

<Page

    x:Class="BingMapsIntro_WinRT_CS.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:m="using:Bing.Maps">

 

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

        <m:Map Name="MyMap" Credentials="YOUR_BING_MAPS_KEY"/>

       

        <CheckBox Content="GPS" Click="GPS_Checked"

                  Width="60" Height="25" Background="Gray"

                  Margin="0,10,100,0" HorizontalAlignment="Right" VerticalAlignment="Top"/>

    </Grid>

</Page>

We can now begin to add the functionality behind the map. Open the MainPage.xaml.cs file and create two global variables called GpsPushpin and geolocator. In the constructor of the MainPage class we will initialize the GpsPushpin object and add it to the map. To begin, we will set the visibility of the GpsPushpin to collapsed. Your MainPage.xaml.cs file should look like this:

using Bing.Maps;

using Windows.Devices.Geolocation;

using Windows.UI.Core;

using Windows.UI.Xaml;

using Windows.UI.Xaml.Controls;

using Windows.UI.Xaml.Navigation;

 

namespace BingMapsIntro_WinRT_CS

{

    publicsealedpartialclassMainPage : Page

    {

        Geolocator geolocator;

        Pushpin GpsPushpin;

 

        public MainPage()

        {

            this.InitializeComponent();

 

            //Create a pushpin for the GPS location and add it to the map

            GpsPushpin = newPushpin()

            {

                Visibility = Windows.UI.Xaml.Visibility.Collapsed

            };

 

            MyMap.Children.Add(GpsPushpin);

        }

 

        protectedoverridevoid OnNavigatedTo(NavigationEventArgs e)

        {

        }

    }

}

Next, we need to create a method called GPS_Checked which fires when the user clicks on the GPS checkbox. When this method is fired, we will need to verify if the checkbox is actually checked. If checked, we will need to verify that the geolocator object has been initialized. If it hasn’t, then create and initialize it. Once verified, add a position changed event to this object called geolocator_PositionChanged. If the checkbox has been unchecked we will need to remove the position changed event from the geolocator object (if it exists) and hide the GpsPushpin. This method looks like this:

privatevoid GPS_Checked(object sender, RoutedEventArgs e)

{

    CheckBox cb = sender asCheckBox;

 

    if (cb.IsChecked.HasValue && cb.IsChecked.Value)

    {

        if (geolocator == null)

        {

            //Create an instance of the GeoLocator class.

            geolocator = newGeolocator();

        }

 

        //Add the position changed event

        geolocator.PositionChanged += geolocator_PositionChanged;

    }

    else

    {

        if (geolocator != null)

        {

            //Remove the position changed event

            geolocator.PositionChanged -= geolocator_PositionChanged;

        }

 

        //Hide the GPS pushpin

        GpsPushpin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

    }

}

Now we have to create the geolocator_PositionChanged event handler. This event will be called on a different thread than the map, so we will need to use a Dispatcher to access the same UI thread as the map. Once this is done, we can get the users location from the PositionChangedEventArgs object and use this to update the location of the GpsPushpin.At the same time, we can set the map view so that it is centered over this location. Finally, we need to make the GpsPushpin visible. This event handler will look like this:

privatevoid geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)

{

    // Need to get back onto UI thread before updating location information

    this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, newDispatchedHandler(

    () =>

    {

        //Get the current location

        Location location = newLocation(args.Position.Coordinate.Latitude, args.Position.Coordinate.Longitude);

 

        //Update the position of the GPS pushpin

        MapLayer.SetPosition(GpsPushpin, location);

 

        //Make GPS pushpin visible

        GpsPushpin.Visibility = Windows.UI.Xaml.Visibility.Visible;

 

        //Update the map view to the current GPS location

        MyMap.SetView(location, 17);

    }));

}

Before we get too far ahead, we need to add the Location services to the capabilities in the package manifest; otherwise, we won’t be able to get any location information from the users device. To do this, simply double click on the Package.appxmanifest file and select the Capabilities tab at the top. Under the Capabilities section, check the Location option.

image

At this point, we are ready to test the application. If you run the application you will see the check box in the top right hand corner. In the first click, you will be asked to allow the application to share your location. After which, it will zoom and display a pushpin on your location.

GPSLocation

Location Accuracy Circle

It is common to display a circle of accuracy in apps that display a user’s location In order to get this,we will need to create the circle. The PositionChangedEventArgs object has an accuracy property which gives an accuracy radius in meters. We can use this radius to make our accuracy circle by creating a User Control called GpsIcon that will mark our user’s location and display our accuracy circle. To do this, right click on the project and select Add -> New Item. Then, select User Control and give it a name of GpsIcon.xaml and press OK.

image

Start by opening the GpsIcon.xaml file. We are going to use several Ellipse objects to create the icon for the center of the circle as well as our accuracy circle. Since we will need to update our accuracy this point, we will give it a name of AccuracyCircle. Your XAML will look like this:

<UserControl

    x:Class="BingMapsIntro_WinRT_CS.GpsIcon"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

   

    <Canvas>

        <Ellipse Name="AccuracyCircle" Fill="AliceBlue" Opacity="0.5" Stroke="Blue" StrokeThickness="2"/>

        <Ellipse Height="20" Width="20" Fill="White" Margin="-10,-10,0,0"/>

        <Ellipse Height="14" Width="14" Fill="Black" Margin="-7,-7,0,0"/>

        <Ellipse Height="10" Width="10" Fill="Yellow" Margin="-5,-5,0,0"/>

    </Canvas>

</UserControl>

Now we can add the logic for this user control to the GpsIcon.xaml.cs file. In the constructor, we will want to take in a Map object. We will need a reference to the map so that we can update the accuracy circle based on the current zoom level. We will also need to create a method for setting the radius of the accuracy circle in meters. Finally, we will need a method to update the radius of the accuracy circle ellipse by converting the radius that is currently in meters to a pixel radius. Putting this all together, the code for the GpsIcon.xaml.cs file will look like this:

using Bing.Maps;

using System;

using Windows.UI.Xaml.Controls;

 

namespace BingMapsIntro_WinRT_CS

{

    publicsealedpartialclassGpsIcon : UserControl

    {

        privateMap _map;

        privatedouble _radius;

        privateconstdouble EARTH_RADIUS_METERS = 6378137;

 

        public GpsIcon(Map map)

        {

            this.InitializeComponent();

 

            _map = map;

 

            //Add a View Changed event to the map to update the accuracy circle

            _map.ViewChanged += (s, e) =>

            {

                //Update the accuracy circle

                UpdateAccuracyCircle();

            };

        }

 

        publicvoid SetRadius(double radiusInMeters)

        {

            //Store the radius value

            _radius = radiusInMeters;

 

            //Update the accuracy circle

            UpdateAccuracyCircle();

        }

 

        privatevoid UpdateAccuracyCircle()

        {

            if (_map != null&& _radius >= 0)

            {

                //Calculate the ground resolution in meters/pixel

                //Math based on http://msdn.microsoft.com/en-us/library/bb259689.aspx

                double groundResolution = Math.Cos(_map.Center.Latitude * Math.PI / 180) *

                    2 * Math.PI * EARTH_RADIUS_METERS / (256 * Math.Pow(2, _map.ZoomLevel));

 

                //Calculate the radius of the accuracy circle in pixels

                double pixelRadius = _radius / groundResolution;

 

                //Update the accuracy circle dimensions

                AccuracyCircle.Width = pixelRadius;

                AccuracyCircle.Height = pixelRadius;

 

                //Use the margin property to center the accuracy circle

                AccuracyCircle.Margin = new Windows.UI.Xaml.Thickness(-pixelRadius/2, -pixelRadius/2, 0, 0);

            }

        }

    }

}

It is now time to update our application to make use of this new GpsIcon user control to mark the user’s location. First, we will need to change the type of the GpsPushpin object from Pushpin to GpsIcon, and pass in a reference to the map when initializing this object. Then, we will need to set the radius in the geolocator_PositionChanged event handler. The MainPage.xaml.cs file should now look like this:

using Bing.Maps;

using Windows.Devices.Geolocation;

using Windows.UI.Core;

using Windows.UI.Xaml;

using Windows.UI.Xaml.Controls;

using Windows.UI.Xaml.Navigation;

 

namespace BingMapsIntro_WinRT_CS

{

    publicsealedpartialclassMainPage : Page

    {

        Geolocator geolocator;

        GpsIcon GpsPushpin;

 

        public MainPage()

        {

            this.InitializeComponent();

 

            //Create a pushpin for the GPS location and add it to the map

            GpsPushpin = newGpsIcon(MyMap)

            {

                Visibility = Windows.UI.Xaml.Visibility.Collapsed

            };

 

            MyMap.Children.Add(GpsPushpin);

        }

 

        privatevoid GPS_Checked(object sender, RoutedEventArgs e)

        {

            CheckBox cb = sender asCheckBox;

 

            if (cb.IsChecked.HasValue && cb.IsChecked.Value)

            {

                if (geolocator == null)

                {

                    //Create an instance of the GeoLocator class.

                    geolocator = newGeolocator();

                }

 

                //Add the position changed event

                geolocator.PositionChanged += geolocator_PositionChanged;

            }

            else

            {

                if (geolocator != null)

                {

                    //Remove the position changed event

                    geolocator.PositionChanged -= geolocator_PositionChanged;

                }

 

                //Hide the GPS pushpin

                GpsPushpin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

            }

        }

 

        privatevoid geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)

        {

            // Need to get back onto UI thread before updating location information

            this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, newDispatchedHandler(

            () =>

            {

                //Get the current location

                Location location = newLocation(args.Position.Coordinate.Latitude, args.Position.Coordinate.Longitude);

 

                //Update the position of the GPS pushpin

                MapLayer.SetPosition(GpsPushpin, location);

               

                //Set the radius of the Accuracy Circle

                GpsPushpin.SetRadius(args.Position.Coordinate.Accuracy);

 

                //Make GPS pushpin visible

                GpsPushpin.Visibility = Windows.UI.Xaml.Visibility.Visible;

 

                //Update the map view to the current GPS location

                MyMap.SetView(location, 17);

            }));

        }

 

        protectedoverridevoid OnNavigatedTo(NavigationEventArgs e)

        {

        }

    }

}

If you run the application and enable the GPS by pressing the GPS checkbox, the map should zoom into the user’s location and display both the location and accuracy circle.

image

Check out the Developer Code Samples section on MSDN for other interesting examples of how to use the Bing Maps SDK for Windows Store Apps.

-Ricky

Create Heat Maps with Bing Maps and Dynamics CRM

$
0
0

The majority of data in the enterprise today has a location component, including most sales, operational, or service-related data. By visualizing our business data on a map, we can identify trends by geography, and use them to make smarter business decisions. In this blog post, we will show how you can visualize business data within Microsoft Dynamics CRM on Bing Maps in the form of a heat map, to identify hotspots of customers, leads, service requests and more. Dynamics CRM provides a powerful general purpose framework for developing line-of-business applications, and we will use Dynamics CRM Online, the Bing Maps AJAX v7 control, and a Heat Map module to create our visualization.

What are heat maps? Wikipedia defines a heat map as “a graphical representation of data where the individual values contained in a matrix are represented as colors”. In a geographic mapping context, heat maps can provide visualization of the relative density of point data:

Heatmap 1

We will now show how to bring this method of visualization into Dynamics CRM through the use of Web Resources and Bing Maps, to show a heat map of our CRM Opportunities, weighted by the Estimated Value, to give us a view into our potential revenue opportunity by geography.

Note that the code samples below assume that your data in CRM has been geocoded, with latitudes and longitudes populated for the entities you wish to visualize. If your data does not already have coordinates populated, you can leverage the Bing Maps Locations API to geocode individual addresses, or alternately, the Bing Maps Spatial Data Services Geocode Dataflow API to geocode your data in batches.

Creating our Heat Map Web Resource:

We will present our mapping visualization in the context of Dynamics CRM Online through the use of Web Resources. We will create one HTML Web Resource for our map, and we will also leverage a JavaScript Web Resource to host the Heat Map module that enables the heat spot visualization.

Our HTML Web Resource will host our map, and retrieve the entity data from Dynamics CRM Online, using the REST Endpoint for Web Resources.

When creating our HTML Web Resource, we must use the appropriate DOCTYPE declaration, add a META element with the charset attribute set to "utf-8", and include the appropriate JavaScript resource files:

·         The Bing Maps AJAX v7 Map Control (we must include the ‘s=1’ parameter in the link, which is required for https access)

·         jQuery

·         The ClientGlobalContext.js.aspx page, for access to the server URL for our REST query

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<head>

    <title>Bing Map Heatmap</title>

    <metahttp-equiv="Content-Type"content="text/html; charset=utf-8"/>

    <styletype="text/css">

        body

        {

               margin:0000;

        }  

    </style>

    <scripttype="text/javascript"charset="UTF-8"src="https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&s=1">

    </script>

    <scripttype="text/javascript"src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.js"></script>

    <scripttype="text/javascript"src="ClientGlobalContext.js.aspx"></script>

Our HTML will be very basic: just a placeholder DIV for the map, which will occupy the entire page. Note that we will call our getMap() function when the page loads:

 

<bodyonload="getMap();">

    <divid="map"style="width: 100%; height: 100%;"/>

</body>

</html>

Instantiating our Map:

In our Web Resource file, we will add JavaScript code to instantiate our map. First, we define a number of global variables, to be used as we load the map and retrieve our data. Note that we use the Client Global Context to retrieve the server URL, which we will use as part of our REST request for CRM entity data, to enable portability of our Web Resource

The getMap() function gets called when the page loads, and at this time, we will instantiate our map, and then register and load a module which will enable our heat map visualization. When loading the module, we define a callback function in which we construct our query to retrieve Opportunity data from the CRM REST endpoint, and then issue an AJAX request. Note how we are also extending the Microsoft.Maps.Location class by adding a multiplier property, which we will use to weight our heat map:

 

//CRM Server Url:

var serverUrl = GetGlobalContext().getServerUrl();

 

// Configure global variables:

var map = null;

   

// Set up arrays to hold opportunity query results and locations for heatmapping:

var opportunityResults = new Array;

var opportunityLocations = new Array();

 

// Heat map layer:

var heatmapLayer = null;

 

// Called on load, we instantiate the map, and retrieve all of our location data from CRM:

function getMap() {

 

    // Instantiate map, and show world view:

    var mapOptions = {

        credentials: "insert key here",

        zoom: 2,

        center: new Microsoft.Maps.Location(36, -40)

    };

    map = new Microsoft.Maps.Map(document.getElementById('map'), mapOptions);

 

    // Extend location to allow for revenue-weighted heatmaps:

    Microsoft.Maps.Location.prototype.multiplier = null;

 

    // Register and load the Client Side HeatMap Module

    Microsoft.Maps.registerModule("HeatMapModule", "./new_heatmap_module");

    Microsoft.Maps.loadModule("HeatMapModule", { callback: function () {

        // Once the module is loaded, retrieve the opportunity data:

        // Define REST query for Opportunity data:

        var oppQuery = "OpportunitySet?$select=EstimatedValue," +

                        "opportunity_customer_accounts/Address1_Latitude," +

                        "opportunity_customer_accounts/Address1_Longitude&" +

                        "$expand=opportunity_customer_accounts";

        // Load Opportunity Data:

        var requestUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/" + oppQuery;

        makeAjaxRequest(requestUrl, opportunityResults, opportunityCallback);

        }

    });

 

}

 

}

 

Our query against the REST endpoint retrieves the EstimatedValue of each opportunity, and also uses the $expand OData option to enable us to retrieve the Latitude and Longitude of the Account to which this Opportunity relates. Note how we are passing three parameters to the makeAjaxRequest function:

·         The URL to use in our request to the REST endpoint

·         The Array we want to populate with our resulting Opportunity data

·         The callback function to call on completion

Retrieving our Opportunity Data:

We will retrieve all of our Opportunity data through the use of the jQuery ajax method. Note that there is a maximum of 50 records returned per request to the CRM REST endpoint. If there are more than 50 Opportunity records, there will be a JSON__next property at the end of the result set. The URL value in that node can be used to retrieve the next set of records. Once all records have been obtained, the callback function (opportunityCallback) is called:

 

// issue ajax request, populate specified array with results, then call specified callback function:

function makeAjaxRequest(requestUrl, resultArray, callbackFunction) {

    $.ajax(

    {

        type: "GET",

        url: requestUrl,

        contentType: "application/json; charset=utf-8",

        dataType: "json",

        error: function (request, textStatus, errorThrown) {

            alert("Error occurred: " + request.responseXML);

            return;

        },

        success: function (data) {

            var results = data.d["results"];

            for (resultKey in results) {

                // Add results to appropriate array:

                resultArray.push(results[resultKey]);

            }

            // Check to see if we have all of the data:

            if (null != data.d.__next) {

                // If not, issue an additional request:

                makeAjaxRequest(data.d.__next, resultArray, callbackFunction);

            } else {

                // Call callback function:

                callbackFunction();

            }

        }

    });

}

Adding our Heat Map Layer:

Now that we have all of our Opportunity data, our callback function will create Microsoft.Maps.Location objects with each Opportunity, and add a multiplier property, calculated based on the Estimated Value of the Opportunity. All Locations are added to an array, which is then used to create our Heat Map Layer with the Heatmap Module.

This module was created by Alastair Aitchison, Microsoft MVP, and is shared on CodePlex as part of the Bing Maps V7 Modules project. Note that this module is dependent on the HTML5 canvas element. For Internet Explorer, this means IE9+ will be needed to view the heat map.

The module accepts several options when creating the heat map layer, in addition to the map and locations parameters:

·         Intensity:  a value between 0 and 1 which dictates the central opacity of each heat spot

·         Radius: the radius, in meters, of each heat spot. Note that we are altering the radius of each heat spot with our weighting based on Estimated Value

·         Unit: we are specifying a radius in meters, but it is also possible to specify a radius in pixels. By using meters, we ensure the heat spots scale with the map as we zoom

·         Colour Gradient: specifies which colors to use to represent the hottest, coolest, and intermediate areas

// Add Opportunities heatmap layer:

var opportunityCallback = function addOpportunityHeatmap() {

 

    for (var j = 0; j < opportunityResults.length; j++) {

        var item = opportunityResults[j];

 

        // Retrieve item values:

        var lat = item["opportunity_customer_accounts"].Address1_Latitude;

        var lon = item["opportunity_customer_accounts"].Address1_Longitude;

        var estimatedValue = item["EstimatedValue"].Value;

 

        // If lat and long available, construct pushpin and add to map:

        if (lat && lon && lat != 0 && lon != 0) {

               

            // Create location:

            var location = new Microsoft.Maps.Location(lat, lon);

 

            // Add a nominal multiplier value to the location, for revenue-based heatmapping:

            if (estimatedValue >= 0) {

                var locMultiplier = estimatedValue / 2000000;

                location.multiplier = locMultiplier;

            }

 

            // Add location to appropriate array for heatmapping:

            opportunityLocations.push(location);

 

        }

    }

 

    // Construct heatmap layer, using heatmapping module:

    heatmapLayer = new HeatMapLayer(

        map,

        [],

        { intensity: 0.7,

            radius: 500000,

            unit: 'meters',

            colourgradient: {

                0.0: 'green',

                0.5: 'yellow',

                1.0: 'red'

            }

        });

        heatmapLayer.SetPoints(opportunityLocations);

 

}

Minor Update to Heat Map Module:

In this example, I have made a minor modification to the heat map module, to allow the multiplier we set for each Location to weight the radius used for each heat spot.

 

// Main method to draw the heatmap

function _createHeatMap() {

    // Ensure the canvas matches the current dimensions of the map

    // This also has the effect of resetting the canvas

    _canvas.height = _map.getHeight();

    _canvas.width = _map.getWidth();

 

    _canvas.style.top = -_canvas.height / 2 + 'px';

    _canvas.style.left = -_canvas.width / 2 + 'px';

 

    // Calculate the pixel radius of each heatpoint at the current map zoom

    if (_options.unit == "pixels") {

        radiusInPixel = _options.radius;

    } else {

        radiusInPixel = _options.radius / _map.getMetersPerPixel();

    }

 

    var ctx = _canvas.getContext("2d");

 

    var shadow = 'rgba(0, 0, 0, ' + _options.intensity + ')';

 

    // Create the Intensity Map by looping through each location

    for (var i = 0, len = _locations.length; i < len; i++) {

        var loc = _locations[i];

        var pixloc = _map.tryLocationToPixel(loc, Microsoft.Maps.PixelReference.control);

        var x = pixloc.x;

        var y = pixloc.y;

 

        // MODIFICATION: Use location multiplier against the radius, if one exists:

        var weightedRadius = null;

        if (loc.multiplier != null&& loc.multiplier > 0) {

            weightedRadius = loc.multiplier * radiusInPixel;

        } else {

            weightedRadius = radiusInPixel;

        }

 

        // Create radial gradient centred on this point

        var grd = ctx.createRadialGradient(x, y, 0, x, y, weightedRadius);

        grd.addColorStop(0.0, shadow);

        grd.addColorStop(1.0, 'transparent');

 

        // Draw the heatpoint onto the canvas

        ctx.fillStyle = grd;

        ctx.fillRect(x - weightedRadius, y - weightedRadius, 2 * weightedRadius, 2 * weightedRadius);

    }

 

    // Apply the specified colour gradient to the intensity map

    _colouriseHeatMap();

 

    // Call the callback function, if specified

    if (_options.callback) {

        _options.callback();

    }

}

 

Uploading our Web Resources:

We can now upload our two Web Resources, and publish them both. The main HTML page will be of type ‘Web Page (HTML)’ and the heat map module will be of type ‘Script (JScript)’. We must ensure the name we choose for the Heat Map Module JavaScript resource is used in our link to the module in our HTML Web Resource.

Heatmap 2

We can now test our heat map by clicking the ‘URL’ to our HTML Web Resource above:

Heatmap 3

You can now add a link to your heat map with the method you desire, such as using a ribbon button, or using a link from a dashboard.

You can create heat maps of accounts, opportunities, leads, service cases, and any other entity that has a location component to it, to help visualize and understand trends in your data by geography, and drive smarter business decisions.

The complete code can be found here.

- Geoff Innis, Bing Maps Technical Specialist

New Hurricane Sandy app uses High-Resolution Imagery

$
0
0

Our new Hurricane Sandy app provides a detailed view of the destruction left in the wake of Sandy. Once weather permitted, Keystone Aerial Surveys, one of our Global Ortho flying partners, acquired over 5,368 sq km of striking high-resolution aerial imagery along the New York and New Jersey coastlines.

The area covered is depicted by the red polygon in the image below. To view more of our Hurricane Sandy imagery:

· Go to www.bing.com/maps

· Select Map apps

· Choose the Hurricane Sandy app

image

When visiting the app, use the Beforehurricane and Afterhurricane buttons to toggle between pre and post hurricane damage.

Hurricane Sandy Coverage zoom_550

Breezy Point, NY, located on a barrier island off the southwestern coast of Long Island, was one of the places hardest hit by Hurricane Sandy. This small community suffered flooding, beach erosion, power outages and fire after the storm made landfall, as seen in the before and after images.

Before hurricane

BreezyPointHouses_before_wm

After hurricane

BreezyPointHouses_after_wm

Mantoloking, New Jersey is located on a barrier island south of Point Pleasant. As with many of the low-lying barrier islands in the NY/NJ area, the storm surge from Hurricane Sandy caused great damage. In Mantoloking, the storm cut completely through the island near the main bridge access from the mainland. In the After image you can see where emergency crews are filling the break back in with sand to keep the ocean from continuing to erode the island and ocean water out of the estuary behind it.

Before hurricane

Mantoloking_before_wm

After hurricane

Mantoloking_after_wm

Disaster Relief Link

- The Bing Maps Team

New Imagery Added to Windows 8 Maps App & Bing Maps

$
0
0

This month we’ve added over 121 TB of satellite and Global Ortho imagery to the Windows 8 Maps app & Bing Maps, built a Hurricane Sandy map app and now feature our full spectrum of imagery daily on Facebook.

 

satellitetopglobalorthotopdisastertopfbtop

 

clip_image001[6]

 

 

satellite_coveragemap_blog

Total coverage of new Satellite imagery currently live on Bing Maps! Visit Bing Maps World Tour Appto view full coverage.

Our latest publication of satellite imagery includes over 15 million square kilometers of new data! This month’s delivery is a sizeable 112 TB and predominantly covers South America, Africa, Asia and Europe with some additional coverage in North America and Australia.

 

Lakhish
Israel

Al Fallujah
Iraq

lakhish1

ala

Ertis River
Zhanabet, Kazakhstan

Barrage de L'Oued Fouds
Atlas Mountains, Algeria

er

Untitled-1

The links below highlight additional satellite imagery to explore in this release.

clip_image001[8]

 

Global_Ortho_coverage_blog

Shaded areas indicate 30cm Aerial imagery; yellow coverage shows the latest release.

Check out the Bing Maps World Tour Appto view Global Ortho Total Coverage.

Our latest release of Global Ortho imagery includes 69 blocks and covers over 800,000 sq km. In total, we have published 10,777,300 square kilometers covering 100% of the United States and 83% of Western Europe! The Global Ortho project is nearing completion with only 4% remaining to be published.

Inn and Danube Rivers Converging
Passau, Germany

Baie de la Fresnaye
North of Pléboulle, France

passaufresnaye

Atlantic Ocean Inlet
Foz, Spain

Lake of Zurich
Zurich, Switzerland

fozzurich

To learn more about the Global Ortho project please visit the below links.

MORE HIGHLIGHTS:

Windows Desktop Themes 

We’ve also refreshed our Europe and U.S. desktop themes. There are now a total of 200+ images for the United States and 175+ images for Europe and the themes are compatible with both Windows 7 and Windows 8! Click the images below to explore the different desktop images.

useurope

 

clip_image001[16]

Our new Hurricane Sandy app provides a detailed view of the destruction left in the wake of Sandy. Once weather permitted, Keystone Aerial Surveys, one of our Global Ortho flying partners, acquired over 5,368 sq km of striking high-resolution aerial imagery along the New York and New Jersey coastlines.

Breezy Point, New York located on a barrier island off the southwestern coast of Long Island, was one of the places hardest hit by Hurricane Sandy. This small community suffered flooding, beach erosion, power outages and fire after the storm made landfall, as seen in the before and after images.
 
Breezy Point, New York BEFOREBreezy Point, New York AFTER
breezybeforebreezyafter

Mantoloking, New Jersey is located on a barrier island south of Point Pleasant. As with many of the low-lying barrier islands in the NY/NJ area, the storm surge from Hurricane Sandy caused great damage. In Mantoloking the storm cut completely through the island near the main bridge access from the mainland. In the After image, you can see where emergency crews are filling the break back in with sand to keep the ocean from continuing to erode the island and to keep the ocean water out of the estuary behind it.

Mantoloking, New Jersey BEFOREMantoloking, New Jersey AFTER
mantoaftermantobefore

To view more of our Hurricane Sandy imagery:

  • - Go to Bing Maps
  • - Select Map Apps
  • - Choose the Hurricane Sandy App
  • - Use the before and after buttons to toggle between pre and post hurricane damage

Disaster Relief Link
Softpedia Press Link

 

clip_image001[18]

Check out the official Bing Maps Facebook page, and LIKE it! Each week we focus on a theme to portray the imagery we have acquired. Themes captured include BASE Jumping, Solar Parks, Haunted Places, Theme Parks, Plant Mazes, Places to Hike, Breweries, Stadiums, and more! facebook_like_button_big11

BingFBPage

- The Bing Maps Team

Modules in Bing Maps for Windows Store Apps (JavaScript)

$
0
0

The Bing Maps V7 AJAX control is designed as a modular framework and the Bing Maps for Windows Store App JavaScript control follows the same design. Modules allow users to load only the features and functionalities they need, rather than loading everything up when the application starts. You can save yourself a lot of development time by using modules and avoid reinventing the wheel. Out of the box, Bing Maps provides the following modules:

Name

Description

Microsoft.Maps.AdvanceShapes

Adds support for complex polygons. i.e. polygons with holes.

Microsoft.Maps.Directions

Allows you to calculate a route and display it on the map. The route is draggable by default for easy customization. The instructions will also be nicely formatted.

Microsoft.Maps.Search

Provides an easy method for geocoding address and searching for points of interest from JavaScript.

Microsoft.Maps.Themes.BingTheme

Modifies the navigation bar, pushpin and infobox look and feel to match the Bing Maps consumer site.

Microsoft.Maps.Traffic

Adds a traffic flow tile layer to the map.

Microsoft.Maps.VenueMaps

Exposes the Venue Map functionality and can be used to find nearby venue maps and load them. Venue Maps are interactive buildings on the map that often show the layout of a building. For instance, you can load a venue map of a mall and see were all the stores are located.


In addition to the modules available through the Bing Maps control, there are a large number of community created modules also available on the Bing Maps V7 Modules CodePlex project. However, not all community created modules are designed to work with Windows Store applications; you may need to make some modifications to get them to work with your code. You can also create custom modules, which is a really great way to promote code reuse. For the purpose of this post, we will build on top of the code we created in the Getting started with Bing Maps Windows Store Apps blog post.

Implementing Modules

There are three steps:

  1. Add a reference to the veapimodules.js file from the Bing Maps SDK
  2. Register the module if it isn’t already registered
  3. Load the module and run any post load logic

To add a reference to the veapimodules.js file in the Bing Maps SDK, open the default.html file and update the Bing Maps references to the following:

<!-- Bing Maps references -->

<scripttype="text/javascript"

        src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

<scripttype="text/javascript"

        src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>


Now, before you can load a module, it must first be registered. All modules built into Bing Maps are already registered, however, if you are using a custom module you will need to register it. If you have used custom modules before, be warned, registeringthe web version of the Bing Maps V7 AJAX control and registering modules in the Windows Store App version of the Bing Maps JavaScript control are done differently. Registering custom modules is pretty straightforward; simply add a line of code to register the name and load in the JavaScript file containing your module code. You can do this by adding code, similar to the example below, into the head of the default.html page.

<!-- Register and load the code to our Custom Module -->

<script>Microsoft.Maps.registerModule('MyModule');</script>

<scripttype="text/javascript"src="/js/myModule.js"></script>


One benefit of this approach is that the JavaScript file for our module will be cached as byte code by the Windows 8 framework, which makes for fast loading. However, it doesn’t have the same benefit of being able to load the code for the module on demand which we were are able to do with the built in modules. This is useful when you want the fastest possible startup for your application. With a bit of code we can use JavaScript to dynamically load our custom modules. Here is a simple function we can use to accomplish this:

function RegisterModule(name, url) {

    //Register the module

    Microsoft.Maps.registerModule(name);

 

   //Load the JavaScript File

   var script = document.createElement("script");

    script.setAttribute("type", "text/javascript");

    script.setAttribute("src", url);

    document.body.appendChild(script);

}


Now that the module is registered, we can load it. When to load a module really depends on the type of module you are using. For instance, the Bing Theme module needs to be loaded before the map is loaded, however the directions module doesn’t need to be loaded until the user wants to get directions. Here is the basic way of loading a module:

Microsoft.Maps.loadModule(“MyModule”);


With some modules you may want to run code after the module has loaded. In this case, you can pass in a callback function as an option when loading the module. Doing the following will trigger a function called myModuleLoaded when the module has completed loading.

Microsoft.Maps.loadModule("MyModule", { callback: myModuleLoaded });


Loading the Traffic Module

Now that we understand how to use the module framework in the Bing Maps control, lets implement the traffic module in our application. To start, we will add a checkbox on the map for toggling the traffic layer on and off. First, open the default.html file and the checkbox to the same floating div that has our GPS checkbox. This time we are going to give the checkbox an id property.

<!DOCTYPEhtml>

<html>

<head>

   <metacharset="utf-8"/>

   <title>BingMapsJSIntro</title>

 

   <!-- WinJS references -->

   <linkhref="//Microsoft.WinJS.1.0/css/ui-dark.css"rel="stylesheet"/>

   <scriptsrc="//Microsoft.WinJS.1.0/js/base.js"></script>

   <scriptsrc="//Microsoft.WinJS.1.0/js/ui.js"></script>

 

   <!-- BingMapsJSIntro references -->

   <linkhref="/css/default.css"rel="stylesheet"/>

   <scriptsrc="/js/default.js"></script>

 

   <!-- Bing Maps references -->

   <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

   <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>

 

   <!-- Our Bing Maps JavaScript Code -->

   <scriptsrc="/js/bingMapsIntro.js"></script>

</head>

<body>

   <divid="myMap"></div>

    

   <divstyle="position:absolute;right:10px;top:10px;background-color:#808080;padding:5px;">

        <inputtype="checkbox"onclick="ToggleGPS(this);"/> GPS

        <inputtype="checkbox"onclick="ToggleTraffic();"id="TrafficChbx"/> Traffic

   </div>    

</body>

</html>


Since the traffic module is a built in module in the Bing Maps SDK we do not need to worry about registering it. We also don’t need to load the traffic module until the user presses the Traffic checkbox. To add the logic for traffic checkbox open the bingMapsIntro.js file and add a global variable called trafficLayer. Next, add a function called ToggleTraffic. In this function we will check to see the trafficLayer variable is implemented. If it is, then we can get the checked state from the traffic checkbox and show or hide the traffic layer accordingly. If the trafficLayer variable is not implemented we will need to load the traffic module and create an instance of the Microsoft.Maps.Traffic.TrafficLayer class after the module has loaded. By default, the traffic tile layer has no opacity to it and it ends up covering up the names of roads. To make for a better user experience we will get the base tile layer of the traffic layer and set it’s opacity to 0.5. Finally, after we created an instance of the TrafficLayer class we will want to rerun our logic for toggling the traffic layer. To do all this, add the following code into the bingMapsIntro.js file.

var map, geoLocationProvider, gpsLayer, trafficLayer;

 

function ToggleTraffic() {

   //Check to see if the traffic layer exists

   if (trafficLayer) {

        //Get a reference to the traffic checkbox

        var chbx = document.getElementById('TrafficChbx');

 

        //Hide or Show the tile layer based on checked state

        if (chbx.checked) {

            trafficLayer.show();

        } else {

            trafficLayer.hide();

        }

    } else {

        //Load the traffic module and create the traffic layer.

        Microsoft.Maps.loadModule('Microsoft.Maps.Traffic', {

            callback: function () {

                //Create the traffic layer

                trafficLayer = new Microsoft.Maps.Traffic.TrafficLayer(map);

 

                //Get the base tile layer and set the opacity

                var layer = trafficLayer.getTileLayer();

                layer.setOptions({ opacity : 0.5 });

 

                //Toggle the traffic layer to the current state of the checkbox.

                ToggleTraffic();

            }});

    }

}


If you run the application now and press the traffic button you may not notice anything if you are zoomed out. To make things easy, I’m going to toggle on both the GPS and the Traffic functionalities. Doing this I end up with the following map:

temp2

For more information on where traffic data is available see the Bing Maps Traffic Coverage section of the MSDN documentation.

Loading a Custom Module

We have seen how to load one of the built in modules to our application, now we will look at how to implement a custom module. To do this we will make use of one of the community created modules called Point Based Clustering. This module will group pushpins together when zoomed out to make the map less crowded. This particular module uses a point based algorithm rather than a traditional grid based one. The point based algorithm gives use a much nicer user experience than the grid based algorithm, but there is a trade off in performance. With that said, this algorithm can easily handle 2,000+ pushpins.

Since this module is not really related to what we have put together in our Bing Maps Intro project we will start fresh with a new project. In Visual Studios create a new project and use the JavaScript -> Store -> Blank App template. Call the project PointBasedClustering_WinRT. Once the application is loaded, right click on the js folder and add a new JavaScript file called bingMapsClustering.js. Next, right click on the References folder and add a reference to the Bing Maps SDK. Now, go to the Point Based Clustering page and download the code. Unzip the file and copy the scripts/minified/PointBasedClustering.min.js and the scripts/TestDataGenerator.js files into the js folder of the project. After you do this your project should look like this:

clip_image003

Now we can get started on implementing this custom module. To start, we will open up the default.html file and add a textbox and a button to a floating div in the top, right hand corner of our map where the user can enter the number of pushpins to add to the map. When the button is clicked it will generate the mock pushpin data and display it on the map and clustering it automatically. We will also need to add a reference to the TestDataGenerator.js file for this example. In a production application you would not need this as you would use real data with the Point Based Clustering module. Adding this to the default.html file we end up with the following HTML:

<!DOCTYPEhtml>

<html>

<head>

   <metacharset="utf-8"/>

   <title>BingMapsJSIntro</title>

 

   <!-- WinJS references -->

   <linkhref="//Microsoft.WinJS.1.0/css/ui-dark.css"rel="stylesheet"/>

   <scriptsrc="//Microsoft.WinJS.1.0/js/base.js"></script>

   <scriptsrc="//Microsoft.WinJS.1.0/js/ui.js"></script>

 

   <!-- BingMapsJSIntro references -->

   <linkhref="/css/default.css"rel="stylesheet"/>

   <scriptsrc="/js/default.js"></script>

 

   <!-- Bing Maps references -->

   <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

   <scripttype="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>

 

   <!-- Our Bing Maps JavaScript Code -->

   <scriptsrc="/js/bingMapsClustering.js"></script>z

 

   <!-- Add a reference to class for generating test data. Not needed in production apps. -->

   <scripttype="text/javascript"src="/js/TestDataGenerator.js"></script>

</head>

<body>

   <divid="myMap"></div>

    

   <divstyle="position:absolute;right:10px;top:10px;background-color:#808080;padding:5px;">

        Data Size: <inputtype="text"id="dataSize"style="width:30px;"/>

        <inputtype="button"value="Get Mock Data"onclick="RequestData();"/>

   </div>    

</body>

</html>


Now, open the bingMapsClustering.js file, add the following code to load the map, and register and load the Point Based Clustering Module. We will register our module right after loading the map in the GetMap function.

var map, clusterLayer;

 

function GetMap() {

   var mapOptions =

    {

        credentials: "YOUR_BING_MAPS_KEY",

        zoom: 2

    };

 

    map = new Microsoft.Maps.Map(document.getElementById("myMap"), mapOptions);

 

   //Register and load the Point Based Clustering Module

    RegisterModule("PointBasedClusteringModule", "/js/PointBasedClustering.min.js");

 

    Microsoft.Maps.loadModule("PointBasedClusteringModule", {

        callback: function () {

            clusterLayer = new PointBasedClusteredEntityCollection(map);

        }

    });

}

 

//Initialization logic for loading the map control

(function () {

   function initialize() {

        Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });

    }

 

    document.addEventListener("DOMContentLoaded", initialize, false);

})();

 

We also need to add the RegisterModule functions so that we can dynamically load our custom module. This can easily be done by adding the following after the GetMap function.

function RegisterModule(name, url) {

   //Register the module

    Microsoft.Maps.registerModule(name);

 

   //Load the JavaScript File

   var script = document.createElement("script");

    script.setAttribute("type", "text/javascript");

    script.setAttribute("src", url);

    document.body.appendChild(script);

}


The last item here is to add the logic for handling the button click event by creating a function called RequestData. In this function we will need to get the users input value and pass it to the test data generator to generate our mock data. To simulate an asynchronous call to get our data, which we would likely do for a production application, our test generator takes in a callback function which it will call after it generates our mock data. We will name this callback function RequestDataCallback and have it populate our cluster layer with the mock data. The following can be added after the RegisterModule function in the bingMapsClustering.js file.

//Makes a request for data

function RequestData() {

   var size = parseInt(document.getElementById('dataSize').value);

    TestDataGenerator.GenerateData(size, RequestDataCallback);

}

 

//Handle the data response

function RequestDataCallback(response) {

   if (response != null) {

        clusterLayer.SetData(response);

    }

}


Let’s run the application. In the textbox, enter the number of pushpins you would like to generate on the map and then press the button. The following is a screenshot with 1,000 pushpins being clustered and rendered on the map. As you zoom in, you will notice that the clusters begin to break apart into their individual pushpins.

temp1

- Ricky Brundritt, EMEA Bing Maps Technology Solution Professional


Geocoding and Routing in Bing Maps Windows Store Apps (Native)

$
0
0

In this blog post we are going to look at how implement Geocoding and Routing using the Native Bing Maps Windows Store App SDK. If you are new to developing with the Native Bing Maps Windows Store App SDK I recommend reading the Getting started with Bing Maps Windows Store Apps blog post first. We will also be making use of the Bing Maps REST Services, if you are unfamiliar with using this in native code take a look at this MSDN documentation on Using the REST services with .NET. The methods covered in this blog post can be used as an example of how to access other REST services from Windows Store applications.

Geocoding is one of the most common tasks by users of online maps. Geocoding is the process of taking an address or query and returning its equivalent coordinate on the map. Routing is the task of calculating the directions between two or more locations. In Bing Maps, there are a lot of different options around routing such as routing by different modes of transportation; driving, walking, or transit.

Setting up the project

To set up the project, open Visual Studios 2012 and create a new project. In the window that opens, select Visual C# -> Windows Store. Select the Blank App template and call the application BingMapsSearch_WinRT_CS and press OK.

Next, we will add in the libraries needed for serializing the response from the Bing Maps REST services. To do this, right-click on the project and select Add -> New Item. Create a class file called BingMapsRESTServices.cs. Open up this class file and delete the contents. Go to the MSDN documentation on Using the REST services with .NET and copy and paste the C# Data Contracts into this file. At this point, your Solution should look something like this:

image

Adding Bing Maps to the App

To get started we will need to add a reference to the Bing Maps SDK. To do this, right click on the References folder and press Add Reference. Select Windows -> Extensions select Bing Maps for C#, C++ and Visual Basic. If you do not see this option, take a moment to verify that you have installed the Bing Maps SDK for Windows 8 style apps. While you are here, you should add a reference to the Microsoft Visual C++ Runtime Package as it is required by the Bing Maps SDK when developing using C# or Visual Basic.

image

You may notice that there is a little yellow indicator on the references that you just added. This is because the Bing Maps SDK requires that you set the Active solution platform in Visual Studio to one of the following options.

  • > C#, Visual Basic: ARM, x86 or x64
  • > C++: ARM, Win32 or x64

To do this, right click on the Solution folder and select Properties. Then go to Configuration Properties -> Configuration. Find your project and under the Platform column set the target platform. For this blog post I’m going to select x86. Press Ok and the yellow indicator should disappear from our references.

image

Now we can add a map to our application. To do this, open the MainPage.xaml file. We will first need to add the Bing Maps SDK as a namespace at the top of the file. After we do this we can add a Map object to the Grid control and add our Bing Maps key to the credentials properties of the map. We will also give the map a name of MyMap. While we are at it, we will create a side panel that has input controls for geocoding and routing and a button for clearing the map. In the side panel we will also add two ListBox objects. We will use these to display the geocode results and route itinerary to the user. The XAML for file will look like this:

<Page

   x:Class="BingMapsSearch_WinRT_CS.MainPage"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:local="using:BingMapsSearch_WinRT_CS"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   xmlns:m="using:Bing.Maps">

 

    <Page.Resources>

        <Style TargetType="Button">

            <Setter Property="Background" Value="Green"/>

        </Style>

    </Page.Resources>

   

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="350"/>

            <ColumnDefinition/>

        </Grid.ColumnDefinitions>

 

        <!-- Left Side Panel -->

        <ScrollViewer Background="Gray">

            <StackPanel Margin="10,10,20,10">

                <!-- Clear Map Button -->

                <Button Content="Clear Map" Click="ClearMapBtn_Click"

                       HorizontalAlignment="Right"/>

 

                <!-- Geocode Input -->

                <TextBlock Text="Geocode" FontSize="24"/>

                <Grid>

                    <TextBox Name="GeocodeTbx" HorizontalAlignment="Left"

                            Width="220" Height="25"/>

                    <Button Content="Geocode" HorizontalAlignment="Right"

                           Click="GeocodeBtn_Click"/>

                </Grid>

 

                <!-- Route Input -->

                <TextBlock Text="Route" FontSize="24" Margin="0,10,0,0"/>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Text="From:" FontSize="18"/>

                    <TextBox Name="FromTbx" Width="220" Margin="10,0,0,0"/>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Text="To:" FontSize="18"/>

                    <TextBox Name="ToTbx" Width="220" Margin="33,10,0,10"/>

                </StackPanel>

                <Button Content="Get Directions" Click="RouteBtn_Click"

                       HorizontalAlignment="Right"/>

 

                <!-- Geocode Results Panel -->

                <ListBox Name="GeocodeResults"

                        SelectionChanged="GeocodeResultSelected" Margin="0,10,0,0">

                    <ListBox.ItemTemplate>

                        <DataTemplate>

                            <TextBlock Text="{Binding Name}"/>

                        </DataTemplate>

                    </ListBox.ItemTemplate>

                </ListBox>

 

                <!-- Route Itinerary Panel -->

                <StackPanel Name="RouteResults">

                    <ListBox ItemsSource="{Binding RouteLegs}">

                        <ListBox.ItemTemplate>

                            <DataTemplate>

                                <ListBox ItemsSource="{Binding ItineraryItems}">

                                    <ListBox.ItemTemplate>

                                        <DataTemplate>

                                            <StackPanel Orientation="Horizontal">

                                                <TextBlock Text="{Binding Instruction.Text}"

                                                          TextWrapping="Wrap" Width="200"/>

                                                <TextBlock Text="{Binding TravelDistance}"

                                                          Margin="10,0,0,0" />

                                                <TextBlock Text="km"/>

                                            </StackPanel>

                                        </DataTemplate>

                                    </ListBox.ItemTemplate>

                                </ListBox>

                            </DataTemplate>

                        </ListBox.ItemTemplate>

                    </ListBox>

                </StackPanel>

            </StackPanel>

        </ScrollViewer>

 

        <!-- Map Area -->

        <m:Map Name="MyMap" Grid.Column="1" Credentials="YOUR_BING_MAPS_KEY"/>

    </Grid>

</Page>

If you create the event handlers for the buttons and the GeocodeResultsListBox you can then run the application to see what it looks like. You should end up with something like this:

wsLayout

Adding the Application Logic

Open up the MainPage.xaml.cs file. In here we will create a global MapShapeLayer variable called routeLayer inside the MainPage class. We will use this shape layer to display the route line on the map. In the constructor of the MainPage class we will initialize this variable and add it to the map. At this point, the MainPage.xaml.cs file will look like this:

using Bing.Maps;

using BingMapsRESTService.Common.JSON;

using System;

using System.Runtime.Serialization.Json;

using System.Threading.Tasks;

using Windows.UI;

using Windows.UI.Popups;

using Windows.UI.Xaml;

using Windows.UI.Xaml.Controls;

using Windows.UI.Xaml.Media;

using Windows.UI.Xaml.Navigation;

 

namespace BingMapsSearch_WinRT_CS

{

    publicsealedpartialclassMainPage : Page

    {

        privateMapShapeLayer routeLayer;

 

        public MainPage()

        {

            this.InitializeComponent();

 

            routeLayer = newMapShapeLayer();

            MyMap.ShapeLayers.Add(routeLayer);

        }

 

        protectedoverridevoid OnNavigatedTo(NavigationEventArgs e)

        {

        }

    }

}

There are a few other common methods that we will want to add to this file to make things a bit easier and keep the code clean. The first common task we will want to do is notify the user if there is an error with their request. In .NET we would normally use the MessageBox class, but this is not available to Windows Store applications. Instead, we have to use the MessageDialog class. This class has a lot more options than we need, so to keep things simple, we will create a method that takes in a string message and displays it to the user. We will call this method ShowMessage and use the following code:

privateasyncvoid ShowMessage(string message)

{

    MessageDialog dialog = newMessageDialog(message);

    await dialog.ShowAsync();

}

The second common task is to call the Bing Maps REST service and then serialize the response into a BingMapsRESTService.Common.JSON.Response object. This class comes from the data contracts we copied in from MSDN documentation on Using the REST services with .NET. In that blog post we made use of the WebClient class to make our request to the service. In Windows Store applications we do not have access to this class and instead make use of the System.Net.Http.HttpClient class. We will call this common method GetResponse and use the following code:

privateasyncTask<Response> GetResponse(Uri uri)

{

    System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();

    var response = await client.GetAsync(uri);

 

    using (var stream = await response.Content.ReadAsStreamAsync())

    {

        DataContractJsonSerializer ser = newDataContractJsonSerializer(typeof(Response));

        return ser.ReadObject(stream) asResponse;

    }

}

In this last common method, we will clear the map and the results panels of our application. The map has to be cleared before we process any new requests. We will also need this functionality for the clear map button. We will call this method ClearMap and use the following code:

privatevoid ClearMap()

{

    MyMap.Children.Clear();

    routeLayer.Shapes.Clear();

 

    //Clear the geocode results ItemSource

    GeocodeResults.ItemsSource = null;

 

    //Clear the route instructions

    RouteResults.DataContext = null;

}

We can now add the button handler for the Clear Map button. All this button handler will do is call our ClearMap method. The handler will look like this:

privatevoid ClearMapBtn_Click(object sender, RoutedEventArgs e)

{

    ClearMap();

}

Adding the Geocoding Logic

We can now add the geocoding logic to the MainPage.xaml.cs file. When the user presses the geocode button we will get their input and check that it is a valid string. If it is, we will then create the URL to geocode the query against the Bing Maps REST Location service and then pass this URL to our GetResponse method. Next, we will display all the locations results on the map as pushpins and add a tap event that will trigger the name of the location to be displayed to the user. We will also pass the results to the GeocodeResults ListBox which will list the location results in the side panel. The GeocodeBtn_Click event handler will look like this:

privateasyncvoid GeocodeBtn_Click(object sender, RoutedEventArgs e)

{

    ClearMap();

 

    string query = GeocodeTbx.Text;

 

    if (!string.IsNullOrWhiteSpace(query))

    {

        //Create the request URL for the Geocoding service

        Uri geocodeRequest = newUri(

            string.Format("http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1}",

            query, MyMap.Credentials));

 

        //Make a request and get the response

        Response r = await GetResponse(geocodeRequest);

 

        if (r != null&&

            r.ResourceSets != null&&

            r.ResourceSets.Length > 0 &&

            r.ResourceSets[0].Resources != null&&

            r.ResourceSets[0].Resources.Length > 0)

        {

            LocationCollection locations = newLocationCollection();

 

            int i = 1;

 

            foreach (BingMapsRESTService.Common.JSON.Location l

                     in r.ResourceSets[0].Resources)

            {

                //Get the location of each result

                Bing.Maps.Location location =

                      new Bing.Maps.Location(l.Point.Coordinates[0], l.Point.Coordinates[1]);

 

                //Create a pushpin each location

                Pushpin pin = newPushpin(){

                    Tag = l.Name,

                    Text = i.ToString()

                };

 

                i++;

 

                //Add a tapped event that will display the name of the location

                pin.Tapped += (s, a) =>

                {

                    var p = s asPushpin;

                    ShowMessage(p.Tag asstring);

                };

 

                //Set the location of the pushpin

                MapLayer.SetPosition(pin, location);

 

                //Add the pushpin to the map

                MyMap.Children.Add(pin);                     

 

                //Add the coordinates of the location to a location collection

                locations.Add(location);

            }

 

            //Set the map view based on the location collection

            MyMap.SetView(newLocationRect(locations));

 

            //Pass the results to the item source of the GeocodeResult ListBox

            GeocodeResults.ItemsSource = r.ResourceSets[0].Resources;

        }

        else

        {

            ShowMessage("No Results found.");

        }

    }

    else

   {

        ShowMessage("Invalid Geocode Input.");

    }

}

Next, we will add a SelectionChanged event to the ListBox. When triggered, it will call a method named GeocodeResultSelected. This method will zoom in to the selected location. The following code will be used for this method:

privatevoid GeocodeResultSelected(object sender, SelectionChangedEventArgs e)

{

    var listBox = sender asListBox;

 

    if (listBox.SelectedItems.Count > 0)

    {

        //Get the Selected Item

        var item = listBox.Items[listBox.SelectedIndex]

                   as BingMapsRESTService.Common.JSON.Location;

 

        //Get the items location

        Bing.Maps.Location location =

               new Bing.Maps.Location(item.Point.Coordinates[0], item.Point.Coordinates[1]);

 

        //Zoom into the location

        MyMap.SetView(location, 18);

    }

}

If you run the application and do a search for “London” your application should look like this:

wsGeo

Adding the Routing Logic

We can now add the routing logic to the MainPage.xaml.cs file. When the user presses the “Get Directions” button we will first get their input locations and check that they are valid strings. If they are valid, we will create the URL to get the driving route between the two locations and pass this URL to our GetResponse method. Next, we will display the route line on the map along with a pushpin for the start and end points. We will also display the route itinerary items in a ListBox in the side panel. The RouteBtn_Click event handler will look like this:

privateasyncvoid RouteBtn_Click(object sender, RoutedEventArgs e)

{

    ClearMap();

 

    string from = FromTbx.Text;

    string to = ToTbx.Text;           

 

    if (!string.IsNullOrWhiteSpace(from))

    {

        if (!string.IsNullOrWhiteSpace(to))

        {

            //Create the Request URL for the routing service

            Uri routeRequest = newUri(                string.Format("http://dev.virtualearth.net/REST/V1/Routes/Driving?wp.0={0}&wp.1={1}&rpo=Points&key={2}", from, to, MyMap.Credentials));

                   

            //Make a request and get the response

            Response r = await GetResponse(routeRequest);

 

            if (r != null&&

                r.ResourceSets != null&&

                r.ResourceSets.Length > 0 &&

                r.ResourceSets[0].Resources != null&&

                r.ResourceSets[0].Resources.Length > 0)

            {

                Route route = r.ResourceSets[0].Resources[0] asRoute;

 

                //Get the route line data

                double[][] routePath = route.RoutePath.Line.Coordinates;

                LocationCollection locations = newLocationCollection();

 

                for (int i = 0; i < routePath.Length; i++)

                {

                    if (routePath[i].Length >= 2)

                    {

                        locations.Add(new Bing.Maps.Location(routePath[i][0],

                                      routePath[i][1]));

                    }

                }

 

                //Create a MapPolyline of the route and add it to the map

                MapPolyline routeLine = newMapPolyline()

                {

                    Color = Colors.Blue,

                    Locations = locations,

                    Width = 5

                };

 

                routeLayer.Shapes.Add(routeLine);

 

                //Add start and end pushpins

                Pushpin start = newPushpin()

                {

                    Text = "S",

                    Background = newSolidColorBrush(Colors.Green)

                };

 

                MyMap.Children.Add(start);

                MapLayer.SetPosition(start,

                    new Bing.Maps.Location(route.RouteLegs[0].ActualStart.Coordinates[0],

                        route.RouteLegs[0].ActualStart.Coordinates[1]));

 

                Pushpin end = newPushpin()

                {

                    Text = "E",

                    Background = newSolidColorBrush(Colors.Red)

                };

 

                MyMap.Children.Add(end);

                MapLayer.SetPosition(end,

                    new Bing.Maps.Location(route.RouteLegs[0].ActualEnd.Coordinates[0],

                    route.RouteLegs[0].ActualEnd.Coordinates[1]));

 

                //Set the map view for the locations

                MyMap.SetView(newLocationRect(locations));

 

                //Pass the route to the Data context of the Route Results panel

                RouteResults.DataContext = route;

            }

            else

            {

                ShowMessage("No Results found.");

            }

        }

        else

        {

            ShowMessage("Invalid 'To' location.");

        }

    }

    else

    {

        ShowMessage("Invalid 'From' location.");

    }

}

At this point, we have accomplished all that we set out to do in this blog post. If you run the application now and calculate a route from “New York” to “Miami” you should end up with something like this:

wsRoute

- Ricky Brundritt, EMEA Bing Maps Technology Solution Professional

Overview of Bing Maps SDK for Windows Store apps in just one minute

$
0
0

Check out the new One dev minute video and tutorial that takes you through all the steps you need to display your location on a map in a C# Windows Store app using the Bing Maps for Windows Store apps SDK. Simple clear instructions take you from signing up for a Trial or Basic Windows Store app Bing Maps key [also see http://www.microsoft.com/maps for more details about key types] to creating the project and adding the map – it’s all there and you can rewind and review as much as you need as well as check out the detailed written tutorial steps. And if you want to go straight to the code, you can get it here.

-The Bing Maps Team

Geocoding Dynamics CRM Data with Bing Maps

$
0
0

The majority of data in the enterprise today has a location component, and this includes much of the entity data in Dynamics CRM. We can leverage the location attributes of our CRM data to provide a wide variety of location-based functionality, including geospatial visualization, finding nearest service agents to jobs, optimizing routes for mobile sales people, analyzing our data in heat maps and thematic maps, and much more. One of the fundamentals required to be able to leverage this location data is the “geocoding” of our location data. Geocoding is the process of taking text-based location data such as addresses or place names, and turning them into geographic coordinates. With accurate geographic coordinates (or latitudes and longitudes) for our entities, we can visualize them on a map, and analyze them spatially. In this blog post, we will review options available for geocoding Dynamics CRM data, including:

● Batch geocoding with Spatial Data Services

● Geocoding via Dynamics CRM Plug-ins

We will be working with:

Dynamics CRM Online

● Excel 2013

● Visual Studio 2010

● The Developer Toolkit for Microsoft Dynamics CRM 2011 and Microsoft Dynamics CRM Online

● The Plug-in Registration Tool from the Microsoft Dynamics CRM SDK download

● A Bing Maps Account that has access to the Bing Maps Spatial Data Services

Batch Geocoding with Spatial Data Services:

We will first walk through the steps involved in geocoding entity data that is already contained within our CRM instance with the use of the Bing Maps Spatial Data Services Geocode Dataflow API. At a high level, we will be exporting entity data using the Dynamics CRM Web Client, geocoding the data using the Geocode Dataflow API, and then re-importing the data with latitudes and longitudes appended to each record.

In this example, we will geocode all Account records which have not already been geocoded. We start by logging into Dynamics CRM Online, selecting Accounts from the left navigation, and then selecting Advanced Find from the Data group on the Accounts tab of the ribbon.

In the resulting window, create a New query, and select Account records in which either the address Latitude or Longitude do not have data:

CRM 1

Now select Edit Columns for the View, and choose those representing the Street, Town, State/Province, ZIP/Postal Code, Country/Region, Latitude, and Longitude of the account address you wish to geocode:

CRM 2

Rearrange the order of the columns as shown below by selecting a column header and using the green arrow buttons:

CRM 3

Now execute your query to view the results by selecting Results. Once the results are displayed, Choose ‘Data… Export Accounts’ from the ribbon:

CRM 4

Choose to export to a ‘Static worksheet’, with data from all pages in the current view, if applicable. Make sure you select the checkbox to ‘Make the data available for re-importing’

CRM 5

When prompted, save the resulting XML Spreadsheet file to your machine, rather than opening it directly. Now open the file in Excel. Note that there are several hidden columns, including column A, which contains a unique ID for each record, along with the columns D through H which contain the address data needed for geocoding. Unhide all columns:

CRM 6

We will now extract the relevant data from this spreadsheet, and create a second spreadsheet which we will use with the Bing Maps Spatial Data Services Geocode Dataflow API.

Since the console application we will use conforms to the Geocode Dataflow API Data Schema v1, we will arrange our data to conform to that. Our mapping of columns will be:

● Column A: Unique Account ID

● Column D: Street

● Column E: State / Province

● Column F: Country / Region

● Column I: Town

● Column J: ZIP / Postal Code

We will now save the spreadsheet as Text (Tab-delimited), ready for use with the sample console application.

Now use Visual Studio to create a Visual C# Console Application, and copy the code from the Geocode Dataflow Sample Code. If necessary, make two small tweaks to the sample code. To make it easy to open our geocoding output data in Excel, we will use the WriteLine() method of the StreamWriter class, instead of the Write() method, to include line breaks in the output data (successfile and failedfile). Build the application, in preparation for geocoding the data.

The Geocode Dataflow API uses a REST API to enable you to:

● HTTP POST up to 200,000 records per job

● Check the status of your job, to determine when it has completed

● Download the results

Our Console Application will handle the interactions with the Geocode Dataflow API for us.

The Console Application takes in four parameters:

dataFilePath: The path to the file that contains the spatial data to geocode

dataFormat: The format of the input data. Possible values are xml, csv, tab and pipe. We are using tab format

key: The Bing Maps Key to use for this job. The same key is used to get job status and download results.

description: Text that is used to describe the geocode dataflow job.

Open up a Command Prompt, and execute the Console Application as shown below:

CRM 7

Upon completion, our geocoding output should be in a file named Success.txt in the current directory. Import this tab-delimited file into Excel, using UTF-8 encoding. The format of this file will conform to the Geocode Dataflow Schema v1.

The fields which will be of main interest to us will be these ones:

● GeocodeEntity/GeocodeResponse/RooftopLocation/@Latitude (Excel Column U)

● GeocodeEntity/GeocodeResponse/RooftopLocation/@Longitude (Excel Column V)

● GeocodeEntity/GeocodeResponse/InterpolatedLocation/@Latitude (Excel Column W)

● GeocodeEntity/GeocodeResponse/InterpolatedLocation/@Longitude (Excel Column X)

However, if you wish to be more selective about the geocoding results that you import into Dynamics CRM, you could use other fields as well. For example, you could choose to import only those results which returned an Address EntityType, with a High Confidence.

Generally speaking, unless we are using our latitudes and longitudes for routing purposes, we will want the Rooftop coordinates when available, and taking the Interpolated coordinates when Rooftop coordinates are not available.

We can now retrieve the most appropriate coordinates from our Success.txt file, and bring them into the Latitude and Longitude columns of our original spreadsheet. There are a number of options for doing this, but in this case, we use the VLOOKUP function in Excel to retrieve the coordinates from the appropriate record in the Success.txt file. If Rooftop coordinates are available, we use them, and if they are not, we use the Interpolated coordinates. If neither is available, or if the VLOOKUP fails, we leave the cell blank. The actual Excel formula used to populate the Latitude column for row 2 is:

=IF(ISERROR(VLOOKUP(A2,Success.txt!$A$1:$AB$6,21,FALSE)),"",IF(VLOOKUP(A2,Success.txt!$A$1:$AB$6,21,FALSE)<>"",VLOOKUP(A2,Success.txt!$A$1:$AB$6,21,FALSE),IF(VLOOKUP(A2,Success.txt!$A$1:$AB$6,23,FALSE)<>"",VLOOKUP(A2,Success.txt!$A$1:$AB$6,23,FALSE),"")))

 

For longitude, we simply add one to the Column Index Number values of each VLOOKUP.

Now convert the formulas to values by highlighting the Latitude and Longitude cells, copying the data, and then Paste Values in the same cells.

After saving, we now have an updated Excel file ready for re-import to Dynamics CRM, with coordinates for our records:

CRM 8

Now we log back into Dynamics CRM Online, and select Accounts from the navigation. From the Accounts tab of the ribbon, choose Import Data from the Data group. In the resulting window, select the location of the XML Spreadsheet file containing our updates.

When prompted, select No for Allow Duplicates, and click Submit:

CRM 9

The data will now be imported, with Latitudes and Longitudes appended to the relevant records in Dynamics CRM.

Geocoding via Plugins

We will now walk through the process of creating a Dynamics CRM Plug-in which will enable CRM entity data to be geocoded whenever a new entity is added or updated. Our MSDN documentation describes a plug-in as custom business logic (code) that you can integrate with Microsoft Dynamics CRM 2011 and Microsoft Dynamics CRM Online to modify or augment the standard behavior of the platform. In our case, our plug-in will leverage the REST Locations API to geocode the address of any new accounts that are added or existing accounts that are updated, adding the resulting Latitude and Longitude to the record.

In Visual Studio, we will create a new Project, and will select a Dynamics CRM 2011 Package using Visual C#:

CRM 10

We are now prompted to Connect to Dynamics CRM Server. Since we are using Dynamics CRM Online, we enter dev.crm.dynamics.com as our CRM Discovery Server Name. We also enter our Microsoft account credentials for authentication:

CRM 11

We now add a new C# Dynamics CRM 2011 Plug-in Library project to our package:

CRM 12

We will now add a Visual C# Class to our GeocodeAccountsPlugin, called GeocodeAccounts.cs. In this class, we will add our code to read the address data from an Account record, geocode the address data using the REST Locations API, and then update the Latitude and Longitude of the Account record if a successful geocoding result is obtained.

When we register our plug-in, we will have execution take place post-operation, and asynchronously, for performance reasons. We will register and make use of a Post Image of our entity, which is effectively a reflection of the Account attributes once the Account Create or Update operation has completed.

The logic of our plug-in can be summarized as:

● The Account address details are retrieved from the Post Image

● The address details are used to prepare a URL for a request to the Bing Maps Locations API, specifying an XML response format

● The request is executed and the response retrieved with the use of the HttpWebRequest class

● The XML response is parsed and the Latitude and Longitude values of the first geocoding result are retrieved using XPath

● The Latitude and Longitude of the Account record are updated using IOrganizationService.Update()

namespace GeocodeAccountsPackage.GeocodeAccountsPlugin

{

    using System;

    using System.ServiceModel;

    using Microsoft.Xrm.Sdk;

    using System.Xml;

    using System.Net;

    using System.Xml.XPath;

 

    ///<summary>

    /// Geocode Account Plugin.

    /// Fires on Create of Account, or Update of Account address properties

    ///</summary>   

    publicclassGeocodeAccounts : IPlugin

    {

        privatereadonlystring postImageAlias = "PostImage";

        privatereadonlystring BingMapsKey = "Insert Key Here";

 

        publicvoid Execute(IServiceProvider serviceProvider)

        {

            // Obtain the execution context from the service provider.

            Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)

                serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

 

            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

 

            // Obtain the post entity image:

            Entity postImage = (Entity)context.PostEntityImages[postImageAlias];

 

            // The InputParameters collection contains all the data passed in the message request.

            if (context.InputParameters.Contains("Target") &&

                context.InputParameters["Target"] isEntity)

            {

                // Obtain the target entity from the input parmameters.

                Entity entity = (Entity)context.InputParameters["Target"];

 

                // Verify that the target entity represents an account.

                if (entity.LogicalName == "account")

                {

                    try

                    {

 

                        // Grab the postImage address attributes for our geocoding request:

                        string addressLine = (postImage.Attributes.ContainsKey("address1_line1")) ? (string)postImage.Attributes["address1_line1"] : "";

                        string locality = (postImage.Attributes.ContainsKey("address1_city")) ? (string)postImage.Attributes["address1_city"] : "";

                        string adminDistrict = (postImage.Attributes.ContainsKey("address1_stateorprovince")) ? (string)postImage.Attributes["address1_stateorprovince"] : "";

                        string postalCode = (postImage.Attributes.ContainsKey("address1_postalcode")) ? (string)postImage.Attributes["address1_postalcode"] : "";

                        string countryRegion = (postImage.Attributes.ContainsKey("address1_country")) ? (string)postImage.Attributes["address1_country"] : "";

 

                        //Get latitude and longitude coordinates for specified location

                        XmlDocument searchResponse = Geocode(addressLine, locality, adminDistrict, postalCode, countryRegion);

 

                        //Create namespace manager

                        XmlNamespaceManager nsmgr = newXmlNamespaceManager(searchResponse.NameTable);

                        nsmgr.AddNamespace("rest", "http://schemas.microsoft.com/search/local/ws/rest/v1");

 

                        //Get all geocode locations in the response

                        XmlNodeList locationElements = searchResponse.SelectNodes("//rest:Location", nsmgr);

                        if (locationElements.Count == 0)

                        {

                            // No geocoding results, so do nothing

                        }

                        else

                        {

                            //Get the geocode location points that are used for display (UsageType=Display)

                            XmlNodeList displayGeocodePoints =

                                    locationElements[0].SelectNodes(".//rest:GeocodePoint/rest:UsageType[.='Display']/parent::node()", nsmgr);

                            string latitude = displayGeocodePoints[0].SelectSingleNode(".//rest:Latitude", nsmgr).InnerText;

                            string longitude = displayGeocodePoints[0].SelectSingleNode(".//rest:Longitude", nsmgr).InnerText;

 

                            Entity account = newEntity("account");

                            account.Attributes.Add("accountid", entity.Attributes["accountid"]);

                            account.Attributes.Add("address1_latitude", double.Parse(latitude));

                            account.Attributes.Add("address1_longitude", double.Parse(longitude));

                            service.Update(account);

 

                        }

 

                    }

                    catch (FaultException<OrganizationServiceFault> ex)

                    {

                        thrownewInvalidPluginExecutionException("An error occurred in the Account Update plug-in.", ex);

                    }

                }

            }

        }

 

 

        // Submit a REST Services or Spatial Data Services request and return the response

        protectedXmlDocument GetXmlResponse(string requestUrl)

        {

 

            HttpWebRequest request = WebRequest.Create(requestUrl) asHttpWebRequest;

            using (HttpWebResponse response = request.GetResponse() asHttpWebResponse)

            {

                if (response.StatusCode != HttpStatusCode.OK)

                    thrownewException(String.Format("Server error (HTTP {0}: {1}).",

                    response.StatusCode,

                    response.StatusDescription));

                XmlDocument xmlDoc = newXmlDocument();

                xmlDoc.Load(response.GetResponseStream());

                return xmlDoc;

            }

        }

 

        // Geocode an address and return the XML response:

        protectedXmlDocument Geocode(string addressLine, string locality, string adminDistrict, string postalCode, string countryRegion)

        {

            //Create REST Services geocode request using Locations API

            string geocodeRequest = String.Format("https://dev.virtualearth.net/REST/v1/Locations?countryRegion={0}&adminDistrict={1}&locality={2}&postalCode={3}&addressLine={4}&o=xml&key={5}",

                System.Uri.EscapeDataString(countryRegion),

                System.Uri.EscapeDataString(adminDistrict),

                System.Uri.EscapeDataString(locality),

                System.Uri.EscapeDataString(postalCode),

                System.Uri.EscapeDataString(addressLine),

                BingMapsKey);

 

            //Make the request and get the response

            XmlDocument geocodeResponse = GetXmlResponse(geocodeRequest);

 

            return (geocodeResponse);

        }

 

 

    }

}

 

 

After successfully building, we will sign the assembly, through the plug-in Properties…Signing (shown below) and then build in preparation for registering our plug-in:

CRM 13

We will now register our plug-in, using the process outlined in the Walkthrough: Register a Plug-in Using the Plug-in Registration Tool on MSDN (you can refer to this article for additional step-by-step information).

We run the Plug-in Registration tool, connect to the Dynamics CRM Online server, and then register our plug-in assembly:

CRM 14

We can follow the step-by-step instructions in the MSDN walkthrough to Register a Plug-in Assembly.

Next, we will register the plug-in for two events: Account Create and Account Update.

In each case, we will select (Assembly) GeocodeAccountsPackage.GeocodeAccountsPlugin in the tree view, and then select Register New Step from the Register menu.

For the Account Create event, we will select the following options:

CRM 15

For the Account Update event, we will select very similar options, adding in Filtering Attributes to ensure the plug-in is only executed on update when the address details for the account change. The Filtering Attributes used will be:

● Street 1 (address1_line1)

● City (address1_city)

● State/Province (address1_stateorprovince)

● ZIP/Postal Code (address1_postalcode)

● Country/Region (address1_country)

CRM 16

We will now Register a New Image for each step, to give us access to the address details of the Account after the Create and Update operations have executed. We specify an Entity Alias (‘PostImage’) which matches the Post Image alias we referenced in our plug-in code. Note how we specify only the address attributes for the Parameters, as these will be used when geocoding the address:

CRM 17

We register images for both the Create and Update steps.

Our Tree View in the Plug-in Registration Tool should now look like this:

CRM 18

We are now ready to add new account records, and update existing account records through the Dynamics CRM Online Web Application, to verify that our plug-in is geocoding the respective addresses. Note that because our plug-in is executing asynchronously after execution of the creation or update of our Accounts, the new Latitude and Longitude values may not necessarily be reflected immediately. After we reopen a newly created or updated record, we should see the new Latitude and Longitude values reflected.

CRM 19

Other Geocoding Options

In addition to geocoding via batch jobs, and via plug-ins, some other options that could be explored include:

● Geocoding individual addresses through HTML Web Resources in forms with the AJAX v7 map control and Search module

● Geocoding individual addresses through Form Scripting using the Bing Maps Locations API

Once our Dynamics CRM Accounts and other entities are geocoded, we can start to take advantage of your location data to find nearby accounts, create optimized itineraries, visualize data in specific territories or areas, and much more. For information on how to create a heat map of our data in Dynamics CRM, see my previous post on this topic.

The code for the GeocodeAccounts.cs class and the Geocode Dataflow console application can be found here

-Geoff Innis, Bing Maps Technical Specialist

New to REST Services: Elevations API

$
0
0

We are happy to announce the release of Elevations API as the latest addition to the Bing Maps REST Services offerings. The Elevations API will enable you to query for elevation information for a set of points, polyline or a region on the Earth described by latitude and longitude pairs.

Here are some example use cases for this API. Let’s say you have a sports GPS tracking device that tracks your distance, speed and elevation while you are on a hike. In this scenario, the Elevations API can be used to provide you with elevation information at specific points during the hike. In another scenario, you can visualize the elevation profile along a pre-determined route. And, of course, if you want to get fancy with 3D, you now have the opportunity to develop 3D elevation models for an area on the Earth.

Currently elevation information is available with the following resolutions: Global Coverage (including poles): 900m resolution (Globe), Global Coverage (56⁰S to 60⁰N):90m resolution (SRTM).US coverage: 10m resolution (NED).

One of the interesting features of this API is the ability to provide elevation data for a region on the Earth or bounding box. With this feature, you can fine-tune the number of elevation points you get back for the bounding box. To give you even more flexibility for your scenarios, the elevation values can be calculated using two different Earth models -- the ellipsoid model and the geoid sea level model. The ellipsoid model uses the World Geodetic System (WGS84) which is an ellipsoidal approximation of the Earth. The geoid sea level model uses the Earth Gravitational Model 2008 (EGM2008 2.5’) and computes a sea level based on the local value of gravity. The ellipsoid model is equivalent to GPS and the geoid sea level model is equivalent to what is commonly known as the height above sea level.

The detailed documentation for this service can be found here.

John O’Brien, director of Soul Solutions, is a Bing Maps MVP and was part of the first look into the new service. It was really cool to see John explore and provide an early preview into the applicable use of our elevation service API which also provided new solutions for his clients. Below are just two examples of how the elevation API is helping John address the needs of his clients.

Firstly, a simple example where you can drag two pins around the map and see the profile of the terrain between them

Elevation 1

The second, using the existing direction module to plot a course by car then visualize the elevation change.

Elevation 2

The V7 AJAX module John built provides an option for developers to add this functionality with a few lines of code. You can download the module plus the example code for the images here.

-The Bing Maps Team

Bing Maps for Windows Store Apps Training Kit

$
0
0

Bing Maps for Windows Store apps combine the power of Windows 8 and Bing Maps to provide an enhanced mapping experience for Windows Store apps. Developers can use this Bing Maps control to incorporate the latest road maps, aerial views, and low-angle high-resolution images into a Windows Store app.

Today we are happy to announce the release of the Bing Maps for Windows Store Apps Training Kit. This training kit is made up of a PowerPoint slide deck which serves as an overview to create a Windows Store App using Bing Maps. The slide deck also includes information on existing applications which use Bing Maps that are in the Windows Store. In addition to the training deck there are 2 labs. The first has been designed for the JavaScript developer and the second, for the Native code developer. Each lab is made up of multiple exercises and should take around 90 minutes to complete.

JavaScript Lab:

* Exercise 1: Creating a Bing Maps Account and Key

* Exercise 2: Loading the Bing Maps control

* Exercise 3: Integrating Location Services

* Exercise 4: Implement Bing Maps Modules

* Exercise 5: Implementing Geocoding and Routing

* Exercise 6: Access the Bing Maps REST Services

Native Lab:

* Exercise 1: Creating a Bing Maps Account and Key

* Exercise 2: Loading the Bing Maps control

* Exercise 3: Integrating Location Services

* Exercise 4: Implementing Geocoding and Routing

You can download the Bing Maps for Windows Store Apps Training Kit here.

- Ricky Brundritt, EMEA Bing Maps Technology Solution Professional

Viewing all 102 articles
Browse latest View live