Search code examples
leafletmapboxturfjs

Mapbox Overlapping Circles


Does anyone know a way to make overlapping circles in mapbox show the same color and only have the border around the outer edge display?

I have this: enter image description here

And I made this in photoshop for what I want: enter image description here


Solution

  • While I don't think there is a way to style all the circles to show their group outline, you can achieve the effect you want by creating a union of all the circle geometries and applying your style to that. Unfortunately, Leaflet's L.circle class offers no way to access a circle's geometry beyond the center point, and to perform a union, you need the path of the circle itself. Fortunately, there is Leaflet Geodesy and its LGeo.circle class, which produces circular polygons with a given radius and number of segments. Once you have these polygon representations of your circles, you can use turf.union to produce the outline you want.

    Say you are starting with a layer of points called pointLayer (this can be a L.geoJson, L.mapbox.featureLayer, or any other class that inherits the .eachLayer method). You can then iterate over the features, creating a circular polygon for each of them and adding it to a temporary layer group, like this:

    var circleLayer = L.layerGroup();
    var radius = 5000
    var opts = {
      parts: 144
    };
    pointLayer.eachLayer(function(layer) {
      LGeo.circle(layer.getLatLng(), radius, opts).addTo(circleLayer);
    });
    

    where radius is in meters and the parts option is the number of segments you want your polygons to have. Next, use the .getLayers method to get an array of all the layers in the temporary group, then iterate over that to create a union of all the features:

    var circleUnion = unify(circleLayer.getLayers()).addTo(map);
    
    function unify(polyList) {
      for (var i = 0; i < polyList.length; ++i) {
        if (i == 0) {
          var unionTemp = polyList[i].toGeoJSON();
        } else {
          unionTemp = turf.union(unionTemp, polyList[i].toGeoJSON());
        }
      }
      return L.geoJson(unionTemp, {style: unionStyle});
    }
    

    where unionStyle is whatever style you want to apply to your newly-combined circles. Here is an example fiddle showing all this with some random data:

    http://fiddle.jshell.net/nathansnider/L2d626hn/