Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mask mapbox-gl map with arbitrary polygon

Tags:

mapbox-gl

I am using mapbox-gl and downloaded vector tiles from osm2vectortiles.org

I'd like to have the map visible only within an known polygon, and cannot find any way to pull this off.

I can imagine a couple ways to approach the problem, and every path has lead me to no answers. Here are some approaches I've tried to research:

  1. Some kind of map-masking layer. (Concept doesn't seem to exist)
  2. Draw the polygon and fill outside it instead of inside it. (Seems you can only fill inside polygons)
  3. Draw a filled box around the outer bounds of the map, and cutout the polygon. (MultiPolygon Features seem to stack instead of cutout)
  4. Modify the mbtiles to pretend everything outside the polygon is water. (https://github.com/mapbox/mbtiles-cutout seemed promising, but I can't seem to get it to work)

What's the right way to approach this problem?

like image 691
James Maroney Avatar asked Mar 10 '23 14:03

James Maroney


1 Answers

All of the options you've mentioned could work. You can cut the original vector data to fit the mask region(as in option 4) or you can draw a mask layer on top of your data(option 3).

Here is how you can do it with a mask layer:

https://jsfiddle.net/kmandov/cr2rav7v/

enter image description here

Add your mask as a fill layer:

 map.addSource('mask', {
    "type": "geojson",
    "data": polyMask(mask, bounds)
  });

  map.addLayer({
    "id": "zmask",
    "source": "mask",
    "type": "fill",
    "paint": {
      "fill-color": "white",
      'fill-opacity': 0.999
    }
  });

You can create your mask in advance (say with QGis, or turf) or you can cut the mask directly in the browser using turf:

function polyMask(mask, bounds) {
  var bboxPoly = turf.bboxPolygon(bounds);
  return turf.difference(bboxPoly, mask);
}

var bounds = [-122.5336, 37.7049, -122.3122, 37.8398]; // wsen 

var mask = turf.polygon([
  [
    [-122.43764877319336,
      37.78645343442073
    ],
    [-122.40056991577148,
      37.78930232286027
    ],
    [-122.39172935485838,
      37.76630458915842
    ],
    [-122.43550300598145,
      37.75646561597495
    ],
    [-122.45378494262697,
      37.7781096293495
    ],
    [-122.43764877319336,
      37.78645343442073
    ]
  ]
]);

Probably, you would like to prevent the user from going outside of the mask boundaries by providing maxBounds:

var map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/light-v9',
  center: [-122.42116928100586, 37.77532815168286],
  maxBounds: bounds,
  zoom: 12
});

Note that there seems to be a bug and you need to set fill-opacity to something like 0.999

like image 115
kmandov Avatar answered Apr 06 '23 07:04

kmandov