7

I was wondering if there was a way to create a buffer around a polyline feature in OpenLayers 2. I have created a tool that allows the user to draw a circle buffer zone of whatever size and style they want around a single point (using this handy walkthough ), but was just wondering if I could do the same with Polylines. The user would define the size of their buffer zone and then draw their polyline on to the map. Once finished drawing the buffer would be added to the map, like the example I made in MapInfo below.

Buffer Example

3 Answers 3

9

There are 2 ways you could approach this; server side or client side. The approach you take will depend on whether you want the processing overhead on the client or on the server (or even if you have access to a backend server like GeoServer).

Method 1: Client Side

There is a pure JavaScript port of the Java Topology Suite called JSTS which contains (amongst many other things) a buffer operation. There is an example of doing a buffer operation with OpenLayers which you could adapt to your own needs.

Method 2: Server Side

If you have access to GeoServer then you can achieve what you need through the WPS extension of GeoServer (Web Processing Service).

The default installation of GeoServer's WPS extension contains a number of different processes that can be run including several for buffering:

  • JTS:buffer
  • gs:PointBuffers
  • gt:BufferFeatureCollection
  • gt:FeatureBuffer
  • gt:buffer

In my opinion the JTS:buffer process is most like what you have mocked up using MapInfo. The JTS:buffer process takes the following parameters:

  • Input Geometry: In a range of formats such as WKT, GML
  • Distance: Specified in the same units as the geometry
  • Quadrant Segments: Effectively the quality of the generated buffer

The output from the process is the generated buffer geometry and that can be requested in a number of formats, all of which can be read by OpenLayers. So, the process I would follow is:

  1. Capture polyline from user input (as WKT or GML)
  2. Capture buffer distance from user input
  3. Generate WPS request XML
  4. POST request XML to GeoServer
  5. Read response from GeoServer
  6. Add feature to map and do any other processing

An example XML request could be:

<?xml version="1.0" encoding="UTF-8"?>
<wps:Execute version="1.0.0" service="WPS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wps/1.0.0" xmlns:wfs="http://www.opengis.net/wfs" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:wcs="http://www.opengis.net/wcs/1.1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd">
  <ows:Identifier>JTS:buffer</ows:Identifier>
  <wps:DataInputs>
    <wps:Input>
      <ows:Identifier>geom</ows:Identifier>
      <wps:Data>
        <wps:ComplexData mimeType="application/wkt"><![CDATA[LINESTRING(385000 185000, 385100 185000, 385200 185000, 385300 185000)]]></wps:ComplexData>
      </wps:Data>
    </wps:Input>
    <wps:Input>
      <ows:Identifier>distance</ows:Identifier>
      <wps:Data>
        <wps:LiteralData>50</wps:LiteralData>
      </wps:Data>
    </wps:Input>
    <wps:Input>
      <ows:Identifier>quadrantSegments</ows:Identifier>
      <wps:Data>
        <wps:LiteralData>50</wps:LiteralData>
      </wps:Data>
    </wps:Input>
    <wps:Input>
      <ows:Identifier>capStyle</ows:Identifier>
      <wps:Data>
        <wps:LiteralData>flat</wps:LiteralData>
      </wps:Data>
    </wps:Input>
  </wps:DataInputs>
  <wps:ResponseForm>
    <wps:RawDataOutput mimeType="application/wkt">
      <ows:Identifier>result</ows:Identifier>
    </wps:RawDataOutput>
  </wps:ResponseForm>
</wps:Execute>

The result from this request would be a WKT encoding of a polygon that is the 50m buffer of the input polyline.

Note that this approach will work with any backend map server that supports the OGC WPS specification.

2
  • Preferably I wanted a client side option. The client side option you gave me (almost) works a treat, and I will be accepting this as the answer, but another question regarding this may pop up from me soon :) I like the look of the server side approach as well, but don't have the time or skills to play with it! I am running on GeoServer. Commented Aug 8, 2012 at 18:16
  • @RobQuincey I'll keep an eye out for any follow on questions!
    – CHenderson
    Commented Aug 8, 2012 at 23:08
2

You can use the buffer() method of turf.js. Turf uses any GeoJSON data in WGS84 (EPSG:4326). Here is a code example :

var geojsonFormat = new OpenLayers.Format.GeoJSON();

var selectionLayer = new OpenLayers.Layer.Vector("selection");
var bufferedLayer = new OpenLayers.Layer.Vector("buffer");

// Create features in selectionLayer
...
// Convert to GeoJSON string 
var selectionLayerGeoJSON = geojsonFormat.write(selectionLayer.features);
// Convert to GeoJSON object
selectionLayerGeoJSON = JSON.parse(selectionLayerGeoJSON);
// 10 km buffering via turf.buffer() method
var bufferedLayerGeoJSON = turf.buffer(selectionLayerGeoJSON, 10, 'kilometers');
// GeoJSON to array of OpenLayers features
var bufferedFeatures = geojsonFormat.read(JSON.stringify(bufferedLayerGeoJSON));
// Add buffered features to your vector layer
bufferedLayer.addFeatures(bufferedFeatures);

Note that if your features are drawn on an EPSG:3857 map, you'll need to convert your features'geometry to EPSG:4326:

aFeature.geometry.transform(new OpenLayers.Projection("EPSG:3857"),new OpenLayers.Projection("EPSG:4326"));

then after buffering convert back then display

aFeature.geometry.transform(new OpenLayers.Projection("EPSG:4326"),new OpenLayers.Projection("EPSG:3857"));
1

you can achive this with some tricky way as following code:

1.First of all define all your LineString Layer with a style.

var style = new OpenLayers.Style({
    strokeWidth: "${strokeWidth}"
  } , {
    context: {
      strokeWidth: function(feature) {
        return feature.attributes.strokeWidth;
      }
    }
  );

2.then add a line with strokeWidth attribute.

var points = new Array(
   new OpenLayers.Geometry.Point(lon1, lat1),
   new OpenLayers.Geometry.Point(lon2, lat2)
);

var line = new OpenLayers.Geometry.LineString(points);
var feat= new OpenLayers.Feature.Vector(line, null, style);
feat.attributes.strokeWidth = 5;
vectorLayer.addFeatures([feat]);

3.when you call you object, you will get sth like this:

>>> vectorLayer.features[0].attributes.strokeWidth
    5

4.get your line and change its strokeWidth.

vectorLayer.features[0].attributes.strokeWidth = 15;
vectorLayer.redraw();

i hope it helps you...

1
  • I should have mentioned that it needs to be able to take user input such as '100 metres' or '3 miles' and make the buffer size that large on the map, a quick look through makes me think that this code would not do that, it would only make the object 'look' bigger. Commented Aug 8, 2012 at 18:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.