@react-native-mapbox-gl/maps 中的标记聚类

Adn*_*Ali 2 mapbox mapbox-gl mapbox-gl-js mapbox-marker react-native-mapbox-gl

我正在使用@react-native-mapbox-gl/maps,我想实现标记的聚类。我找不到任何适合我的实施的解决方案。附加图像将显示两个标记应该合并,但事实并非如此。

在此输入图像描述

下面我粘贴我的代码:

<MapboxGL.MapView
      showUserLocatin={true}
      zoomLevel={10}
      zoomEnabled={zoomEnabled}
      pitchEnabled={true}
      onPress={onMapPress}
      onRegionIsChanging={onRegionIsChanging}
      surfaceView={true}
      rotateEnabled={rotateEnabled}
      compassEnabled={false}
      showUserLocation={false}
      userTrackingMode={MapboxGL.UserTrackingModes.None}
      scrollEnabled={scrollEnabled}
      styleURL={styleURL}
      centerCoordinate={getFocusPoint() || getStartingPoint()}
      ref={(c) => (_map = c)}
      onRegionDidChange={onRegionChange}
      style={style}
      cluster
    >
      {renderLines()}
      <MapboxGL.SymbolLayer
        id={'abc'}
        sourceID={MapboxGL.StyleSource.DefaultSourceID}
      />
      <MapboxGL.Camera
        zoomLevel={zoom}
        centerCoordinate={getFocusPoint() || getStartingPoint()}
      />
      {(simplePlaceData?.length > 0 || places?.length > 0) && renderMarkers()}
    </MapboxGL.MapView>
Run Code Online (Sandbox Code Playgroud)

下面是我们的 renderMarkers 函数(基本上我在 MapboxGL.PointAnnotation 中显示任何 RN 组件,例如图像/图标):

const renderMarkers = () => {
    if (simplePlaceData)
      return simplePlaceData?.map((_place) => {
        const {lat, lng, id} = _place
        const latVal = parseFloat(lat)
        const lngVal = parseFloat(lng)
        if (!lat || !lng || isNaN(latVal) || isNaN(lngVal)) return null

                return (
                    <MapboxGL.PointAnnotation
                        key={`${id}`}
                        id={`${id}`}
                        title={`${lat}-${lng}`}
                        coordinate={[parseFloat(lng), parseFloat(lat)]}>
                     <Col style={styles.mapMarkers}>
              <Icon
                name={'map-marker'}
                family={'materialCommunity'}
                color={Colors.linkBlue}
                size={31}
              />
            </Col>
                    </MapboxGL.PointAnnotation>
                )
            })
        else
            return places?.length > 0 &&  places.map(_place => {
                const {lat, lng, id, image, name} = _place.trip_place.place
                const isSelected = (getFocusPoint() || getStartingPoint())?.first() == lng &&
                    (getFocusPoint() || getStartingPoint())?.last() == lat
                if (Platform.OS === 'ios') {
                    return (
                        <MapboxGL.PointAnnotation
                            key={`${id}`}
                            id={`${id}`}
                            title={name}
                            coordinate={[parseFloat(lng), parseFloat(lat)]}
                        >
                            <MapMarker
                                image={{uri: image}}
                                imageSize={isSelected ? 41 : 31}
                                style={isSelected ? styles.mapMarkersSelected : styles.mapMarkers}
                                onPress={() => selectPlace(_place.trip_place.place, true)}
                            />
                        </MapboxGL.PointAnnotation>
                    )
                } else {
                    return (
                        <MapboxGL.MarkerView
                            id={`${id}`}
                            key={`${id}`}
                            coordinate={[parseFloat(lng), parseFloat(lat)]}
                            title={name}
                        >
                            <View style={isSelected ? styles.mapMarkerContainerSelected : styles.mapMarkerContainer}>
                                <MapMarker
                                    image={{uri: image}}
                                    imageSize={isSelected ? 41 : 31}
                                    style={isSelected ? styles.mapMarkersSelected : styles.mapMarkers}
                                    onPress={() => selectPlace(_place.trip_place.place, true)}
                                />
                            </View>
                        </MapboxGL.MarkerView>
                    )
                }
            })
    }
Run Code Online (Sandbox Code Playgroud)

是否有任何解决方案可以申请 MapboxGL.PointAnnotation 将标记显示为内部包含多个项目的组合簇?或者我可以使用 MapboxGL 的另一个组件来实现此功能?

谢谢

Ami*_*ssi 11

因此,根据我使用 React Native Mapbox GL 的经验,您不能使用点注释进行聚类。您必须使用图标。要使其发挥作用,您必须记住的一条规则是您的标记必须是 GEO JSON 要素集合。如果您不知道那是什么,请查看下面的链接。 https://enterprise.arcgis.com/en/geoevent/latest/ingest/GUID-F489B3D2-74DB-4EA2-8A4E-330628193843-web.png 获得特征集合后,将其输入 Shapsource,集群应该启动出现。

 <MapboxGL.ShapeSource
            ref={shapeSource}
            shape={{ type: 'FeatureCollection', features: [...''] }}
            id="symbolLocationSource"
            hitbox={{ width: 18, height: 18 }}
            onPress={async point => {
              if (point.features[0].properties.cluster) {
                const collection = await shapeSource.current.getClusterLeaves(
                  point.features[0],
                  point.features[0].properties.point_count,
                  0,
                )
                // Do what you want if the user clicks the cluster
                console.log(collection)
              } else {
                // Do what you want if the user clicks individual marker

                console.log(point.features[0])
              }
            }}
            clusterRadius={50}
            clusterMaxZoom={14}
            cluster
          >
Run Code Online (Sandbox Code Playgroud)

为了在放大后显示标记的单独图片;您需要从单个标记获取图像。因此,如果您有一个要素集合,每个要素都应该有一个图像,您可以使用存储在项目文件夹中的图像并替换符号中的 iconImage 属性。或者,如果您的功能有指向图像的链接,您可以在功能中使用该属性,如下所示:

 iconImage: ['get', '___ whatever name you gave the link___'],

Run Code Online (Sandbox Code Playgroud)
 <MapboxGL.SymbolLayer
              id="singlePoint"
              filter={['!', ['has', 'point_count']]}
              style={{
                iconImage: ['get', '___ whatever name you gave the link___'],
                iconSize: 0.3,
                iconHaloColor: 'black',
                iconHaloWidth: 10,
                iconColor: 'white',
                iconHaloColor: 'black',
                iconHaloWidth: 400,
                iconAllowOverlap: true,
              }}
            />
Run Code Online (Sandbox Code Playgroud)

为了让它显示出来,你需要mapbox图像

  <MapboxGL.Images
            images={images}
            onImageMissing={async url => {
              setImages({ ...images, [url]: { uri: await getImage(url) } })
            }}
  />
Run Code Online (Sandbox Code Playgroud)

因此,我们对链接执行的 get 请求将调用 Mapbox 图像。只需确保您有图像,并在您的状态下设置图像即可。然后,您将可以显示点注释的当前图像。唯一的问题是它很难编辑,所以你不能只让它们显示为圆圈,除非它们以这种方式裁剪。

   <MapboxGL.MapView
          style={styles.map}
          ref={mapRef}
          styleURL="___ url___"
          zoomEnabled
        >
          <MapboxGL.Camera
            animationDuration={250}
            ref={ref => (this.camera = ref)}
            minZoomLevel={5}
            zoomLevel={6}
            maxZoomLevel={20}
            animationMode="flyTo"
            centerCoordinate={currrentLocation}
            Level={stateZoomLevel}
          />
   
          <MapboxGL.Images
            images={images}
            onImageMissing={async url => {
              setImages({ ...images, [url]: { uri: await getImage(url) } })
            }}
          />
          {/* Cluster Individual Drop View */}
          <MapboxGL.ShapeSource
            ref={shapeSource}
            shape={{ type: 'FeatureCollection', features: [...''] }}
            id="symbolLocationSource"
            hitbox={{ width: 18, height: 18 }}
            onPress={async point => {
              if (point.features[0].properties.cluster) {
                const collection = await shapeSource.current.getClusterLeaves(
                  point.features[0],
                  point.features[0].properties.point_count,
                  0,
                )
                // Do what you want if the user clicks the cluster
                console.log(collection)
              } else {
                // Do what you want if the user clicks individual marker

                console.log(point.features[0])
              }
            }}
            clusterRadius={50}
            clusterMaxZoom={14}
            cluster
          >
            <MapboxGL.SymbolLayer
              id="pointCount"
              style={layerStyles.clusterCount}
            />
            <MapboxGL.UserLocation
              visible
              onUpdate={location => {
                setCurrentLocation({
                  latitude: location.coords.latitude,
                  longitude: location.coords.longitude,
                })
              }}
            />
            <MapboxGL.CircleLayer
              id="clusteredPoints"
              belowLayerID="pointCount"
              filter={['has', 'point_count']}
              style={{
                circlePitchAlignment: 'map',
                circleColor: '#A59ADD',
                circleRadius: [
                  'step',
                  ['get', 'point_count'],
                  20,
                  100,
                  25,
                  250,
                  30,
                  750,
                  40,
                ],
                circleOpacity: 0.84,
                circleStrokeWidth: 0,
                circleStrokeColor: 'blue',
              }}
            />
            <MapboxGL.SymbolLayer
              id="singlePoint"
              filter={['!', ['has', 'point_count']]}
              style={{
                iconImage: ['get', '__image name___'],
                iconSize: 0.3,
                iconHaloColor: 'black',
                iconHaloWidth: 10,
                iconColor: 'white',
                iconHaloColor: 'black',
                iconHaloWidth: 400,
                iconAllowOverlap: true,
              }}
            />
          </MapboxGL.ShapeSource>
        </MapboxGL.MapView>

const layerStyles = {
  singlePoint: {
    circleColor: 'green',
    circleOpacity: 0.84,
    circleStrokeWidth: 2,
    circleStrokeColor: 'white',
    circleRadius: 5,
    circlePitchAlignment: 'map',
  },
  clusteredPoints: {},
  clusterCount: {
    textField: '{point_count}',
    textSize: 12,
    textPitchAlignment: 'map',
  },
}
Run Code Online (Sandbox Code Playgroud)

如果这有助于投票!