mapbutcher

ArcGIS Server REST API, OpenLayers and some potatoes

Posted on 07 Oct 2008 in porterhouse | 6 comments

I recently had a short but humorous conversation with James Fee about my lament for AXL, James suggested that JSON offers some real advantages over AXL which got me thinking….

Fast forward to a few days later, a friend of mine is showing me the ArcGIS Server Flex API which provides some rather nice vector management based upon JSON returns from the ArcGIS Server REST API…….

Fast forward to that evening, i’m chatting with someone else about a potential Integration showcase at FOSS4G2009…..

Fast forward to late last night..

So i’d had a glass of wine or two and thought that i’d boil some potatoes  – why because i’m busy and I have a hungry little boy who doesn’t like waiting for his dinner when he comes home (…i used to be a scout..be prepared!) While the potatoes came to the boil I began some map butchery.

OpenLayers handles vectors rather nicely and the ArcGIS Server REST API can return geometry – ESRI and Opensource integration, can’t be that hard – here’s a small recipe based on the existing OpenLayers vector sample  (excuse the hacks – i did say there was wine involved)

Pre-requisites:

1. ArcGIS Server 9.3 – with service running
2. Some wine
3. Some boiling potatoes
4. No consideration for code

1. So the REST API has a Query Layer operation a typical call to this operation might be:

http://localhost/ArcGIS/rest/services/worldadmin/MapServer/0/query?text=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&where=%22FIPS_CNTRY%22+%3D+%27AS%27&returnGeometry=true&outSR=4326&outFields=&f=json

Some things which are worth noting here is that I’m using a where clause in my query (where=[FIPS_CNTRY]=’AS’) and also I am specifying the output spatial reference as 4326 – which happens to be WGS 1984 which will mean my geometries will match the base map in OpenLayers and finally the format as JSON- ESRI offers a f-pjson format which is handy for inspecting the JSON.

2. Now we need to create a JSON object based upon our ArcGIS Server REST call above:

	//create esri JSON object
	var myReturn = "esriObj = "+xmlHttpGet(restCall, false);
	eval(myReturn);

I can now work with esriObj as a JSON object i.e. esriObj.geometryType. What happens in the xmlHttpGet method? Basically I create a XMLHttpRequest and pass in my REST URL – your can see this code here

3. OK i have my ‘ESRI query’ JSON object now I need to parse the features in this object and essentially create GeoJSON strings which the OpenLayers sample will be happy with – cue the code butchery…

 
function esriDeserialize(geojson)
{
 
	var element = document.getElementById('text');
	var type = document.getElementById("formatType").value;
	var features = formats['in'][type].read(geojson);
	var bounds;
	if(features)
	{
		if(features.constructor != Array) {
			features = [features];
		}
		for(var i=0; i<features.length;>
			if (!bounds) {
				bounds = features[i].geometry.getBounds();
			} else {
				bounds.extend(features[i].geometry.getBounds());
			}
 
		}
		vectors.addFeatures(features);
		//map.zoomToExtent(bounds);
		var plural = (features.length &gt; 1) ? 's' : '';
		//element.value = features.length + ' feature' + plural + ' added'
	} else {
		element.value = 'Bad input ' + type;
	}
}
 
function getEsriGeom(restCall){
 
	//call ESRI Rest API
	//"http://pc302926/ArcGIS/rest/services/worldadmin/MapServer/0/query?text=&amp;geometry=&amp;geometryType=esriGeometryEnvelope&amp;inSR=&amp;spatialRel=esriSpatialRelIntersects&amp;where=%22FIPS_CNTRY%22+%3D+%27AS%27&amp;returnGeometry=true&amp;outSR=4326&amp;outFields=&amp;f=json"
	var element = document.getElementById('text');	
 
	//create esri JSON object
	var myReturn = "esriObj = "+xmlHttpGet(restCall, false);
	eval(myReturn);
 
    element.value = "";
	var coordPairsPerFeature = 0;
 
	//for each feature
	for (var i=0; i &lt; esriObj.features.length; i++)
	{
		//get the geometry
		var o = esriObj.features[i].geometry;
		element.value = element.value + esriObj.features[i].attributes.ADMIN_NAME;
 
		//loop through all the rings
		for (var s=0; s &lt; o.rings.length; s++)
		{
			//create geojson start &amp; end - i know i'm getting polygons
			var geojsonstart = '{"type":"Feature", "id":"OpenLayers.Feature.Vector_124", "properties":{}, "geometry":{"type":"Polygon", "coordinates":[['
			var geojsonend = ']]}, "crs":{"type":"OGC", "properties":{"urn":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}';
 
			//the coordinates for this ring
			var coords = o.rings[s];
 
			//loop through each coordinate
			var coordPair="";
			for (var g=0; g &lt; coords.length; g++)
			{
			    coordPairsPerFeature = coordPairsPerFeature+1;
 
				//alert(coords[g]);
				if(g==coords.length-1){
					coordPair = coordPair+"["+coords[g]+"]";
				}else{
					coordPair=coordPair+"["+coords[g]+"],";
				}
			}
 
			//combine to create geojson string
			esriDeserialize(geojsonstart+coordPair+geojsonend);
		}
 
		element.value = element.value + "," + coordPairsPerFeature +"n";
	}
 
}
</features.length;>

4. Finally I call esriDeserialize which is just an amended version of the OpenLayers sample Deserialize method which does not update the text box (i do that during the previous method in the stack with the number of vertices’s per geometry) and does not refresh the map after each addition of the OpenLayers vectors. The video below shows OpenLayers rendering all the US states polygons via the ArcGIS Server REST API -315, 984 vertices.

 

Post-requisites

1. Forget about potatoes
2. Go to bed
3. Wake up 7 hrs later due to strong smell of burning potatoes
4. Go back to sleep
5. Wake up 1 hr later with a sudden realisation that i was trying to be prepared…!

The code can be downloaded from here

6 comments

  1. Nichola / October 7th, 2008 22:17

    So the little one didn’t get his potatoes then?

  2. Al Pascual / October 8th, 2008 5:21

    Great post, thanks for sharing the code. Great use of geoJson.

  3. Bob / October 12th, 2008 0:51

    Haha nice one. I remember my mum burning hard boiled eggs in the same way once.

    She actually fused the eggs to the pan and had to throw it out.

  4. Foley / November 11th, 2010 6:44

    The link to the code is broken! Could you please fix that link?

  5. mapbutcher / November 20th, 2010 8:20

    Foley,

    Apologies – re-organising files :(

    Link now fixed

    Simon

  6. lplp / April 15th, 2011 1:50

    Hi,
    has anybody ever though incorporating this code to OpenLayers so you can build an OpenLayers.Layer.Vector from an OpenLayers.Procole.ArcGIS93Rest ?

    This would allow easy selection and feature display of an ArcGIS93Rest vector layer…

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>