Tag Archives: ArcGIS Server

ArcGIS Server Legend Resource Application

Building on my last post, I wanted to create a RESTful app that serves up legends from ArcGIS Server.  Ideally, this app would not need any configuration.  I thought this was very doable, since I could just put the URL information for the map service into the URL for the legend resource service by my new RESTful app.  All in all, this was much easier than even I predicted.  Oh, and I have to thank Colin Casey (again) for refactoring my code to look more Ruby-way like.

At first, I thought of using a Rails app for this, which I did stand up and get running.  However, it seemed like way too much for just a simple app.  There is no database, no real views, and not much that required all the conventions that Rails uses.  I have been hearing tons about Sinatra (including a running joke that it’s where experienced Rails developers eventually land) and how lightweight it is.  And, it is VERY lightweight.  I am not going to post any examples of Sinatra here, but a rudimentary scan of the Sinatra home page is enough to show that it’s not a lot of weight.  So, I selected Sinatra and had the app working in a  few hours (most of which were me struggling with my RubyNoob issues)  The result is legend_resource and is posted on github for your criticism and mockery.

Using LegendResource

It’s very easy to get legend_resource up and running.

  1. Pull down the code (git clone git@github.com:ruprict/legend_resource.git)
  2. Install Bundler, if it isn’t already (gem install bundler –pre)
  3. You might have to install RMagick, if you have not already.  As I alluded to in my last post, you should go the the RMagick site and figure out the best way to install it for your operating system.  (#copout)
  4. type ‘bundle install’ from the git repo root.   This should install all the necessary gems.
  5. type ‘rackup’. This should fire up the application on port 9292.

Now that the app is up and running, you can generate a legend for any map service.  For example, if you want a legend for the USA_Percent_Male map service in the Demographics folder on server.arcgisonline.com, click on this link:


Or create an HTML page with an img tag and set that link to the src.  Like this,

Neat, eh?

That’s it.  Neat, huh?

The URL scheme is pretty simple:  http://<webserver>/legend/<mapserver>/<mapservicepath>, where

  • webserver is whereever the legend_resource app is currently hosted.
  • mapserver is your ArcGIS server
  • mapservicepath is the path to the service on mapserver.  This works for services in the root or in a folder.  The link above was in a folder, for example.

Config Options

The configuration options for legend_resource are few right now.  Out-of-the-github, I want it to just work, and it does.   It writes the files to the local file system if you don’t tell it otherwise.  Right now, the only other option is a Google Storage for Developers backend that exists because I received my invite to it this morning.  If you want to use that, you have to:

1) Change the gstore.yaml file to add your access_key and secret.

2) Comment out the line in config.ru that sets up the GStoreLegend as the file handler.

run LegendResource
# Uncomment this line to use Google Storage (don't forget to change the gstore.yml file)')
#LegendResource.set :filehandler, GStoreLegend

I did that for a Heroku app that I am hosting at http://agslegend.heroku.com (the image above is from said Heroku app) that you are free to use to crank out a few legends.  Just bear in mind that the map service will have to be exposed to the web for my Heroku app to see it.

I hope someone else finds this useful.  It was a ton of fun to make and I learned a lot about ruby in the process.  I realize that my code is pretty noobish from the Ruby standpoint, so feel free to fork the repo, refactor, and issue pull requests.  That’s how I learn.  Also, if you’d like to see other options for the legends, hit me on github or leave a comment.

Happy Legending!

UPDATE:  One thing I don’t think I made clear is that the REST interface for this service only handles GET and DELETE.  If you HTTP GET to the url, it will either create or return the legend.  If you HTTP DELETE to it, it deletes the legend, so, the next GET will create it anew.

Create Legend Images from ArcGIS Server with Ruby

Recently, I needed to create a legend for an ArcGIS Server map service, and was amazed that it was still a non-trivial activity. Googling it, I saw a few posts with (what I considered to be) WAY too complicated C# code for such a simple task. Also, there is no great way to get a legend out of ArcMap (for gawd’s sake) which left me thinking “Surely, there is an easy way to do this.” (expletives removed)

I have been mucking about (again) with ruby and Rails, which is great and depressing all at the same time. I don’t use much ruby in my 9-to-5, as it’s neck-deep in Microsoft, so I try to shoehorn ruby into my work however I can. In this case, I remembered the venerable Dave Bouwman’s Ruby-Fu presentation at DevSummit (That guy is always doing the stuff I want to be doing. I don’t like him.) and that he had found a ruby library that spoke both REST and SOAP to ArcGIS Server. Being an experienced AGS dev-monkey, I also know that you can get legend and symbology information from the SOAP API. Thusly, a not-terribly-original-or-visionary idea was born: Use ruby to create a legend.

My main requirement is that it easy, something on the order of:

  1. Tell the thing the URL of my map service.
  2. Tell the thing I want a legend for the map service.
  3. Save the legend given to me by the thing to a file.

So, I got my shoehorn out and when in search of ArcGIS-flavored ruby bits.


I hunted down the slides for Dave’s preso to find the name of the ruby library he mentioned. It is arcserver.rb (github) written by Colin Casey, an extremely patient and approachable developer. I sent him a message with my Grand Legend Plan, and he say “Do it, man.” arcserver.rb already did #1 and #2 from my list above. All I had to do was #3.  Once you’ve installed the arcserver.rb gem (so, type ‘gem install arcserver.rb’ at your command prompt and watch it install all kinds of stuff….WEEE!)  (run this in irb):

require 'rubygems'
require 'arcserver'
server = ArcServer::MapServer.new("http://server.arcgisonline.com/ArcGIS/services/Demographics/ESRI_Diversity_US_2D/MapServer")

That gives you a text representation of all the legend information for the service. So, all I had to do was loop through all the symbology and write out the symbols. Easy, right? Well, in ruby evertyhing is easy (no fanboy bias there at all). I needed an image processor, and the Old Man of Ruby Image Processors is RMagick. Now, bear in mind that I did all of this on a Windows box, but I used Cygwin. You can install RMagick 2 on Windows natively, so I hear/read, but I didn’t do it that way. However you do it, you’re gonna need RMagick, and therefore, ImageMagick. (um, everything in ruby is easy *cough*)

Got RMagick installed?? Awesome! Wasn’t that easy? Are you giving me the finger? Let’s continue. One of my goals in contributing to Colin’s project was to not pollute it too much. Being pretty much a ruby novice, I figured the best thing to do was to keep as much of my code in its own class/file, so Colin could easily remove/rewrite/laugh-and-point-at it how he saw fit. The final (cleaned and reorganized by Colin) version consists of a LegendImage class that you can see here on Github (I don’t want to post a ton of code here, it’s just unwieldy) I am not going to walk through the code, but I’d like to point out that it’s <70 lines and very readable. For a first run, I was very happy. If people use it or I find the need, the next step would be to handle options (dpi, width, height, layers to exclude, etc.) but, for now, this works. Also, I’ve heard that 10.1 is going to fix this legend issue and make it easy to create them, so putting a ton of work into this prove to be fruitless.

Now, to create a legend image, do the same thing we did above, but add (if you’ve installed RMagick since you started irb, you need to restart it):

require 'RMagick'

which will write a PNG file called “legend.png” in the from which directory you fired up ‘irb’. Kick ass. Three lines of code (less if you chain) to get a (very basic, but usable) legend from ArcGIS Server. Here is the legend it creates using the Diversity service from ArcGISOnline.

Legend for Diversity Map Service

I thought that was pretty cool and useful. There may be other, more elegant ways out there to get a legend from an ArcGIS Server map service, and I am sure someone will mention them in the comments. Even so, I enjoyed doing this little exercise and I appreciate Colin letting me contribute to his project. Here are all the irb commands needed once you have the prerequisites and the gem installed:

require 'rubygems'
require 'RMagick'
require 'arcserver'
server = ArcServer::MapServer.new("http://server.arcgisonline.com/ArcGIS/services/Demographics/ESRI_Diversity_US_2D/MapServer")

My next task is to use this library in a Rails-based web mapping application. Hopefully, I’ll get to that in the next week or so.

Enhanced by Zemanta

Unit Testing Objects Dependent on ArcGIS Server Javascript API

Recently, I’ve created a custom Dojo dijit that contains a esri.Map from the ArcGIS Server Javascript API.  The dijit, right now, creates the map on the fly, so it calls new esri.Map(…) and map.addLayer(new esri.layers.ArcGISTiledMapServiceLayer(url)), for example.  This can cause heartburn when trying to unit test the operations that my custom dijit is performing.  I am going to run through the current (somewhat hackish) way I am performing unit tests without having to create a full blown HTML representation of the dijit.

I’ll be using JSpec for this example, so you may want to swing over to that site and brush up on the syntax, which is pretty easy to grok, especially if you’ve done any BDD/spec type unit testing before.

The contrived, but relatively common, scenario for this post is:

  1. My custom dijit makes a call to the server to get information about some feature.
  2. The service returns JSON with the extent of the object in question.
  3. I want my map control to go to that extent.

Following the Arrange-Act-Assert pattern for our unit tests, the vast majority of the work here will be in the Arrange part.  I don’t want to pull in the entire AGS Javascript API for my unit tests.  It’s big and heavy and I am not testing it so I don’t want it.    Also, I don’t want to invoke the call to the server in this test.  Again, it’s not really what I am testing, and it slows the tests down.  I want to test that, if my operation gets the right JSON, it sets the extent on the map properly.

The Whole Test

Here is the whole JSpec file:

describe 'VersionDiff'

   vd = new esi.dijits.VersionDiff();
 describe 'updateImages()'
   it 'should change the extent of the child map'
           var obj={};
           return obj;
     vd.childMap = new esri.Map();
     var text = fixture("getFeatureVersionGraphics.txt")
     text = dojo.fromJson(text)
     vd.childMap.extent.xmin.should.be 7660976.8567093275
     vd.childMap.extent.xmax.should.be 7661002.6869258471
     vd.childMap.extent.ymin.should.be 704520.0600393787
     vd.childMap.extent.ymax.should.be 704553.8080708608


The Arrange portion of the test stubs out the methods that will be called in the esri namespace.  Since the goal of the test is to make sure my djiit changes the extent of the map, all I need to do is stub out the setExtent method on the Map.  setExtent takes an Extent object as an argument, so I create that in my local, tiny esri namespace.  Now I can set the property on my dijit  using my stubbed out map.  Thanks to closures global variables (ahem), the esri namespace I just created will be available inside my function under test.  Closures are sexy, and I only know enough about them to be dangerous.  Yay!  I don’t have to suck in all the API code for this little test.  That fixture function is provided by JSpec, and basically pulls in a text file that has the JSON I want to use for my test.  I created the fixture my saving the output of a call to my service, so now I don’t have to invoke the service inside the unit test.


This is the easy part.   Call the function under test, passing in our fixture.


How do I know the extent was changed?  When I created my tiny esri namespace, my esri.geometry.Extent() function returns an object that has the same xmin/ymin/xmax/ymax properties of an esri.geometry.Extent object.  The setExtent() function on the map stores this object in an extent property.  All I have to do is make sure the extent values match what was in my fixture.

I didn’t include the source to the operation being tested, because I don’t think it adds much to the point.  Suffice it to say that it calls setExtent() on the childMap property.

So What?

I realize this may not be the greatest or cleanest approach, but it is serving my needs nicely.  I am sure in my next refactor of the unit tests that I’ll find a new approach that makes me hate myself for this blog post.  As always, leave a comment if you have any insight or opinion.  Oh, and regardless of this test, you should really look into JSpec for javascript unit testing.  What I show here is barely the tip of what it offers.

Reblog this post [with Zemanta]

2010 ESRI Developers Summit

So, I’m off to the ESRI Dev Summit next week to meet and learn from a legend (the official unit of measure of geonerds) of geonerds.  I will be giving a user presentation on using Cairngorm 3 to create testable applications with ArcGIS Server.  The presentation is all but done, and I’ll have links to the slides as well as the source I use for the demo app once the conference is over.  I am very interested in some of the other user presentations, which span the gamut of what can be done with ArcGIS and a bit of nerd elbow grease.  I’ll definitely be attending the Ruby/Rails based user presentations, as well as some of the other Flex and javascript-based presos.  Just like last year, I’ll not likely go to any Silverlight presentations, simply because we are not currently using Silverlight.

If you’re going to be in Palm Springs this year and want to have a pint or ten, hit me on twitter (@ruprictGeek).  For what I do, the ESRI Developers Summit is far-and-away the most relevant and important conference, so the more geonerds I can meet, the better.

Hope to see you there!

ArcGIS Javascript API Tasks and the Back Button

Today I was working on an issue with a Sharepoint (I know, I know) web part that we have created to host a map. The web part using the ESRI ArcGIS Javascript API to dynamically load some graphics and layers when the page is loaded. The structure of the Sharepoint pages is hierarchical, so the user would select a property, then a site on that property, then an agreement on that site. Each of these pages contained a map that zoomed to the relevant area and loaded the relevant graphics/layers. This hierarchy leads the users to hit the browser Back button quite often. Go to a property, then a site, back to the property, to another site, then an agreement, back to the site….you get the idea.

Unfortunately, when the user hit the back button in that piece of crap Internet Explorer, the queries would not fire. In all other browsers, the queries work fine when the back button is clicked, but not IE. As you probably already know, if an enterprise is using Sharepoint, then they are using IE as their standard browser. This issue was causing a ton of grief.

I tried many different approaches, from forcing HTTP headers (Pragma: no-cache or Expires: -1) to trying to reload the page if the history.next object was defined. What finally worked was slightly changing the URL that task used so that IE wouldn’t use the client-side cache. I used a random number generator in javascript and appended it to the URL. The code is below.

var find = new ESRI.ArcGIS.VE.Query();



var findTask = new ESRI.ArcGIS.VE.QueryTask();

//Have to append a random number to get this to work when back button is pressed



The “_esi=” is just a key I put in to know it was mine and is, likely, unnecessary. May not be the best solution (I bet Vish will skewer it) but it works. Anyway, this took a few hours away from my life, so I thought I’d post it here. Hope it helps someone else.

ArcGIS Server 9.3 First Looks, Part 2: Virtual Earth Adapter

We are using the Virtual Earth Tile Server that Dave Bouwman created which publishes tiles from ArcGIS Server services to Virtual Earth. It is a danged neato peace of software, and combined with the ArcDeveloper REST API, gives us a great option for exposing ArcGIS Server services. In fact, it’s such a great option that ESRI has made it a core offering, providing adapters for Google Maps and Virtual Earth along with the new REST API at 9.3. This post focuses on the Virtual Earth adapter, although I am guessing it is not functionally different from the Google Maps adapter.

When I heard about the javascript and REST APIs coming in 9.3, I was very excited. I proclaimed the end of all pain in the GIS nerd world, just knowing that these new offerings would not only make my applications better, but they would make me a better person. They would help me easily query my GIS data and teach my kids right from wrong.

My expectations may have been a bit too high.

Here are some things that I didn’t know about the VE Adapter. They may be obvious to some, but I was mildly surprised to hear them:

  • You HAVE to use a tile cache to use the VE adapter. Yes, I know it isn’t that surprising, but I had some hope that we could display live services. Yes, I know it would be slow, but sometimes hope blinds a man…
  • You HAVE to use the WGS84 Web Mercator GCS, which is not a requirement of Dave B’s tile server (score one for Dave, open source, and little people everywhere)
  • The ArcGIS Server REST API supports JSONP out-of-the-box. All you have to do is add a ‘callback’ parameter to your querystring and it’ll return the JSON all nicely wrapped in the javascript function you specify. That is very, very nice.

You can use the ‘cache-on-demand’ feature, which is a godsend to those of us who have watched cache generation processes leak into 3 weeks.

So, real quick like, I’ll crank out some code that shows you to query the REST API to get all the available map services, add them to your page. Then, just because I am freaking crazy, we’ll add the ability to toggle the tile layers on/off on your VE map.


First, get ArcGIS Server 9.3. Then, publish a couple of map services per the requirements of using the VE adapter. I mention most of it above, but here it is from the horse’s mouth. Oh, and it’ll help if the map services have data from the same area.

Make a VE Map

Create an HTML file (doesn’t even have to be served by a web server, since we’re all in javascript) and put in the base structure for a map. Something like:

<!-- Virtual Earth API -->
<script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6" type="text/javascript"></script>
<!-- ESRI VE ADapter -->
<script src="http://serverapi.arcgisonline.com/jsapi/ve/?v=1" type="text/javascript"><!--mce:1--></script>
<!-- DOJO from AOL CDN -->
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>

<script language="javascript" type="text/javascript" >
 var map = null;
 var layerFactory;
 function OnPageLoad() {
            var centerat = new VELatLong(45.5852, -122.5951); //Replace this with your center
            map = new VEMap('mymap');
            map.LoadMap(centerat,12,VEMapStyle.Aerial ,false);
	    layerFactory= new ESRI.ArcGIS.VE.ArcGISLayerFactory();

  <div id='mymap' style="position:relative;height:400px;width:600px;float:left;"></div>
  <ul id="services"></ul></body>

So, a couple of quick comments about this “base” VE map. I have added the script tags to pull in the ESRI VE adapter, as well as Dojo. I am gonna use Dojo for this example because it makes querying a cross-domain REST service easy as 1,2,3. It is likely that your AGS installation will not be on the same server or in the same domain as your web server, so it is nice that AGS 9.3 has JSONP baked right in. Also, in the above code, I create a ESRI layer factory, which is an object that creates tile specifications for Virtual Earth. Finally, I add an unordered list (ul) that will eventually hold my services.

Ideally, we’d like to boogie out and get the list of services that are currently being published by AGS when the page loads. So, lets add a getServices() method and call it from our OnPageLoad…shall we?

var AGS_SERVER="http://yourserver/arcgis/rest/services";

function getServices(){
                    services=resp.services; // Automatically deserialized by dojo.  Thanks!
                    var ulServ=dojo.byId('services');

                            if (s.type=="MapServer"){
                                var li = document.createElement("ul");




Here is where using Dojo (or any javascript framework that will handle JSONP requests easily) really pays off. The getServices method is simply issuing an AJAX request to our AGS REST Service Catalog. The response is automatically deserialized into JSON and fed to our ‘load’ function. The load function then loops over each service (the response has folders in it too, but we are ignoring those today) and adds a list item to our services list for each MapServer. A click handler is added to each list item to call our serviceClick function (we haven’t added that yet). Side note: Using dojo.hitch here forces the serviceClick method to be called in the context of the list item that is clicked. In other words, when serviceClick is called, the ‘this’ keyword will refer to the list item. A whole lotta stuff happening on one line of code, which is one place where I think Dojo shines.

So, let’s quickly add the serviceClick (and some other) function:

function serviceClick(){
        var lyr= map.GetTileLayerByID(this.innerHTML);
        if (lyr==null)

    function addLayer(lyrName){

        layerFactory.CreateLayer(AGS_SERVER+"/"+lyrName+"/MapServer", lyrName,GetMap);

    function toggleLayer(lyrName){

        var lyr=map.GetTileLayerByID(lyrName);
        if (lyr.IsVisible)

    function GetMap(tileSourceSpec, resourceInfo) {



So, the serviceClick function gets the innerHTML from the list item clicked, which in this case is the name of the AGS service. It then checks our Virtual Earth map to see if that layer has been added. If the layer has not been added, we use the layer factory created on page load to create a tile specification for that service. The layer factory actually issues an AJAX request, which is why we have to specify a callback method (GetMap). GetMap adds the created tile spec to the map, and our layer is visible. Clicking on the service name in the list again will toggle that layer off. So, with very little code, we’ve created a pretty functional map with a nice VE interface and a poor man’s table-of-contents. Not bad for a few minutes work.

As usual, this post has gone on longer than I’d hoped.  If you want the not-split-up-by-the-blog-post HTML file, just drop me a comment.  Also, drop a comment if you have a question or think I am wrong/high/crazy.

ArcGIS Server 9.3 REST API First Looks, Part 1

Esri-logoImage via Wikipedia

You may (or may not) know that I am one of the authors of the ArcDeveloper REST API, which is an open source REST API for ArcGIS Server that can be used against ArcGIS Server (AGS) 9.2, right now, free to all comers, no waiting, etc.  If you know that, you probably know that ESRI is releasing it’s own REST API for AGS at 9.3, due out later this year.  So, I thought I’d take a few posts to show you how the REST API (in beta) is looking.  For the impatient, it looks great.  For others that may not have the beta, read on.

So, first off, we are just gonna check out the very basics of the REST API.  When you install 9.3, there is no real indication of anything all that different.  The AGS Service Properties dialogs look (basically) the same, except for some (hugely exciting, but beyond the scope of this article) changes to the Caching tab.  The real excitement comes when you start messing around with URLs against your map server.  BTW, I am using Fiddler2 with the JSON Viewer plug-in to send requests to the server and look at the results.

AGS 9.0 and later have always exposed a SOAP endpoint for each service it publishes as well as service catalog.  There is a whole SOAP API, which is my preferred method to interact with AGS services, and the URL to the SOAP service catalog looks like:


Following this pattern, the REST API brings along a similar service catalog endpoint:


The new-kid-on-the-block REST URL is even cooler, though, as it formats the results into a cool “ArcGIS Service Explorer” that looks like:

ArcGIS Services Explorer at 9.3

Which allows you to look at metadata about your services, view them in Google Earth (how cool is that?), ArcMap, ArcGIS Explorer, or the new ArcGIS Javascript API (a subject of posts to come).  Also, you can drill-down into your service and get layer info, spatial reference, unit info, and tiling information.  In fact, on the tiling information, you can actually LOOK at some of the tiles.  Other information includes supported operations that you can execute within the Explorer, like Export Map or Identify.  Here’s a picture of the service page:

Tons of info right out of the box.

Another item the Service page has is a “Supported Interfaces” section, which I would call supported formats.   The ones listed out of the box are REST and SOAP.  Clicking on the REST link will give you all (well, most of) the information just mentioned, but in JSON format .   Here, lemme show you:

Fiddler (w/JSON Viewer) display of REST GET Request of AGS

The only difference between the URL to get to the cool HTML Services Explorer page and the URL that spits out JSON is the addition of a ‘f’ (for ‘format’) querystring parameter, like so:


MMMMM….now, THAT’s some good REST.

There is similar love for supported operations, allowing you to crank out a quick image or perform a Find and look at the results.   Also, the (impressively comprehensive) API reference is linked on the Services Explorer pages, which, oh by-the-way, takes you here.

Finally, the last thing I want to cover in this post is the REST admin inteface.  If you go to the following URL in your browser:


you’ll be hit with a login screen for the ArcGIS REST API Admin application.  It’s pretty sparse right now, not even meriting a screen shot.  Currently, you can use the admin site to tell AGS when to recycle the cached service responses and to turn on the REST Services Catalog.  Now, that second option was nowhere to be found in my admin app, but the docs assure me it’s there.

So far, the only disappointment I have had is that ESRI has chosen not to use GeoJSON as their format to return features in (or, for that matter, even as an option).  I don’t profess to know why, but I’ll try to float that to one of my contacts on the mother ship soon.

Summing up, the AGS REST API looks great before you even show a map on a site.  I am hoping to go that in future posts.