React-mapbox-gl: styling individual features

Created on 24 Apr 2017  路  3Comments  路  Source: alex3165/react-mapbox-gl

this is kind of 2 issues:

  1. segregating layers by feature type
  2. styling individual features (instead of layers)

the docs declare: "The type of the feature is defined at the Layer level. If you want to create a new type, create an associated new layer."

the GeoJSON spec doesn't limit a FeatureCollection to a single type, though. which means if i'm working with an existing valid GeoJSON FeatureCollection of multiple Feature types, i must split the existing FeatureCollection into multiple new FeatureCollections for every feature type. (N collections for N Feature types).

the issue compounds if similar types can have different styles (ie. polygons can have different colors). now i have to split my FeatureCollection into every possible combination of type/style (ie. purple polygons, yellow polygons, yellow lines). for what it's worth, Leaflet offers options for styling a FeatureCollection at the Feature level.

it would be really nice to just create a layer, loop through my Features, and render them each as they individually as they require. am i missing something? or must i really split out existing valid FeatureCollections based on their type/style combinations before i can work with them?

thanks for a great library!!

Most helpful comment

the issue compounds if similar types can have different styles (ie. polygons can have different colors). now i have to split my FeatureCollection into every possible combination of type/style (ie. purple polygons, yellow polygons, yellow lines). for what it's worth, Leaflet offers options for styling a FeatureCollection at the Feature level.

It is possible to use data-driven styling that should at least cover this case. If there's complex logic for conditional styling, you'll need to apply some function to your input GeoJSON and store the result as a property. Could be as simple as a color property on each feature as an output of some function that considers multiple properties.

If you have multiple conceptual layers within your FeatureCollection, it's not unreasonable (IMO) to need to split those out into coherent groups before attempting to work with them. It's a similar difficultly as determining what should be done with a GeometryCollection, and it is very pervasive: e.g. what is the geometric centre of a geometry collection containing a point, a line, and six polygons? What does fill-color mean to such a collection? And so on.

But even if you'd rather keep just one collection, it's already possible to include a filter property on the Mapbox GL style. For example:

var style = {
  'greyStyle': {
    'layout': {
      "visibility": "visible"
    },
    'paint': {
      "fill-color": "#16161d",
      "fill-opacity": 0.2
    },
    'options': {
      'layer': {
        'filter': ["all",
          ["==", "foo", true]
        ]
      }
    }
  }
};

Then you could have a second style that has 'filter': ["all", ["==", "foo", false]] that handles the opposite case. You would then add two layers, possibly sharing the same source, but using two different layer layerOptions that handle the filtering. This way, you don't need to modify your FeatureCollection at all:

<GeoJSONLayer
  id={"my-layer"}
  before={"some-other-layer"}
  data={myFeatureCollection}
  fillLayout={style.greyStyle.layout}
  fillPaint={style.greyStyle.paint}
  layerOptions={style.greyStyle.options.layer}
/>

All 3 comments

the issue compounds if similar types can have different styles (ie. polygons can have different colors). now i have to split my FeatureCollection into every possible combination of type/style (ie. purple polygons, yellow polygons, yellow lines). for what it's worth, Leaflet offers options for styling a FeatureCollection at the Feature level.

It is possible to use data-driven styling that should at least cover this case. If there's complex logic for conditional styling, you'll need to apply some function to your input GeoJSON and store the result as a property. Could be as simple as a color property on each feature as an output of some function that considers multiple properties.

If you have multiple conceptual layers within your FeatureCollection, it's not unreasonable (IMO) to need to split those out into coherent groups before attempting to work with them. It's a similar difficultly as determining what should be done with a GeometryCollection, and it is very pervasive: e.g. what is the geometric centre of a geometry collection containing a point, a line, and six polygons? What does fill-color mean to such a collection? And so on.

But even if you'd rather keep just one collection, it's already possible to include a filter property on the Mapbox GL style. For example:

var style = {
  'greyStyle': {
    'layout': {
      "visibility": "visible"
    },
    'paint': {
      "fill-color": "#16161d",
      "fill-opacity": 0.2
    },
    'options': {
      'layer': {
        'filter': ["all",
          ["==", "foo", true]
        ]
      }
    }
  }
};

Then you could have a second style that has 'filter': ["all", ["==", "foo", false]] that handles the opposite case. You would then add two layers, possibly sharing the same source, but using two different layer layerOptions that handle the filtering. This way, you don't need to modify your FeatureCollection at all:

<GeoJSONLayer
  id={"my-layer"}
  before={"some-other-layer"}
  data={myFeatureCollection}
  fillLayout={style.greyStyle.layout}
  fillPaint={style.greyStyle.paint}
  layerOptions={style.greyStyle.options.layer}
/>

@kn0ll Sorry for the very late reply, if you have a valid Geojson that you want to display I would rather suggest to use the component GeoJSONLayer rather than a combination of Layer and Feature components. I would use Layer and Feature when you want more control over the elements you want to display on the map like complexe user interactions or make a feature draggable ...

Also now with the version 2.3 of react-mapbox-gl you can listen for mouse events on your GeoJSONLayer component.

If you still think there a need for an API change please feel free to open a new issue with a quick explanation of your problem and eventually some example / propositions of new API.

@alex3165 following on this.

Is the <Source> and <Layer> approach supposed to work with a GeoJSON including a GeometryCollection ? (Points and Polygons)

Mapbox.gl seem to support it (see here), along with the source and layer approach.

I understand GeoJSONLayer is kinda "more suited" for this, but I personally need some very complex stuff, not achievable with that : multiple layers of same type, multiple complex filters on different layers of the same type, etc..

Also, duplicating the "data" is not an option I guess, so I have no chance to use GeoJSONLayer

Was this page helpful?
0 / 5 - 0 ratings