Search code examples
react-nativereact-native-mapbox-gl

How to add markers / annotations programatically with mapbox and react native


I'm new to react native and cannot find any documentation on how to add markers / annotations programatically to the map using mapbox.

We are using geofire query, which triggers when a point of interest is withing range.

Inside the trigger I want to insert the marker.

All the documentation I found about it is this: https://www.mapbox.com/help/first-steps-react-native-sdk/ which adds the marker during initialization and render.

Here is my code so far

    render () {
        const {navigate} = this.props.navigation;
        return (
          <View style ={{flex: 1, position: 'relative'}}>
            <Mapbox.MapView
                styleURL={Mapbox.StyleURL.Dark}
                zoomLevel={15}
                centerCoordinate={[11.256, 43.770]}
                ref={map => { this.map = map; }}
                style={{flex: 1}}>
                {this.renderAnnotations([11.256, 43.770])}
            </Mapbox.MapView>


            <View style={styles.menuMainContainer}>

                {this.state.menuStatus ? <Animatable.View style={styles.menuSubcontainer}  animation={"bounceIn"}>
                    <View style={{justifyContent: 'space-between', justifyContent: 'center', flex: 1, marginBottom: 50}}>
                      <View style={{flexDirection: 'row', justifyContent: 'space-around'}}>
                        <MenuOptions imageSource={Images.lightIcon} menuTag="trash" name="Basureros"/>
                        <MenuOptions imageSource={Images.lightIcon} menuTag="holes" name="Huecos"/>
                      </View>
                      <View style={{flexDirection: 'row', justifyContent: 'space-around'}}>
                        <MenuOptions imageSource={Images.lightIcon} menuTag="hydrants" name="Hidrantes"/>
                        <MenuOptions imageSource={Images.lightIcon} menuTag="parking" name="Estacionamiento"/>
                      </View>
                      <View style={{flexDirection: 'row', justifyContent: 'space-around'}}>
                        <MenuOptions imageSource={Images.lightIcon} menuTag="others" name="Otros"/>
                      </View>
                    </View>
                  </Animatable.View> : null
                }
            </View>

            <View style ={styles.bottomContainer}>

              <TouchableOpacity  style={styles.buttons}>
                <Text style={styles.buttonText}>Boton_1</Text>
              </TouchableOpacity>
              <TouchableOpacity onPress ={this._takePhotofromCamera} style={styles.buttons}>
                <Text style={styles.buttonText}>Agregar Reportes</Text>
              </TouchableOpacity>
              <TouchableOpacity style={styles.buttons} onPress = {() => this.toggleMenuStatus()}>
                <Text style={styles.buttonText}>Boton_3</Text>
              </TouchableOpacity>
            </View>

      </View>

        )
      }
    }


    renderAnnotations = (location) =>{
        console.log('entro renderan2')
        return(
          <Mapbox.PointAnnotation
            key='pointAnnotation'
            id='pointAnnotation'
            coordinate={location}>

            <View style={styles.annotationContainer}>
              <View style={styles.annotationFill} />
            </View>
            <Mapbox.Callout title='Look! An annotation!' />
          </Mapbox.PointAnnotation>


      )
      }

    this.state.geoQuery.on("key_entered", function(key, location, distance) {
           console.log(key + " is located at [" + location + "] which is within the query (" + distance.toFixed(2) + " km from center)");
this.renderAnnotations();
})

I'm getting: Error: this.renderAnnotations is not a function

I also tried copying the entire function inside this.state.geoQuery, no error, but markers are not showing either.

this.state.geoQuery.on("key_entered", function(key, location, distance) {
       console.log(key + " is located at [" + location + "] which is within the query (" + distance.toFixed(2) + " km from center)");
       return(
         <Mapbox.PointAnnotation
           key='pointAnnotation'
           id='pointAnnotation'
           coordinate={location}>

           <View style={styles.annotationContainer}>
             <View style={styles.annotationFill} />
           </View>
           <Mapbox.Callout title='Look! An annotation!' />
         </Mapbox.PointAnnotation>
     )});

Thanks


Solution

  • After chatting directly with Mapbox support, they told me PointAnnotation is legacy and should use ShapeSource and SymbolLayer instead, it have a LOT better performance. Here is how to do it:

        <Mapbox.MapView
                    key='mainmap'
                    textureMode={true}
                    pitch={60}
                    ref={(c) => this._map = c}
                    onPress={this.onPress}
                    styleURL={Mapbox.StyleURL.Light}
                    zoomLevel={17}
                    maxZoomLevel={20}
                    minZoomLevel={15}
                    centerCoordinate={this.initCenterLocation()}
                    style={{ flex: 1 }}
                    showUserLocation={true}
                    userTrackingMode={Mapbox.UserTrackingModes.FollowWithHeading}
                >
                    <Mapbox.ShapeSource
                        id='exampleShapeSource'
                        shape={this.state.featureCollection}
                        onPress={(feature) => this.onShapeSourceLayer(feature)}
                        images={{ assets: ['pin', 'm1_marker', 'm2_marker', 'm3_marker', 'm4_marker'] }}>
                        <Mapbox.SymbolLayer id='exampleIconName' minZoomLevel={1} style={stylesIcon.icon} />
                    </Mapbox.ShapeSource>
                </Mapbox.MapView>
    

    Insert new annotations / points:

        this.setState({
                featureCollection: Mapbox.geoUtils.addToFeatureCollection(
                    this.state.featureCollection,
                    Mapbox.geoUtils.makeFeature({ type: 'Point', coordinates: location }, { icon: iconImage, key: key }),
                ),
            });
    

    On annotation Press function:

    onShapeSourceLayer(e) {
    
        const feature = e.nativeEvent.payload;
    
        this.setState({
            annotationKey: feature.properties.key
        }, function () {
    
            this.togglePostModal(true)
        });
    
    }