Skip to content

Instantly share code, notes, and snippets.

@calvinmetcalf
Created July 20, 2012 11:50
Show Gist options
  • Save calvinmetcalf/3150329 to your computer and use it in GitHub Desktop.
Save calvinmetcalf/3150329 to your computer and use it in GitHub Desktop.
Using ESRI JSON in Leaflet

Basic example of taking an output from our server and putting it on a map. As leaflet allows you to add geoJSON directly, we convert it from esri's JSON format to a more standard one.

<!doctype html>
<html lang="en">
<head>
<meta charset='utf-8'/>
<style>
html { height: 100% }
body { height: 100%; margin: 0; padding: 0;}
#map{ height: 100% }
</style>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.3.1/leaflet.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.3.1/leaflet.ie.css" />
<![endif]-->
<script src="http://cdn.leafletjs.com/leaflet-0.3.1/leaflet.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<title>
Cameras
</title>
</head>
<body>
<div id="map"></div>
<script type="text/javascript" src="toGeoJSON.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
//set the options
var center = new L.LatLng(42.3584308,-71.0597732);
var zoom = 8;
var url= "http://{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png";
var options={
subdomains:["otile1","otile2",/*"otile3",*/"otile4"],//we'd usually use all 4 but something is up with #3 at the moment
attribution:"Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>"
};
//create the tiles
var tiles = new L.TileLayer(url,options);
//create the map
var m = new L.Map('map',{
center:center,
zoom:zoom,
layers:[tiles]
});
var gj = new L.GeoJSON();
//create empty geojson object and add it to the map
m.addLayer(gj);
//create the popups
gj.on("featureparse", function (e) {
if (e.properties){
e.layer.bindPopup(makePop(e.properties));
}
});
//get the current bounds
var bbox=m.getBounds().toBBoxString();
//the url
var url = "http://services.massdot.state.ma.us/ArcGIS/rest/services/Assets/SmartCameras/MapServer/0/query?outFields=*&f=json&outSR=4326&inSR=4326&geometryType=esriGeometryEnvelope&geometry="
//get the features
$.get(url+bbox,parseJSONP,"JSONP");
//this is the call back from the jsonp ajax request
function parseJSONP(data){
//we call the function to turn it into geoJSON and write a callback to add it to the geojson object
toGeoJSON(data,
function(d){
gj.addGeoJSON(d)
}
);
}
//the function called earlier to make the popup, it goes through all the attributes and makes them into a nice key value list
function makePop(p){
var a = [];
for(var key in p){
a.push(key+": "+p[key]);
}
return a.join("<br/>");
};
/*
fork me on github: http://github.com/calvinmetcalf/esri2geo
*/
function toGeoJSON(data,cb){
var outPut = { "type": "FeatureCollection",
"features": []};
var fl = data.features.length;
var i = 0;
while(fl>i){
var ft = data.features[i];
/* as only ESRI based products care if all the features are the same type of geometry, check for geometry type at a feature level*/
var outFT = {
"type": "Feature",
"properties":ft.attributes
};
if(ft.geometry.x){
//check if it's a point
outFT.geometry=point(ft.geometry);
}else if(ft.geometry.points){
//check if it is a multipoint
outFT.geometry=points(ft.geometry);
}else if(ft.geometry.paths){
//check if a line (or "ARC" in ESRI terms)
outFT.geometry=line(ft.geometry);
}else if(ft.geometry.rings){
//check if a poly.
outFT.geometry=poly(ft.geometry);
}
outPut.features.push(outFT);
i++;
}
function point(geometry){
//this one is easy
return {"type": "Point","coordinates": [geometry.x,geometry.y]};
}
function points(geometry){
//checks if the multipoint only has one point, if so exports as point instead
if(geometry.points.length===1){
return {"type": "Point","coordinates": geometry.points[0]};
}else{
return { "type": "MultiPoint","coordinates":geometry.points};
}
}
function line(geometry){
//checks if their are multiple paths or just one
if(geometry.paths.length===1){
return {"type": "LineString","coordinates": geometry.paths[0]};
}else{
return { "type": "MultiLineString","coordinates":geometry.paths};
}
}
function poly(geometry){
//first we check for some easy cases, like if their is only one ring
if(geometry.rings.length===1){
return {"type": "Polygon","coordinates": geometry.rings};
}else{
/*if it isn't that easy then we have to start checking ring direction, basically the ring goes clockwise its part of the polygon, if it goes counterclockwise it is a hole in the polygon, but geojson does it by haveing an array with the first element be the polygons and the next elements being holes in it*/
var ccc= dP(geometry.rings);
var d = ccc[0];
var dd = ccc[1];
var r=[];
if(dd.length===0){
/*if their are no holes we don't need to worry about this, but do need to stuck each ring inside its own array*/
var l2 = d.length;
var i3 = 0;
while(l2>i3){
r.push([d[i3]]);
}
return { "type": "MultiPolygon","coordinates":r};
}else if(d.length===1){
/*if their is only one clockwise ring then we know all holes are in that poly*/
dd.unshift(d[0]);
return {"type": "Polygon","coordinates": dd};
}else{
/*if their are multiple rings and holes we have no way of knowing which belong to which without looking at it specially, so just dump the coordinates and add a hole field, this may cause errors*/
return { "type": "MultiPolygon","coordinates":d, "holes":dd};
}
}
}
function dP(a){
//returns an array of 2 arrays, the first being all the clockwise ones, the second counter clockwise
var d = [];
var dd =[];
var l = a.length;
var ii = 0;
while(l>ii){
if(c(a[ii])){
d.push(a[ii]);
}else{
dd.push(a[ii]);
}
ii++;
}
return [d,dd];
}
function c(a){
//return true if clockwise
var l = a.length-1;
var i = 0;
var o=0;
while(l>i){
o+=(a[i][0]*a[i+1][1]-a[i+1][0]*a[i][1]);
i++;
}
return o<=0;
}
if(cb){
cb(outPut)
}else{
return outPut;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment