mapbox-gl-js
mapbox-gl-js copied to clipboard
A new fill paint property to mask areas outside region of interest or polygon
This is a feature request. The implementation details are unknown.
Motivation
As a map designer, a common cartographic technique for me to focus the user attention to an area of interest is to mask/hide details of the areas outside the region of interest.
To accomplish such an effect with the existing GL style-spec, one needs to create a polygon covering the whole world with a hole of the desired region. This is a cumbersome and tedious data creation process for a map designer.
Design Alternatives
- A new
fill-region: 'inside'<default> | 'outside'
property for the existing fill layer. The 'outside' value would apply all the paint properties to all areas outside of the polygons in the layer if set https://github.com/mapbox/mapbox-gl-js/issues/6267#issuecomment-369928098 - ~~A new
inverted-fill
layer type which will apply a fill style to all areas outside of a polygon~~ - ~~New
inverted-fill-x
properties for all existing fill properties~~
Design
Adding a new fill-region
paint property is simple and communicates clearly to the user where the paint is applied in relation with the polygon.
~~Feel that maybe a new inverted-fill
layer type might be the simplest with respect to keeping the style-spec clean~~
Mock-Up
What will this design look like to developers?
map.addLayer({
'id': 'area of interest',
'source': 'aoi',
'type': 'fill',
'layout': {},
'paint': {
'fill-region': 'outside',
...any supported fill properties
}
});
What will this design look like to end users?
Image source: inverted fill in qgis
Concepts
fill-region
is the new concept that would be introduced. This feature is called "inverted polygon" in qgis.
Another alternative would be to add a fill-region: 'inside' | 'outside'
property to the existing fill layer.
This feature would make it easier for the map designer, avoiding the need to use turf.mask. See prior discussion for this feature at #993 and #6257.
While masks work great for maps without symbol layers, one challenge are labels near the borders of the mask. This proposal is likely out-of-scope for this particular bug, but it's important to consider when creating masks.
We need this feature in our application and I am willing to work on it to make it happen.
What we need is to invert the 'water' layer - we need a 'land' layer to place above a custom layer where we render wave height and ocean currents. And because it is such a large dataset for the water layer, we would really like to not have to download, invert offline and upload it again.
(Or, we would need a way to mask our custom layer with the water layer, but I think an inverted fill
is more usable.)
I have implemented a proof-of-concept (/hack) of @mourner 's suggestion from https://github.com/mapbox/mapbox-gl-js/issues/993#issuecomment-74130793 to invert geojson on-the-fly inside mapbox, but did not manage to do the same with vector tiles.. Would that be feasible?
I would like some guidance so that I don't develop something that cannot be merged.
I've worked on this a bit more, taking another approach than the one mentioned above. Instead I'm using the stencil buffer to mask the polygon and then fill the tile.
Still lots of work to be done, but at least this looks like it will work.
Is this feature planned?
@waissbluth I've received no indication that this would be accepted if I opened a pull request. I still need this for a customer project, but it is on low priority right now.
@markusjohnsson Do you have a public fork you'd be willing to share? Looks like a wondrous start—is the "inverse" fill styled the same way I would style a fill
-type layer?
This is orthogonal to the request for masking, but in case anyone is coming here looking for a way to effectively dim the background layer outside an area of interest without blotting it out entirely, I shared a simple approach towards the end of this workshop at State of the Map U.S. 2018.
Is there any feature like this (mask areas outside polygon) in Mapbox iOS SDK ? Appreciate for the answer!
The new within
expression https://blog.mapbox.com/introducing-gl-js-v1-9-0-and-the-within-expression-6268f6c32be3 may help with some of the use cases here. It will let you apply a different style to points and lines outside a polygon.
The new
within
expression https://blog.mapbox.com/introducing-gl-js-v1-9-0-and-the-within-expression-6268f6c32be3 may help with some of the use cases here. It will let you apply a different style to points and lines outside a polygon.
Sorry, but I mean in Mapbox iOS SDK, not in mapbox-gl-sj.
Sorry, but I mean in Mapbox iOS SDK, not in mapbox-gl-sj.
I was commenting in general about this thread, not in response to your question.
@fvonk, as of mapbox/mapbox-gl-native-ios#184 and v5.8.0, you can use a SELF IN %@
expression, which is equivalent to the within
expression seen here. However, it only works on whole features in shape or vector tile sources; it won’t cut up a single feature that happens to be partially inside your region of interest.
You can use turf's mask function for that https://www.npmjs.com/package/@turf/mask Simply create a "cover polygon" with the extend of your (Map)View (or the whole world) and use your Polygon. Turf even creates the "cover polygon" for you, if you do not provide one. https://github.com/Turfjs/turf/blob/master/packages/turf-mask/index.js#L58
Has there been any update to the status of this feature request?
We are currently using the solution that leverages turf-mask to invert the geometries. But in our case, it is too cumbersome to render on the client, so we are processing them as tilesets.
In order to avoid the high cost of processing 10m resolution tiles that span the entire planet, we are forced to use a maxzoom value of 5. This results in a 300m resolution, which is not ideal.
This feature seems like the only solution to our problem.
It's a shame that within
can only be applied to point and line geometries, not everything else.
@boredland yeah, and that lines won't get clipped to the bounds either, they're either all in or out :(