0

I successfully created a buffer on Leaflet with Turf.JS . I had to change the map CRS to WGS84 (epsg:4326) to make it work. But the problem is that I need to go back to the default CRS of Leaflet which is EPSG:3857 , and that code make the buffer look like an egg, in Europe.

How could I change that code?

 var x, myFunction, data, features, buffered, bufferedLayer;
function myFunction() {
  var x = document.getElementById("number").value;
    var xdiv = x/100;
  var data = drawnItems.toGeoJSON();
  var buffered = turf.buffer(data, xdiv,{units: 'kilometers'});
        var bufferedLayer = L.geoJSON(null);
        bufferedLayer.addData(buffered);
            drawnItems.addLayer(bufferedLayer); 
        bufferedLayer.addTo(map);
 }

1 Answer 1

1

Turf is using geodesic buffer. You will never be able to get a round buffer on an EPSG 3857 map. You can always make a cartesian buffer but it will be quite wrong...

An example with EPSG 3857 using reproject library, jsts, proj4js and Leaflet below. You can also look at the demo. It's mainly useful in my opinion when using a local projection that preserve locally quite well distance, area and angle unlike here.

bundle.js mentioned in the sample is a file generated from reproject library using npm run bundle (you can also found it in the mentioned live demo)

<!DOCTYPE HTML>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <script src="https://unpkg.com/[email protected]/dist/leaflet.js"
      integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
      crossorigin=""></script>
    <script src="https://unpkg.com/[email protected]/dist/jsts.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.7.5/proj4.min.js"></script>
    <script src="bundle.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
  integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
  crossorigin=""/>
    <style>
      html, body {
        height: 100%;
        padding: 0;
        margin: 0;
      }
      #map {
        /* configure the size of the map */
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      // initialize Leaflet
      var map = L.map('map').setView({lon: 2.18, lat: 46}, 8);
      var epsg3857 = proj4.Proj("EPSG:3857");
      var crss = {
        "EPSG:3857": epsg3857
      };
      var pt = {
        "type": "Feature",
        "properties": {},
        "geometry": {
          "type": "Point",
          "coordinates": [2.18, 46]
        }
      };
      
      // Reproject geometry coordinates to EPSG 3857
      var point3857geometry = reproject.reproject(pt.geometry, proj4.WGS84, epsg3857, crss);

      // Convert GeoJSON geometry with EPSG 3857 coordinates to jsts geometry
      var geojsonReader = new jsts.io.GeoJSONReader();
      var ptJsts = geojsonReader.read(point3857geometry);
      // Create a 40000 meters buffer in "local" projection 3857
      var bufferPtJsts = ptJsts.buffer(40000);
      // Write back the generate buffer to GeoJSON
      var geojsonWriter = new jsts.io.GeoJSONWriter();
      var bufferGeoJSON = geojsonWriter.write(bufferPtJsts, 32);
      // Reproject geomtry of buffer to WGS84
      var bufferWGS84 = reproject.reproject(bufferGeoJSON, epsg3857, proj4.WGS84, crss);
      console.log(bufferWGS84);
      // Copy input feature and change geometry to polygon buffer
      var bufferFeature = JSON.parse(JSON.stringify(pt));
      bufferFeature.geometry = bufferWGS84;
      // Add GeoJSON as a Leaflet layer
      var myLayer = L.geoJSON().addTo(map);
      myLayer.addData(bufferFeature);

      // add the OpenStreetMap tiles
      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
      }).addTo(map);

      // show the scale bar on the lower left corner
      L.control.scale().addTo(map);

      // show a marker on the map
      L.marker({lon: 0, lat: 0}).bindPopup('The center of the world').addTo(map);
    </script>
  </body>
</html>
2
  • hello. I tried to better understand your code. How can I use the "drawnItems" from Leaflet.draw instead of a given point? I've got a "Cannot read properties of undefined (reading 'type')" error.
    – Vincent Dc
    Commented Feb 18, 2022 at 19:12
  • Try drawnItems.toGeoJSON().features.filter(el => el.geometry.type == 'Point').map(el => el.geometry). It returns an array of element similar to pt.geometry. You need to reuse most of my code in a loop with my additional info.
    – ThomasG77
    Commented Feb 18, 2022 at 22:55

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.