React-native-mapbox-gl: [v6] SymbolLayer with style { iconName:{token} }

Created on 16 Oct 2017  路  11Comments  路  Source: nitaliano/react-native-mapbox-gl

Thanks for your work on the v6 branch!

I am trying to add a Mapbox.SymbolLayer with a style with an iconName value as a token. All other ways work (commented bellow)!

const styles = Mapbox.StyleSheet.create({
    reports: {
        // iconImage: 'min-pin-with-incident',
        // iconImage: 'min-pin',
        // iconImage: require('../assets/min-pin-with-incident'),
        iconImage: '{icon}',
    },
})

And in my component's render method:

...
render() {
  return (
    <Mapbox.MapView>
      <Mapbox.ShapeSource id="reports" shape={sources.reports}>
        <Mapbox.SymbolLayer id="reports" style={styles.reports} />
      </Mapbox.ShapeSource>
    </Mapbox.MapView>
  )
}
...

Here is the data for my Mapbox.ShapeSource (sources.reports):

{"type":"FeatureCollection","features":[{"type":"Feature","id":"9d10456e-bdda-4aa9-9269-04c1667d4552","properties":{"icon":"min-pin"},"geometry":{"type":"Point","coordinates":[-117.20611157485109,52.18096108426141]}}]}

Not sure if it has been tested and implemented yet, but it seems it is when reading the docs https://github.com/mapbox/react-native-mapbox-gl/blob/v6/docs/SymbolLayer.md.

Here is the warning I am getting. Looks like the token is not parsed and replaced.
```
Could not find image file:///Users/karlguillotte/Library/Developer/CoreSimulator/Devices/C534294E-62BB-47EC-BFBA-FAF5A60C27BE/data/Containers/Bundle/Application/15739B69-797E-42D1-AE98-4088E74D3F5F/AvCanMobile.app/%7Bicon%7D.png

bug v6

All 11 comments

@karlguillotte thanks for posting this, the docs are auto generated from the json style spec, so they might be slightly ahead. I'll look into it and get it working.

Just wanted to update this ticket. I have a working implementation on iOS I just need to do the Android implementation then the PR will land.

The API I have in mind is below the ShapeSource will now be responsible for declaring any external images that we want to add to our geojson source, this will also ensure that the images are being cleaned up out of memory when the source is no longer in use.

const styles = Mapbox.StyleSheet.create({
    reports: {
        iconImage: '{icon}',
    },
})

...

const featureCollection = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
      properties: {
        icon: 'example',
      },
      geometry: {
        type: 'Point',
        coordinates: [
          -117.20611157485,
          52.180961084261,
        ],
      },
    },
  ],
};

...

render() {
  return (
    <Mapbox.MapView>
      <Mapbox.ShapeSource id="reports" shape={featureCollection} images={{ example: require('./example.png')}}>
        <Mapbox.SymbolLayer id="reports" style={styles.reports} />
      </Mapbox.ShapeSource>
    </Mapbox.MapView>
  )
}

@karlguillotte would you mind testing this branch out. I also added an example for this here.

Thanks @nitaliano ! It is working, but now I am a bit confused about how icons are read. In the documentation, it is stated they are coming from the sprite. See the scenarios below.

First, here is the data used in the scenarios.

const data = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
            properties: {
                icon: 'beer-15',
                otherIcon: 'min-pin',  // part of the app assets
            },
            geometry: {
                type: 'Point',
                coordinates: [-118.98783, 51.42952],
            },
        },
        {
            type: 'Feature',
            id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
            properties: {
                icon: 'bicycle-15',
                otherIcon: 'min-pin-with-incident',  // part of the app assets
            },
            geometry: {
                type: 'Point',
                coordinates: [-120.26662, 50.65807],
            },
        },
    ],
}

Scenario A - Working as expected with dynamic icons

const style = Mapbox.StyleSheet.create({
    icon: {
        iconImage: '{icon}',
    }
}
...
render() {
    return [
        <Mapbox.MapView styleURL={Mapbox.StyleURL.Outdoors}>
            <Mapbox.ShapeSource id="test" shape={data}>
                <Mapbox.SymbolLayer id="test" style={style.icon} />
            </Mapbox.ShapeSource>
        </Mapbox.MapView>,
    ]
}
...

Scenario B - Working as expected with static icons

const style = Mapbox.StyleSheet.create({
    icon: {
        iconImage: 'min-pin', // this is an image part of my app assets, it works with 'min-pin-with-incident as well'
    }
}
...
render() {
    return [
        <Mapbox.MapView styleURL={Mapbox.StyleURL.Outdoors}>
            <Mapbox.ShapeSource id="test" shape={data}>
                <Mapbox.SymbolLayer id="test" style={style.icon} />
            </Mapbox.ShapeSource>
        </Mapbox.MapView>,
    ]
}
...

Scenario C - However does not work with dynamic icons coming from the app assets


const style = Mapbox.StyleSheet.create({
    icon: {
        iconImage: {otherIcon}, // now using another property
    }
}
...
render() {
    return [
        <Mapbox.MapView styleURL={Mapbox.StyleURL.Outdoors}>
            <Mapbox.ShapeSource id="test" shape={data}>
                <Mapbox.SymbolLayer id="test" style={style.icon} />
            </Mapbox.ShapeSource>
        </Mapbox.MapView>,
    ]
}
...

Why is scenario C not working?

@karlguillotte for dynamic image we are not searching in Images.xcassets it is coming from the javascript.

If you did

import otherIcon from './otherIcon.png';

...

<MapboxGL.ShapeSource ... images={{ 'min-pin': otherIcon }}>
...
</MapboxGL.ShapeSource>

it would work and this is a solution that works cross platform. I've avoided having to look in Images.xcasserts on iOS and res on Android. If this is a valuable feature to add I have no problem implementing it.

We will still need to be able to register these images with the Maps SDK on the native sides so we could do something like

<MapboxGL.ShapeSource ... images={{ 'my-js-img': jsIcon, assets: ['min-pin'] }} />

@karlguillotte I just pushed some more commits to the branch. I added support for pulling images out of *.xcassets on iOS and drawables dir on Android. The example has been updated.

Thanks @nitaliano ! Busy working n another project now, but I will give it a try early next week.

Closing this out since the fix has been merged into the v6 branch, if you run into any more issues we can reopen.

@nitaliano I have been testing with the images property and it working well! Thanks.

@karlguillotte What does your images property looks like in Scenario A ?
Thanks

@KevinHu2014 'min-pin' like in the Scenario B - but the value is stored in a icon property of every features in my GeoJSON feature collection. More details can be found here.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

igor9silva picture igor9silva  路  3Comments

smoll picture smoll  路  4Comments

olofd picture olofd  路  3Comments

max-prokopenko picture max-prokopenko  路  4Comments

yaduc picture yaduc  路  3Comments