Skip navigation

Got Maps? - 30 Oct 2009

Develop a Map-centric Web Application in Silverlight

INETA Community Voices

LANGUAGES: C#

ASP.NET VERSIONS: 3.5

 

Got Maps?

Develop a Map-centric Web Application in Silverlight

 

By Al Pascual

 

One routine task for developers is the creation of reports to analyze data. One of the shortcomings of this task, however, is the inability to analyze the information in different formats to fulfill different requirements. The analysis of variable data requires that some information be presented to the user within a formatted table or graphical chart. Ideally, data should be visualized or represented in a geographic context so it can enable queries and be manipulated. There is huge value in visualizing tabular data on a map. For example, population data of the US could be viewed in a table or chart, but the data could be overwhelming. Maps, on the other hand, allow the user to examine the geographic context of the data and easily identify trends.

 

The best way to present the user with a huge amount of information is in a geographic context. To achieve these results, one needs Microsoft technologies ASP.NET, the .NET 3.5 Framework, Silverlight, and JavaScript combined with ArcGIS Server 9.3 and the REST API for visualization of the data.

 

To demonstrate how to build a map viewer in Silverlight, this article will use the MultiScaleImage provided with Silverlight 2 beta 2.0.30523. With the Silverlight map viewer, users will be able to create a Web page and add their local georeferenced data or live data, creating a GeoRSS feed using GeoTwitter. This guide will also help users extend the control using C# and interact with the Silverlight map viewer control using JavaScript.

 

What Is Geographic Information System Technology?

Geographic Information System (GIS) technology allows us to view, understand, question, interpret, and visualize data in many ways that reveal relationships, patterns, and trends in the form of maps, globes, reports, and charts. GIS helps answer questions and solve problems by looking at data in a way that is quickly understood and easily shared.

 

Configuring Solutions through Mashups

In the past few years, mashup has become a word familiar to most developers (and to a lesser extent, the general public). A mashup is the keystone to service-oriented architecture, allowing developers to publish content using one or more remote service. The mashup became famous when Google published its online mapping API. Overnight, anyone with a glimmer of JavaScript talent could publish their data on a map on their Web site in just a few lines of code. In the past few years, APIs have been used to display information on top of free visualization map applications, such as Virtual Earth and Google Maps.

 

Introduction to the ESRI ArcGIS Server REST API

Because I am most familiar with ArcGIS Server, this is what I used for this article. However, other products are available, such as Google Maps (http://maps.google.com) and Microsoft Virtual Earth (http://maps.live.com).

 

ArcGIS Server 9.3 comes with a .NET API for ASP.NET and the flexible REST API that allows you to develop your own viewer; this article will use the latest build of the Silverlight map viewer. The Silverlight map viewer and JavaScript API take advantage of the REST API in ArcGIS Server to consume and query map data. The REST API is stateless and does not store transaction requests. To retrieve information you can use the ArcGIS online at http://sampleserver1.arcgisonline.com/ArcGIS/rest/services.

 

ArcGIS Online is a cluster of servers, available on the Internet, with cached base maps and resources. You can see the resources in HTML, JSON, or KML. Sampleserver1.arcgisonline will be used for all the samples in this guide.

 

The world map extent will be referenced often throughout this guide to describe the four points that describe the four corners of the map, using the most common latitude/longitude measurement for maps. For help and documentation of the REST API for ArcGIS Server 9.3, visit http://resources.esri.com/help/9.3/arcgisserver/apis/rest/index.html.

 

Share Geographic Information Using GeoRSS

There are many formats to publish map services, most of which are image-based to provide a geographic base map. Because sharing information is easier because of expanded bandwidth and storage, many new formats allow users to share geographic information that can be displayed in any base map. There is a downside to these new formats: being file-based, users must fetch the file again to update the map. RSS feeds eliminate this hassle. GeoRSS (Geographic Really Simple Syndication) provides access to an up-to-date source of geographically tagged information.

 

With RSS, users subscribe to a feed, which is time sorted, and the client or aggregator is the one requesting the updated feed using the last one fetched. RSS is a format of XML. GeoRSS works the same way, extending the format to include a point or collection of points to generate a polyline or polygon. There are different formats of GeoRSS; this article will only reference Simple GeoRSS.

 

Subscribing to a GeoRSS feed means receiving to your application the updated geometry in real time and creating a layer of that geometry that any map viewer supporting GeoRSS can consume in real time. For example, you can keep track of the changes in a hurricane or car accidents in real time. Figure 1 demonstrates how to generate a GeoRSS feed and consume it in Google Maps. There are a few GeoRSS editors online for you to quickly sketch your geographic information. I recommend using an editor like the GeoTwitter Editor (see Figure 2; http://geotwitter.net/editor.aspx).

 


Figure 1: Generate a GeoRSS feed and consume it in Google Maps.

 


Figure 2: The GeoTwitter Editor.

 

Although there are many ways to parse RSS in .NET, in this article we ll parse GeoRSS. To convert it into points, this guide will parse GeoRSS in C#, VB.NET, and JavaScript. Any of these will be useful to add the points to the Silverlight map viewer.

 

The Silverlight Map Viewer Using MultiScaleImage

ESRI has released a Silverlight 2.0 beta 2 viewer proof of concept on their resource page, created by Richie Carmichael; download the source code from http://resources.esri.com/arcgisserver/adf/dotnet/index.cfm?fa=codeGalleryDetails&scriptID=15746.

 

The control was built using the MultiScaleImage control, also known as DeepZoom. The control uses the REST API to construct URLs to individual map image tiles and pass them to the MultiScaleImage control. DeepZoom provides panning, zoom in, and zoom out capability, as well as the spring animation feature, an animation effect that makes the DeepZoom control appealing to most users. In the first version of the MultiScaleImage, developers had to create a zoomable image using the DeepZoom Composer. With the release of Silverlight 2.0 beta 2, developers can create a provider to consume any other images not prepared by the DeepZoom Composer.

 

In these exercises, we are going to consume GeoRSS and add it as points to the Silverlight map control. The sample will also contain a location service.

 

We then can add the control to an HTML page or .NET Web Form, as Silverlight downloads into your browser from the server as a browser plug-in (see Figure 3). In Listing One, the control is added to an HTML page and provides a map of the world, with pan and zoom in/out, attaching to the mouse events in the browser. You can download the code from http://alpascual.com/files/folders/2776/download.aspx.

 


Figure 3: The Silverlight map viewer control on an HTML page.

 

With the code from Listing One, it is very easy to add the control to an HTML page. The object for Silverlight is simply dropped into the page, and, if installed in your browser, the plug-in will be initialized; if not, you ll be asked to download the Silverlight plug-in from Microsoft before running the xap file. (Adding the Silverlight map viewer to your Web page is very straightforward. If Silverlight is not installed on the target computer, the user will be prompted to install Silverlight from the Microsoft Web site.)

 

If we look into the Silverlight control, we can see how MultiScaleImage requests that the different map images tile upon the mouse events using the ESRI REST API. Keeping track of the map extent is done in the Silverlight control rather than the server; the REST API, as previously discussed, is stateless and does not know the last extent of the map. The Silverlight map control includes only the MultiScaleImage control, which provides the springing effect when panning out of the box, as well as a smooth transition between tiles. To do a mashup of two or more map services, you can use multiple MultiScaleImage controls with different transparencies in the image. All the maps must use the same projection.

 

In the code-behind we attached all the mouse events to retrieve the correct image from the ArcGIS server 9.3 using the REST API. The control will take care of the image transitions, as well as the zoom in/out animation. The server returns JSON strings that are being desterilized to C# classes with all the image attributes and properties. To demonstrate this technique, the code in Figure 4 shows how to create an instance of the control.

 

MultiScaleImage msi = this.map.Children[0] as MultiScaleImage;

 if (msi == null) { return; }

 MapTileSource mts = msi.Source as MapTileSource;

 if (mts == null) { return; }

 ArcGISMapServiceLayer layer = (ArcGISMapServiceLayer)mts.Layer;

 double widthDegrees = layer.FullExtent.XMax - layer.FullExtent.XMin;

  Point origin = new Point();

 origin.X = (value.XMin - layer.FullExtent.XMin) / widthDegrees;

 origin.Y = (value.YMax - layer.FullExtent.YMax) / widthDegrees;

 double width = (value.XMax - value.XMin) / widthDegrees;

 msi.ViewportWidth = width;

 msi.ViewportOrigin = origin;

Figure 4: Create an instance of the MultiScaleImage control.

 

Silverlight Communication with ASP.NET and JavaScript

A key advantage of using the Silverlight control instead of a map div to display a map is that the plug-in does all the work with the image. This means the image will be rendered and processed faster using the Background worker thread from the Silverlight plug-in. It also means you can store images in the user s hard disk for later use, or to avoid a round trip with Silverlight isolated storage to the server to download it again.

 

Now that you ve included the Silverlight control in an HTML page, we re going to use the ArcGIS 9.3 JavaScript API as the SDK for Silverlight. We ll create a page to geocode any point from the Silverlight control, as well as use GeoRSS to place information in the Silverlight map.

 

JavaScript can easily communicate with Silverlight by using the method attribute (ScriptableMember) on the method you want to expose to JavaScript from inside Silverlight 2.0 beta 2. That wasn t true in previous versions of Silverlight. Normally, C# methods start with an uppercase letter, and JavaScript methods begin with a lowercase letter. You can use the proper ScriptAlias to expose the method for each platform to correct this case:

 

[ScriptableMember(ScriptAlias="graphics")]

   public Graphics Graphics

   {

      get { return _graphics; }

      set { _graphics = value; }

   }

 

The sample shown in Listing Two will use the GeoRSS parser to add points to the map. Using the JavaScript GeoRSS parser with a timer, the map viewer can always be up to date with the live GeoRSS feed and convert them to geometry points in Silverlight. You can download the complete code from http://alpascual.com/files/folders/2776/download.aspx.

 

The JavaScript to parse GeoRSS is shown in Listing Three; the complete file can be downloaded from http://pascual.com/files/folders/2776/download.aspx.

 

To use the JavaScript API from ArcGIS online, you need only to include the script, as shown in the sample below (the script will be downloaded to the browser from ArcGIS Online; the examples all use the JavaScript API version 1.1):

 

 

The JavaScript API is very robust and helps you develop a map viewer and execute tasks faster. The results are ideal for displaying a hefty amount of information in a simple geographic environment. Tool tips display the information of the item added into the map, making it very intuitive. GeoRSS information can be formatted in HTML and style sheets can be created to make a better presentation layer when the mouse is moved over the item.

 

A Deep Look into the Silverlight Map Control

You should download the code from the resource page at http://resources.esri.com (Richie Carmichael did a great job commenting the code). The Map.xaml contains the Silverlight UserControl where the MultiScaleImage would be created. The code in Figure 5 shows you the Silverlight UserControl containing the MultiScaleImage and the canvas to display the map.

 

 x:Class="ESRI.PrototypeLab.Silverlight.Map"

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

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

 >

 

   

       

       

   

   

      

       

   

   

     Grid.Row="0" Grid.RowSpan="2" />

   

     Grid.Row="0" Grid.RowSpan="2" />

   

    Grid.Column="1"

    Grid.Row="1"

    Margin="10,10,10,10"

     Background="Black"

    CornerRadius="20"

    Opacity="0.5">

      

        HorizontalAlignment="Center"

       VerticalAlignment="Center"

       FontFamily="Trebuchet MS"

       Foreground="White" />

   

 

Figure 5: Use the Silverlight UserControl with the MultiScaleImage and a canvas.

 

Looking at the code-behind, the control needs to hook to all mouse events needed for panning and zooming. You need to set the map extent, the part of the map you want to see, and the service to use. The WebClient class communicates with the server using JSON. You can download the complete code from http://resources.esri.com/arcgisserver/adf/dotnet/index.cfm?fa=codeGalleryDetails&scriptID=15746. Use the code shown in Figure 6 to initialize the events on the MultiScaleImage.

 

public Map() {

   InitializeComponent();

   // Clear Items

   this.grid.Height = double.NaN;

   this.grid.Width = double.NaN;

   //

   this.coordinates.Text = Map.BLANK_COORDINATE;

   // Handle Map Interaction

   this.map.MouseLeftButtonDown += new

     MouseButtonEventHandler(this.Map_MouseLeftButtonDown);

   this.map.MouseLeftButtonUp += new

     MouseButtonEventHandler(this.Map_MouseLeftButtonUp);

   this.map.MouseMove += new

     MouseEventHandler(this.Map_MouseMove);

   this.map.MouseLeave += new

    MouseEventHandler(this.Map_MouseLeave);

   this.map.ViewportChanged += new

     RoutedEventHandler(Map_ViewportChanged);

   // Handle Browser Event

   MouseWheelHelper mouseWheelHelper = new

    MouseWheelHelper(this.map);

   mouseWheelHelper.Moved += new

    EventHandler

     (this.MouseWheelHelper_Moved);

   //

   this.Loaded += new RoutedEventHandler(this.Map_Loaded);

 }

Figure 6: The Silverlight control constructor used to initialize all events in the map.

 

Use Geolocating to Display Results

Geolocating is the term used when you provide an address and the geolocator finds the coordinates that correspond to that address. Conversely, reverse geolocating is when the user provides a point (latitude and longitude) and the geolocator finds the address.

 

In the sample shown in Figure 7, we re going to add a button to the HTML page. Right-click the mouse to grab the clicked point of the map to find the address of those coordinates. As discussed previously, we ll use the ArcGIS Server 9.3 JavaScript API to construct the query to the server and return the results from the point in the Silverlight control that will be displayed in a JavaScript alert box to show the bidirectional communication built in to Silverlight 2.0 beta 2.

 

function ReveseGeocoder() {

  map.OnClick = "LocationOnClick";

  var infoTemplate = new esri.InfoTemplate("Address",

   "Street: ${Address} City: ${City} State: ${State}

    Zip: ${Zip}");

  var symbol = new esri.symbol.SimpleMarkerSymbol(

   esri.symbol.SimpleMarkerSymbol.STYLE_CIRCLE, 15,

    new esri.symbol.SimpleLineSymbol(esri.symbol.

   SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0, 0,

   255]), 2), new dojo.Color([0, 0, 255]));

  dojo.connect(locator, "onLocationToAddressComplete",

    function(candidate) {

      if (candidate.address) {

       var graphic = new esri.Graphic(candidate.location,

         symbol,

        candidate.address,

        infoTemplate);

        map.graphics.add(graphic);

       alert(graphic.getTitle() + graphic.getContent());

        // Create a infoWindow class

       map.infoWindow.setTitle(graphic.getTitle());

       map.infoWindow.setContent(graphic.getContent());

        var screenPnt = map.toScreen(candidate.location);

        map.infoWindow.show(screenPnt,

         map.getInfoWindowAnchor(screenPnt));

      }

   });

 }

Figure 7: Reverse geocoding an address.

 

The JavaScript locator method will use the REST API to process the point into the server; you can manually browse the REST API using the end point to test the locator. You can download the rest of the code from http://alpascual.com/files/folders/2776/download.aspx.

 

Conclusion

This article presents a simple way to add rich maps to your application and provide your users with a fast and rich interface to visualize your data in a geographic context. With a few simple lines, you can add to any Web page the Silverlight map with a few base maps from the ArcGIS online server and add dynamic data using other map services or GeoRSS for streaming live data to your Silverlight control.

 

Even while having an extended JavaScript API, as well as a .NET API that you can use out of the box with ArcGIS Server 9.3, if you would additionally like to replace your map for a Silverlight map, you can go to the resources page and download the code (http://resources.esri.com) or only the control to add it to your pages. There are many resources online to extend the Silverlight control to include many animations, events, and effects on the map control.

 

If you want to start using the Silverlight control immediately, I recommend you begin by downloading the code and compiling it on your computer.

 

Source code accompanying this article is available for download.

 

Al Pascual is a senior software engineer at ESRI headquarters, located in Redlands, CA, where he works in the Professional Services division. Al s latest personal hack, GeoTwitter, makes extensive use of the advantage of visualizing Twitter on a map. Al is a Microsoft ASP.NET MVP. Keep up with Al by visiting his blog at http://silverlightme.net or send an e-mail to mailto:[email protected].

 

References

GeoTwitter: http://geotwitter.net

GeoRSS: http://georss.org

Google Maps: http://maps.google.com

ESRI: http://esri.com

Resource Page: http://resources.esri.com

Richie Carmichael s blog: http://mrrichie.spaces.live.com

ArcGIS online REST API information: http://resources.esri.com/help/9.3/arcgisserver/apis/rest/index.html

Al Pascual s blog: http://silverlightme.net

Silverlight Forums and Resources: http://silverlight.net

 

Begin Listing One Adding the Silverlight control to an HTML page

 type="application/x-silverlight-2-b2" height="100%"

 width="100%">

   

    value="ClientBin/ESRI.PrototypeLab.Silverlight.xap"/>

   

   

   

   

     style="text-decoration: none;">

      Get Microsoft Silverlight

       style="border-style: none"/>

   

 

End Listing One

 

Begin Listing Two Add a GeoRSS feed to your Silverlight map

 

End Listing Two

 

Begin Listing Three A JavaScript GeoRSS parser

function GeoRSSItem(itemtags) {

 this.feedType = 1;

   this.lat="";

   this.lon="";

   this.fType="point"; // by default the feature

                       // type is point

   this.coords="";

   this.title="";

   this.description="";

   this.pubDate="";

   this.link="";

   this.id="";

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

     var v="";

     if (itemtags[j].firstChild)

      v=itemtags[j].firstChild.data;

     var tag = itemtags[j].nodeName;

     if (tag == 'geo:lat') {

       this.lat = v;

     } else if (tag == 'geo:long') {

       this.lon = v;

     } else if (tag == 'georss:point') {

       var ptArr=v.split(" ");

       this.lat = ptArr[0];

       this.lon = ptArr[1];

     } else if (tag == 'gml:pos') {

       var ptArr=v.split(" ");

       this.lat = ptArr[0];

       this.lon = ptArr[1];

     } else if (tag == 'georss:line') {

       this.coords=v;

       this.fType="line"

     } else if (tag == 'georss:polygon') {

       this.coords=v;

       this.fType="polygon"

     } else if (tag == 'title') {

       this.title= (v==null? "":v);

     } else if (tag == 'description') {

       if (v!=null) {

         if (v.lastIndexOf(".")>-1) {

             var fExt=v.substr(v.lastIndexOf(

              ".")+1).toLowerCase();

             if (fExt=="gif" || fExt=="jpg" ||

                  fExt=="png") {

                 v="";

             }

          }

        } else {

         v="";

        }

         this.description=v;

     } else if (tag == 'link') {

       if (v!=null) {

         if (v.lastIndexOf(".")>-1) {

             var fExt=v.substr(v.lastIndexOf(

                               ".")+1).toLowerCase();

             if (fExt=="gif" || fExt=="jpg" ||

                 fExt=="png") {

                 v="";

             }

          }

        } else {

         v="";

        }

       this.link=v;

     } else if (tag == 'pubDate') {

       this.pubDate=(v==null? "":v);

     } else if (tag == 'ems:sym') {

         if (itemtags[j].firstChild.firstChild)

             v=itemtags[j].firstChild.firstChild.data;

         if (v!=null) {

             this.sym=v.substring(0,v.indexOf("."));

         }

     } else if (tag == 'guid') {

       if (v.indexOf(":")>0) {

         this.id=v.substring(v.indexOf(":")+1);

       } else {

         this.id=v;

       }

     }

   } //end for

}

End Listing Three

 

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish