Search code examples
javascriptreact-nativereact-native-iosreact-native-mapbox-gl

React Native using RNFS in order to load and display Mapbox icons stored on the device


Currently I am trying to implement a way to use React-Native to display custom icons on a Mapbox map that are stored on the users device. I thought the example found here (ShapeSourceIcon example for the official documentation as a starting point.

So following the example I came to the following render method:

render() {
  return (
     <MapboxGL.MapView
        ref={map => { this.map = map; }}
        style={styles.map}
        logoEnabled={false}
        onPress={this.onPress}
        onDidFinishLoadingMap={this.finishedLoadingMap}
        styleURL={'custom_url'}>

        <MapboxGL.Camera
            animationMode={'flyTo'}
            animationDuration={2000}
            centerCoordinate={[ 6.16389,52.255 ]}
            zoomLevel={8}/>

       <MapboxGL.Images
           images={{example: exampleIcon}}
       />

       <MapboxGL.ShapeSource 
           id="routes"
           shape={featureCollection}>

           <MapboxGL.SymbolLayer
               id="routes"
               style={exampleStyles.icon}/>
       </MapboxGL.ShapeSource>
  )
}

Below is the feature collection that represents the variable used in the shapesource. which has some small modifications compared to the one found in the link above.

const featureCollection = {
type: 'FeatureCollection',
features: [
  {
    type: 'Feature',
    id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
    properties: {
      icon: 'example',
    },
    geometry: {
      type: 'Point',
      coordinates: [6.1552165, 52.2660751],
    },
  },
  {
    type: 'Feature',
    id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
    properties: {
      icon: 'example',
    },
    geometry: {
      type: 'Point',
      coordinates: [26.542969, -30.221102],
    },
  },
  {
    type: 'Feature',
    id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
    properties: {
      icon: 'example',
    },
    geometry: {
      type: 'Point',
      coordinates: [-117.206562, 52.180797],
    },
  },
 ],
};

The example styles looks like this:

const exampleStyles = {
  icon: {
    iconImage: '{icon}',
  },
};

And the exampleIcon variable is just a simple png imported into the project for now. And this will actually display the icons on the specified positions according to the featureCollection. The next step was for me to load a file using RNFS (React Native File Storage) doing this something like this:

'file://' + RNFS.DocumentDirectoryPath + `/Icons/336.png`

The above code then would replace the exampleIcon in the MapboxGL.Images part of the render method. This will no longer display the icon on the map. So I was thinking it might be impossible to display images like this but as a sort of hail mary I decided to do the following:

const exampleStyles = {
    icon: {
      iconImage: 'file://' + RNFS.DocumentDirectoryPath + `/336.png`,
    },
};

And this would display the icon on the map again so I figured it must be possible to display dynamic icons based on one of these tactics but I'm not sure anymore and the documentation isn't of any help for my perticular situation.


Solution

  • After focussing on other parts of the application for a while I decided to revisit this issue. Since I already made a workaround in the application it wasn't too big of an issue for me anymore. After digging some deeper into the library I finally figured out how to solve it. I needed to replace the iconImage object with something like this:

    const exampleStyles = {
      icon: {
        iconImage: iconImage: ['get' , 'iconID'],
      },
    };
    

    And generating the correct images we needed to provide to mapbox we would loop through all images in the directory and add them to a dictionary like variable like so:

    imagesDic[name] = {uri: 'file://' + RNFS.DocumentDirectoryPath + `/Storage Card/RoutAbel/Icons/${name}.png`};
    

    Pay special attention to the requirement of adding the 'uri:' part.