Al Pascual



Geo RSS
Geo Twitter Timeline

Blogs I read

<December 2008>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Using the ESRI JavaScript API as the Silverlight control SDK

After Richie released the Map Viewer Silverlight control I thought to provide the control with an SDK.  Completely write an SDK in Silverlight for queries and tasks would take a long time. However ArcGIS 9.3 comes out with the Rest Api and Silverlight can talk to Javascript without any problems. ESRI Javascript API uses rest to talk to the server. So I would use the Javascript API from Silverlight as the SDK.

This is how a little application using the JavaScript API looks like

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Create Map</title>
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.1/js/dojo/dijit/themes/tundra/tundra.css">
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>
    <script type="text/javascript">
      dojo.require("esri.map");

      function init() {
        var map = new esri.Map("map");
        var tiledMapServiceLayer = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer");
        map.addLayer(tiledMapServiceLayer);
      }

      dojo.addOnLoad(init);
    </script>
  </head>
  <body class="tundra">
    <div id="map" style="width:900px; height:600px; border:1px solid #000;"></div>
  </body>
</html>

If you look at the div to create the map you can replace that line with the Silverlight Control:

<object id="map" data="data:application/x-silverlight," type="application/x-silverlight-2-b2" height="100%" width="100%">
     <param name="source" value="ClientBin/ESRI.PrototypeLab.Silverlight.xap"/>
     <param name="onerror" value="onSilverlightError" />
     <param name="background" value="white" />
     <param name="initParams"
      value="Url=http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer,ShowCoordinateDisplay=true" />
     <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
     <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
     </a>
 </object>

Then you need to replace the map object to use the Silverlight map instead of the div, in the JavaScript line:

var map = new esri.Map("map");  
var map = document.getElementById("map").Content.Map;

The second like is an object in Javascript that reference the Silverlight Map control.

Now I started building the methods supported by the Javascript API. For example the addLayers method would look like this in Silverlight:

[ScriptableMember]
public void addLayer(System.Windows.Browser.ScriptObject mapLayer)
{   
    Url = mapLayer.GetProperty("url").ToString();
}

The arguments passed by JavaScript are ScriptObject type that you need to get the properties from inside the object as shown above.

Silverlight 2.0 makes the communication between JavaScript and Silverlight very easy. Now, to call Javascript methods from Silverlight you can use this method in C#:

HtmlPage.Window.CreateInstance(method, args);

First parameter is the javascript method to execute, the second is the list of parameters to pass to the Javascript method:

MapEventArgs args = new MapEventArgs(coor.X, coor.Y);

Now you can have a simple application using the ESRI JavaScript API with the Silverlight Map control to query and geolocate:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Silverlight Demonstration</title>
    <style type="text/css">
    html, body {
        height: 100%;
        overflow: auto;
    }
    body {
        padding: 0;
        margin: 0;
    }
    #silverlightControlHost {
        height: 90%;
    }
    </style>
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.1/js/dojo/dijit/themes/tundra/tundra.css">
    <script type="text/javascript">
        function onSilverlightError(sender, args) {
            var appSource = "";
            if (sender != null && sender != 0) {
                appSource = sender.getHost().Source;
            }
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;
            var errMsg = "Unhandled Error in Silverlight 2 Application " + appSource + "\n";
            errMsg += "Code: " + iErrorCode + "    \n";
            errMsg += "Category: " + errorType + "       \n";
            errMsg += "Message: " + args.ErrorMessage + "     \n";
            if (errorType == "ParserError") {
                errMsg += "File: " + args.xamlFile + "     \n";
                errMsg += "Line: " + args.lineNumber + "     \n";
                errMsg += "Position: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError") {
                if (args.lineNumber != 0) {
                    errMsg += "Line: " + args.lineNumber + "     \n";
                    errMsg += "Position: " + args.charPosition + "     \n";
                }
                errMsg += "MethodName: " + args.methodName + "     \n";
            }
            throw new Error(errMsg);
        }
    </script>    
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>
    <script type="text/javascript">
        dojo.require("esri.map");
        dojo.require("esri.tasks.query");
        dojo.require("esri.tasks.gp");

        var locator;
        var map;

        function init() {
            map = document.getElementById("map").Content.Map;
            
            // Start listening to the MapMouseMove Event
            map.MapMouseMove = MapMouseMove;

            locator = new esri.tasks.Locator("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Locators/ESRI_Geocode_USA/GeocodeServer");
        }

        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));
                }
            });
        }

        function LocationOnClick(args) {
            var point = new esri.geometry.Point(args.X, args.Y);
            //map.graphics.clear();
            locator.locationToAddress(point, 100);            
        }


        function ToggleCoordinateDisplay() {
            var map = document.getElementById("map").Content.Map;
            // Toggle the display of the coordinate display in the bottom right hand corner
            map.ShowCoordinateDisplay = !map.ShowCoordinateDisplay;
        }
        function DisplayMapExtent() {
            var map = document.getElementById("map").Content.Map;
            // Display map extent (in JSON)
            alert(map.Extent);
        }
        function FullExtent() {
            var map = document.getElementById("map").Content.Map;
            // Set Full Extent (using JSON)
            map.Extent = "{\"spatialreference\":null,\"xmax\":180,\"xmin\":-180,\"ymax\":90,\"ymin\":-90}";
        }
        // 
        function MapMouseMove(sender, args) {
            var label = document.getElementById("label1");
            // Display Mouse Coordinates
            label.innerHTML = args.X + " " + args.Y;
        }

        function ChangeStreets() {
            var streetMap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer");

            map.addLayer(streetMap);
        }
 
        function PopulationQuery() {
            var startExtent = new esri.geometry.Extent(-83.41, 31.98, -78.47, 35.28, new esri.SpatialReference({ wkid: 4326 }));
 
            //build query task
            var queryTask = new esri.tasks.QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/3");

            //build query filter
            var query = new esri.tasks.Query();
            query.returnGeometry = true;
            query.outFields = ["NAME", "POP2000", "POP2007", "POP00_SQMI", "POP07_SQMI"];
            query.where = "STATE_NAME = 'South Carolina'";

            var infoTemplate = new esri.InfoTemplate();
            infoTemplate.setTitle("${NAME}");
            infoTemplate.setContent("<b>2000 Population: </b>${POP2000}<br/>"
                             + "<b>2000 Population per Sq. Mi.: </b>${POP00_SQMI}<br/>"
                             + "<b>2007 Population: </b>${POP2007}<br/>"
                             + "<b>2007 Population per Sq. Mi.: </b>${POP07_SQMI}");

            map.infoWindow.resize(245, 105);

            //Can listen for onComplete event to process results or can use the callback option in the queryTask.execute method.
            dojo.connect(queryTask, "onComplete", function(featureSet) {
                map.graphics.clear();
                var symbol = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255, 255, 255, 0.35]), 1), new dojo.Color([125, 125, 125, 0.35]));
                //QueryTask returns a featureSet.  Loop through features in the featureSet and add them to the map.
                for (var i = 0, il = featureSet.features.length; i < il; i++) {
                    //Get the current feature from the featureSet.
                    //Feature is a graphic
                    var graphic = featureSet.features[i];
                    graphic.setSymbol(symbol);
                    graphic.setInfoTemplate(infoTemplate);

                    //Add graphic to the map graphics layer.
                    map.graphics.add(graphic);
                }
            });

            queryTask.execute(query);
        }


        dojo.addOnLoad(init);        
    </script>
</head>
<body>
    <!-- Runtime errors from Silverlight will be displayed here.
    This will contain debugging information and should be removed or hidden when debugging is completed -->
    <div id='errorLocation' style="font-size: small;color: Gray;"></div>
    <div id="silverlightControlHost">
        <object id="map" data="data:application/x-silverlight," type="application/x-silverlight-2-b2" height="100%" width="100%">
            <param name="source" value="ClientBin/ESRI.PrototypeLab.Silverlight.xap"/>
            <param name="onerror" value="onSilverlightError" />
            <param name="background" value="white" />
            <param name="initParams"
                   value="Url=http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer,ShowCoordinateDisplay=true" />
            <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
                 <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
            </a>
        </object>
        <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
    </div>
    <input id="button1" type="button" value="Reverse Geocoder" onclick="ReveseGeocoder()" />
    <input id="button2" type="button" value="Toggle Coordinate Display" onclick="ToggleCoordinateDisplay()" />
    <input id="button3" type="button" value="Population" onclick="PopulationQuery()" />
    <input id="button4" type="button" value="Street Map" onclick="ChangeStreets()" />
    <label id="label1" style="font-family: Arial; font-size: larger"></label>
    </body>
</html>

This is still a work in progress, I need to finish every method from the map control implemented in the JavaScript API. Silverlight 2.0 is very powerful to create rich graphical web applications. Sorry if the article got bigger than intended.

Cheers

Al

Posted from http://weblogs.asp.net/albertpascual

Comments

south carolina map said:

Pingback from  south carolina map

# September 13, 2008 1:09 AM