Skip to content

Instantly share code, notes, and snippets.

@calvinmetcalf
Created July 20, 2012 15:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calvinmetcalf/3151306 to your computer and use it in GitHub Desktop.
Save calvinmetcalf/3151306 to your computer and use it in GitHub Desktop.
bbox queries for large data sets

this is like the other example but since it has a larger dataset we start zoomed in farther, and reload the data every time the viewpoint changes instead of loading all of it when the map loads.

<!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>
Outfall Locations
</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 = 14;
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. note we're only getting a subset of fields
var url = "http://services.massdot.state.ma.us/ArcGIS/rest/services/Assets/Outfalls/MapServer/0/query?outFields=OutfallType,OutfallShape,Material,Town&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){
/*you'd think you'd want to put the command to clear the old layer here instead of after zooming, but the markers are not not visible when you zoom, so it ends up being much less noticeable clearing them earlier*/
toGeoJSON(data,function(d){gj.addGeoJSON(d)});
}
//set up listeners on both drag and zoom events
m.on("dragend",redo);
m.on("zoomend",redo);
//the function called by those event listeners
function redo(){
bbox=m.getBounds().toBBoxString();//get the new bounds
gj.clearLayers();//clear the current layers
$.get(url+bbox,parseJSONP,"JSONP");//ajax request
}
//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