Hey,
filtering seems to be off in a few cases:
SymbolLayers, but they don't seem to work on FillLayer nor LineLayerfilter={[
'all',
['>', 'scale', 1],
['<', 'scale', 2],
]}
Fix for 1: The filter property was not exported in [type]LayerManager.m for Fill, Line, Circle and Extrusion layers. Adding it resolves the issue. Haven't looked at Android yet.
Fix for 2: Recast filters to floatValue whenever possible, or retain type defined in JS side if possible. The filters are currently only evaluated as strings because the entire filter is cast to NSString before processing on the native side.
Thanks for looking into this and figuring out what's happening.
We can send a json blob that describes what each elements in the array is
{
"type": "number",
"value": 12
}
{
"type": "string",
"value": "prop"
}
{
"type": "op",
"value": ">"
}
or on the native side when we assemble the array we can try to parse the string values to numbers which is a dumber version, but might be all we need.
- (void)setFilter:(NSString *)filter
{
_filter = [FilterParser parse:filter];
if (_style != nil) {
[self updateFilter];
}
}
Once we fix 1, 2, 4 we can look into 3 and see if the problem is in the RN or Native layer
Hey,
reg'd 2, I think the JSON blob approach is the right way to go, as the naive parser wouldn't be able to differentiate between the following filters: ['==', 'prop', 1] and ['==', 'prop', '1'].
The JSON blob approach is probably also needed to make interpolate functions behave correctly as well.
There are JSON blobs for anything that is passed into the StyleSheet checkout https://github.com/mapbox/react-native-mapbox-gl/blob/v6-improvements/docs/StyleSheet.md#native-module-json-blob-format
one of the problems is in JS all keys in objects are converted to string so if I write { 1: 'test' } 1 will always be a string, so the assumption that I've been going with is if the key is a parsable number just parse it. One interesting idea for styling functions could be converting it from object based to array based.
object based
fillExtrusionColor: MapboxGL.StyleSheet.source({
0: 'white',
50: 'blue',
100: 'red',
}, 'height', MapboxGL.InterpolationMode.Exponential),
array based
fillExtrusionColor: MapboxGL.StyleSheet.source(
[0, 50, 100],
['white', 'blue', 'red'],
'height',
MapboxGL.InterpolationMode.Exponential,
),
Hey @nitaliano
That is a great idea! I think an array based API aligned with the mapbox style function specification would probably cause the least friction among developers.
A react-native API equivalent would probably be along the lines of:
fillExtrusionColor: MapboxGL.StyleSheet.source(
[
[0, 'white']
[50, 'blue'],
[100, 'red'],
],
'height',
MapboxGL.InterpolationMode.Exponential,
),
where each stop is identified as a [stop, value] array. What do you think?
On a different note, it would also be great if we could modify the base multiplier for the Exponential functions similar to what is possible in the raw style spec.
I really like that! The API will move towards what you posted.
fillExtrusionColor: MapboxGL.StyleSheet.source(
[
[0, 'white']
[50, 'blue'],
[100, 'red'],
],
'height',
MapboxGL.InterpolationMode.Exponential,
),
Once we update the API to be array based, we can look into being able to modify the multipliers for the interpolation modes.
@kristfal I have my first pass at a PR for updating the filtering let me know what you think https://github.com/mapbox/react-native-mapbox-gl/pull/764. I'll work on updating the StyleSheet once we get filtering out of the way
Hey,
filtering looks correct in my tests now. The only remaining issue seems to be that they don't update at runtime or hot reloads. Keep up the good work, this is really nice 馃憤
Update: Filtering on Android still seems a bit off for all layer types when using filtering with an in statement like this:
['in', 'type', 'arc'] or ['in', 'stylegroup', 'mainroad', 'minorroad', 'motorway']
In the above cases, all features are shown. This works though:
['==', 'type', 'arc']
Composite filtering using in is also not working on Android, returning all features (despite any definition beyond the in filter):
['all', ['in', 'type', 'line'], ['==', 'scale', 2]]
@kristfal I think I see the problem I'm passing in a List<Object> when the filter is expecting ...Object so updating the code to pass in a Object[] should fix in and !in
Just pushed a commit. I tested it using
<MapboxGL.VectorSource>
<MapboxGL.FillLayer
id='testFill'
sourceLayerID='road'
filter={[
'all',
['in', 'class', 'motorway'],
['!in', 'class', 'street'],
]}
style={styles.boxFill} />
</MapboxGL.VectorSource>
and it seems to be working now
I also pushed a commit that enables updating filtering at runtime.
I'd love a little more info on how LineLayer filtering works. Is it possible to filter by properties I set on my geoJSON feature?
@nitaliano Looks good regarding filters.
Found one issue: I notice that if I run 2 maps on Android at the same time, the 2nd "clones" the viewport of the first map, and is by itself unresponsive to input gestures. This works fine on iOS.
I just tested, and that issue is also present on master as well, however it was working fine a few commits ago / before I upgraded to RN 0.50.1.
You able to reproduce or want me to track down the culprit and open a new issue on it?
@kristfal a new issue to track it would be good
@butchmarshall yes
Here is a link to the style spec that explains more about filtering https://www.mapbox.com/mapbox-gl-js/style-spec/#other-filter scroll all the way to the bottom to the Filter section.
Essentially if I provide GeoJSON into a shape source I can then filter on those properties, so let's say I have this
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"type": "pizza"
},
"geometry": {
"type": "Point",
"coordinates": [
-118.828125,
37.16031654673677
]
}
},
{
"type": "Feature",
"properties": {
"type": "coffee"
},
"geometry": {
"type": "Point",
"coordinates": [
-124.8046875,
33.43144133557529
]
}
},
{
"type": "Feature",
"properties": {
"type": "ice cream"
},
"geometry": {
"type": "Point",
"coordinates": [
-128.32031249999997,
51.83577752045248
]
}
}
]
}
I can then filter the GeoJSON properties
<MapboxGL.CircleLayer
id='...'
filter={['==', 'type', 'pizza']} />
that would only show features with the property type=pizza
You can also do compound filters
<MapboxGL.CircleLayer
id='...'
filter={[
'all',
['==', 'type', 'pizza'],
['==', 'type', 'coffee']
]} />
Mapbox vector tiles also ships with some default layers on the map as well. You can go to https://www.mapbox.com/studio/tilesets/ to checkout the layers that are on the map, so let's say I wanted to make every street blue I can do
const styles = MapboxGL.StyleSheet.create({
streetLine: {
lineColor: 'blue',
lineWidth: 2
}
});
// when you don't provide an id the VectorSource uses the composite source
// which is built in to the default Mapbox Styles(Street, Dark, Light, Traffic, Outdoors, ...)
<MapboxGL.VectorSource>
<MapboxGL.LineLayer
id='streetFill'
sourceLayerID='road' // road is a layer defined on the map already
style={styles.streetLine}
filter={['in', 'type', 'street']} />
</MapboxGL.VectorSource>
Filtering and runtime styling are very powerful together and you can do some really cool things. Let me know if you have any other questions. I can also add more to the docs section about styling and filtering layers.
I'm going to close out this ticket since we have filtering working as expected now the PR will merge in today
This is amazing. v6 branch is everything I wanted from v5. Thanks for your hard work!
https://github.com/mapbox/react-native-mapbox-gl/blob/v6-improvements/docs/StyleSheet.md#native-module-json-blob-format is down
Most helpful comment
@kristfal a new issue to track it would be good
@butchmarshall yes
Here is a link to the style spec that explains more about filtering https://www.mapbox.com/mapbox-gl-js/style-spec/#other-filter scroll all the way to the bottom to the Filter section.
Essentially if I provide GeoJSON into a shape source I can then filter on those properties, so let's say I have this
I can then filter the GeoJSON properties
that would only show features with the property type=pizza
You can also do compound filters
Mapbox vector tiles also ships with some default layers on the map as well. You can go to https://www.mapbox.com/studio/tilesets/ to checkout the layers that are on the map, so let's say I wanted to make every street blue I can do
Filtering and runtime styling are very powerful together and you can do some really cool things. Let me know if you have any other questions. I can also add more to the docs section about styling and filtering layers.
I'm going to close out this ticket since we have filtering working as expected now the PR will merge in today