1

I'm new in Turf JS and I have a polygon with a negative offset like:

const coords= [
  [25.085416706126708,55.1561039686203],
  [25.085351117322578,55.15612542629241],
  [25.08549687017286,55.15618711709976],
  [25.08557703416652,55.15636146068573],
  [25.085567317321594,55.15644192695618],
  [25.085411847697962,55.15658676624298],
  [25.085487153321573,55.15664041042328],
  [25.085615901538485,55.156659185886376],
  [25.085598897064752,55.15631586313248],
  [25.085535737570268,55.15617907047272]
];

const polygon = L.polygon(coords, { fillColor: 'orange', fillOpacity: 0.5, weight: 20, color: 'white', opacity: 0.5, fill: true});
const buffer = turf.buffer(polygon.toGeoJSON(), -3, { units: 'meters' });

const buffered = L.geoJSON(buffer, {
  color: 'orange',
  weight: 15,
  lineJoin: "miter",
  //lineCap: "round",
  opacity: 0.5,
  fillOpacity: 0
}).addTo(map);

    map.on('zoomend', function (e) {
       map.eachLayer(function (layer) {
          layer.setStyle({ weight: map.getZoom() > 16 ? (75 / Math.pow(2, 19 - map.getZoom())) : 15 });
          layer.bringToFront();
       });
    }

but is missing some areas when drawn on the map, like:

enter image description here

The real polygon shape, without offset (or offset set to 0) is

enter image description here

If I'm increasing the weight to the polygon with offset, a larger area will be missing and the same thing happen for smaller polygons with closer lines.

In the jsfiddle, the orange offset polygon should go around the red one (on the inside) but is missing some small areas. It should fill that small area from inside, even if the offset polygon borders are overlapping

Edit: I'm trying to achieve the just darker line from a polygon that has filling enter image description here

For example, if I have a polygon with 40m border and filling color, 20m of the border will overlap the filling color. That area is what I'm trying to achieve. I'm changing the border width when the zoom changes to keep the same 40m. Is there a way to draw it using Turf JS?

6
  • It all depends on what are you trying to achieve with this negative buffer polygon. Visual effect of original polygon and buffer polygon together is mixture of thick lines with pixel width that does now change with zoom and buffer offset which changes with zoom, so there is different visual effect depending on zoom.
    – TomazicM
    Jul 5 at 9:39
  • @TomazicM Added details to the question. Please let me now if there is something else that I need to add
    – LAffair
    Jul 5 at 10:31
  • 1
    The turf buffer algorithm will clip self intersecting areas and will create a Multipolygon Jul 5 at 11:56
  • @bloigge I see... Is something that I can use instead?
    – LAffair
    Jul 5 at 12:14
  • Please edit your question and add more relevant code of how you change border width when the zoom changes.
    – TomazicM
    Jul 5 at 12:51

1 Answer 1

1

Basic principle to create polygon with custom inner and outer border, where each part of polygon (inner border, outer border, interior) has it's own style, using turf.js library, would be:

  • Create polygon buffer with positive offset with turf.buffer method, then create difference between buffer and polygon with turf.difference method. Resulting polygon is outer border.
  • Create polygon buffer with negative offset with turf.buffer method, then create difference between polygon and buffer turf.difference method. Resulting polygon is inner border. If negative buffer polygon is empty, whole polygon gets role of inner border.
  • Use buffer with negative offset as polygon interior. If negative buffer is empty, polygon has no interior.

Polygon with custom border is then feature group consisting of those three polygons.

Code could then look something like this:

function polygonWithCustomBorder(coords, polyStyle, outerBorderStyle, innerBorderStyle) {
  var polygonGroup = L.layerGroup({
    interactive: true
  });

  var polygon = L.polygon(coords, {
    stroke: false,
    fill: true,
    fillOpacity: 0,
  });
  polygon.addTo(polygonGroup);
  
  var polyGeoJSON = polygon.toGeoJSON();
  
  var outerBuffer = turf.buffer(polyGeoJSON, outerBorderStyle.width, {units: 'meters'});
  var outerDiff = turf.difference(outerBuffer, polyGeoJSON);     
  var outerBorder = L.geoJSON(outerDiff, {
    weight: 0,
    lineJoin: "miter",
    fillOpacity: outerBorderStyle.opacity,
    fillColor: outerBorderStyle.color
  }).addTo(polygonGroup);
  
  var innerBuffer = turf.buffer(polyGeoJSON, -innerBorderStyle.width, {units: 'meters'});
  if (innerBuffer)
    var innerDiff = turf.difference(polyGeoJSON, innerBuffer);
  else {
    var innerDiff = polyGeoJSON;
  }
  var innerBorder = L.geoJSON(innerDiff, {
    weight: 0,
    lineJoin: "miter",
    fillOpacity: innerBorderStyle.opacity,
    fillColor: innerBorderStyle.color
  }).addTo(polygonGroup);

  if (innerBuffer) {
    var innerPolygon = L.geoJSON(innerBuffer, {
      weight: 0,
      lineJoin: "miter",
      fillOpacity: polyStyle.fillOpacity,
      fillColor: polyStyle.fillColor
    }).addTo(polygonGroup);
  }

  return polygonGroup;
}

An example of creating polygon with the above function:

const coords = [
  [25.085416706126708,55.1561039686203],
  [25.085351117322578,55.15612542629241],
  [25.08549687017286,55.15618711709976],
  [25.08557703416652,55.15636146068573],
  [25.085567317321594,55.15644192695618],
  [25.085411847697962,55.15658676624298],
  [25.085487153321573,55.15664041042328],
  [25.085615901538485,55.156659185886376],
  [25.085598897064752,55.15631586313248],
  [25.085535737570268,55.15617907047272]
];   

var polygon = polygonWithCustomBorder(
  coords,
  {fillOpacity: 0.2, fillColor: 'red'},
  {width: 5, color: 'blue', opacity: 0.5},
  {width: 3, color: 'red', opacity: 0.5}
);
polygon.addTo(map);

Here's how it looks like:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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