Geoprocessing has been primarily a desktop activity. Using ArcServer, you can publish geoprocessing services. This takes geoprocessing off the desktop but requires communication between a client and server. I don’t mind you downloading my data and processing it on your desktop, but I really don’t like the idea of you using my CPU and memory running some harebrained geoprocessing task off my server. Given the advances in web technology, especially JavaScript, can’t we come up with something better? Can’t we let the client handle the work?
We can with Turf.js.
Using Turf.js you can perform a large number of commonly used geoprocessing functions client side. In this post, I will show you how to buffer, point in polygon and sum a field for points in a polygon.
Buffer a Point
1. Using Leaflet.js, create a map and add a tile layer:
- var map = L.map(‘map’, { center: [35.10418, -106.62987],zoom: 9});
- L.tileLayer(‘http://{s}.tile.osm.org/{z}/{x}/{y}.png’).addTo(map);
2. Create two points using turf.point and Long,Lat.
- pointOne = turf.point(-106.32568,35.11542);
- pointTwo = turf.point(-106.33,35.22)
3. The points are now in GeoJSON. to add them to Leaflet.js us L.geoJson.
- L.geoJson(pointOne).addTo(map);
- L.geoJson(pointTwo).addTo(map);
4. Buffer a point and assign the result to a variable. Then add the buffer to the map. the buffer function takes a feature (point, line, polygon, feature collection), a distance, and the units (miles, kilometers or degrees).
- var b = turf.buffer(pointOne,2,”miles”);
- L.geoJson(b).addTo(map);
Now you should have a map that looks like the one below.
Point in Polygon
Now that we have two points and a buffer, let’s perform a point in polygon.
1. Create a polygon from the buffer.
- var polygon = turf.polygon(b.features[0].geometry.coordinates, {
“fill”: “#6BC65F”,
“stroke”: “#6BC65F”,
“stroke-width”: 5,
“title”:”Polygon”,
“description”:”A sample polygon”
});
2. To PIP, use turf.inside() passing the point and polygon as parameters. the result will be true or false.
- alert(“pointTwo is inside? “+turf.inside(pointTwo, polygon));
Now you will be alerted that the point is not inside the polygon.
In the previous example, the features did not have any attributes. In the next geoprocessing example, we will calculate a value from points in a polygon.
Using Statistics: Sum
1. This example starts with a Leaflet.js map.
- var map = L.map(‘map’, {center: [35.10418, -106.62987],zoom: 9});
- L.tileLayer(‘http://{s}.tile.osm.org/{z}/{x}/{y}.png’).addTo(map);
2. Add a function for iterating through features so we can add a popup.
- function onEachFeature(feature, layer) {
layer.bindPopup(“<h3>Add this number: “+feature.properties.title+”</h3>”+feature.properties.description);}
3. Now add your points, but this time we will add properties to the points.
- var p1 = turf.point(-106,35, {“marker-color”: “#6BC65F”,”title”: 100, “description”: “Not in Polygon”, “someOtherProperty”:”I am another property” });
- var p2 = turf.point(-106.62987,35.10418, {“marker-color”: “#6BC65F”,”title”: 4, “description”: “In Polygon”, “someOtherProperty”:”I am another property” });
- var p3 = turf.point(-106.64429,35.14125, {“marker-color”: “#6BC65F”,”title”: 1, “description”: “Also in Polygon”, “someOtherProperty”:”I am another property” });
4. To sum a filed, you will need at least one polygon – you can use multiple as well.
- var polygon = turf.polygon([ [
[-106.73355,35.21197],[-106.73355,35.04911],[ -106.51932,35.04911],[-106.49872,35.19177]
]], {
“fill”: “#6BC65F”,
“stroke”: “#6BC65F”,
“stroke-width”: 5,
“title”:”Polygon”,
“description”:”A sample polygon”
});
5. Create feature collections for the polygon(s) and points. Add them to the map using an option to call your onEachFeature function.
- var p = turf.featurecollection([polygon]);
var t = turf.featurecollection([p1,p2,p3]); - L.geoJson(p).addTo(map);
- L.geoJson(t, {
onEachFeature: onEachFeature
}).addTo(map);
6. Now pass the sum function the polygon, points, the field to sum and the name of the output field.
- var sum = turf.sum(p,t,”title”,”output”);
7. when you click the map you will get the result. Notice the marker with the value of 100 is ignored since it is outside the polygon.
- map.on(“click”,function(){alert(sum.features[0].properties.output);});
Lastly, when you can click a marker and the popup information is displayed.
Running geoprocessing tasks without having to pass data back and forth from client to server is the way to go. It also means your browser can now work as a simple desktop GIS application.
Reblogged this on PRAGMATIC URBANISM.
Is there a way to choose my own buffer while i am in the map?
What are you trying to do with it? You can get the GeoJSON of the buffer by assigning it to a variable:
buffered = turf.buffer(b,.05,”miles”); Or a Leaflet object by var :buff=L.geoJson(buffered).addTo(map);
Is that what you need?
what I am trying to do (using your example) is to create a form or sth where the user is able to write the buffer distance but I do not know how to do it
Ok, I got it. You need to add a marker to the map. Open a popup on the marker with a form that allows you to enter a value for the buffer. Then have a submit button. When clicked, grab the value in the box and run turf.buffer with that value.
In this case we have only two point, but in the case of having more than two points and if I want to create a buffer from a layer of 200 points….I would like to know if you kwnow how to create a form where writting a distance, you can obtain a buffer
Thak u very much
You want it for each point individually or for all points the same distance?
Here is Point by Point
var k;
var map = L.map(‘map’, {center: [35.10418, -106.62987], zoom:10 });
L.tileLayer(‘http://{s}.tile.osm.org/{z}/{x}/{y}.png’).addTo(map);
map.on(“click”,function(e){
a=L.marker(e.latlng).bindPopup(‘Buffer Distance: Submit’).addTo(map).openPopup();
b=a.toGeoJSON();
});//end on
function getDist(){
var a=document.getElementById(“dist”).value;
console.log(a);
var buffered = turf.buffer(b,a,”miles”);
var k=L.geoJson(buffered).addTo(map);
}
Here is how to do all the same. You need to disable the map default on clicks or propogation on the textbox. I didnt do that. Double click a bunch of markers. Then in lower left, enter a number then click the submit. It will buffer them all
var mkers=[];
var k;
var map = L.map(‘map’, {center: [35.10418, -106.62987], zoom:10 });
L.tileLayer(‘http://{s}.tile.osm.org/{z}/{x}/{y}.png’).addTo(map);
map.on(“dblclick”,function(e){
L.marker(e.latlng).addTo(map);
mkers.push(L.marker(e.latlng));
});//end on
function getDist(){
var a=document.getElementById(“dist”).value;
for(var x = 0;x<mkers.length;x++){
var b=mkers[x].toGeoJSON();
var buffered = turf.buffer(b,a,"miles");
var k=L.geoJson(buffered).addTo(map);
}
}
var done = L.control({ position: 'bottomleft' });
done.onAdd = function(map) {
this._div = L.DomUtil.create('div', 'mylegend-css-class');
this._div.innerHTML = 'Buffer Distance: Submit’;
return this._div;
};
done.addTo(map);
Thank u very much. I supose that the process is the same if I work with a *.js layer…don´t I?
I would think so.
I would like for all points…
the same distance
Here is how to do all the same. You need to disable the map default on clicks or propogation on the textbox. I didnt do that. Double click a bunch of markers. Then in lower left, enter a number then click the submit. It will buffer them all
var mkers=[];
var k;
var map = L.map(‘map’, {center: [35.10418, -106.62987], zoom:10 });
L.tileLayer(‘http://{s}.tile.osm.org/{z}/{x}/{y}.png’).addTo(map);
map.on(“dblclick”,function(e){
L.marker(e.latlng).addTo(map);
mkers.push(L.marker(e.latlng));
});//end on
function getDist(){
var a=document.getElementById(“dist”).value;
for(var x = 0;x<mkers.length;x++){
var b=mkers[x].toGeoJSON();
var buffered = turf.buffer(b,a,"miles");
var k=L.geoJson(buffered).addTo(map);
}
}
var done = L.control({ position: 'bottomleft' });
done.onAdd = function(map) {
this._div = L.DomUtil.create('div', 'mylegend-css-class');
this._div.innerHTML = 'Buffer Distance: Submit’;
return this._div;
};
done.addTo(map);
Here is a working example
http://paulcrickard.github.io/buffer.html