Недавно я смог глубже взглянуть на описанную выше проблему и фактически пришел к решению, которое было достаточно хорошим для моего варианта использования. Есть несколько вариантов решения этой проблемы.
1) Использование другого кластерного решения в сочетании с Mapbox, например, Supercluster
2) Создайте репро Mapbox и добавьте метод, который вызывает метод getClusterLeaves()
из собственного SDK.
Решение 1
Первое решение использует пакет Supercluster npm, и это решение полностью основано на информации, найденной на эту страницу. Я поделюсь кодом, которым я закончил, но для получения дополнительной информации я хотел бы предложить вам прочитать связанный ресурс.
//Initialize supercluster, these values worked great for me
const cluster = new Supercluster({ radius: 40, maxZoom: 16 });
cluster.load(collection.features);
Переменная коллекции, используемая в методе загрузки суперкластера, должна представлять значение FeatureCollection. Которые можно создать несколькими способами. Тот, который мне понравился, был ниже.
const collection = MapboxGL.geoUtils.makeFeatureCollection(groupFeatures);
Переменная groupFeatures может быть массивом, состоящим из объектов, отображаемых на карте. Для облегчения доступа я сохранил переменную кластера в моем состоянии, прежде чем двигаться дальше. Мне нравится хранить вещи отдельно, чтобы мне было легко увидеть, какая часть кода за что отвечает. Итак, мой метод рендеринга выглядит примерно так, как показано ниже.
<MapboxGL.MapView
ref={c => (this._map = c)}
onRegionDidChange={this.updateClusters}
zoomEnabled
style={[{ flex: 1 }]}>
//This is where we render the clusters
{this.renderPoints()}
</MapboxGL.MapView>
Следующим шагом является получение фактических кластеров с помощью суперкластера, для этого нам нужны границы отображаемой карты и текущий уровень масштабирования (с использованием Math.round, поскольку десятичные значения могут привести к ошибкам в суперкластере).
const bounds = await this._map.getVisibleBounds();
const zoom = Math.round(await this._map.getZoom());
const westLng = bounds[1][0];
const southLat = bounds[1][1];
const eastLng = bounds[0][0];
const northLat = bounds[0][1];
Теперь мы можем получать фактические кластеры, делая что-то вроде такого:
const sc = this.state.superCluster;
const clusters = sc.getClusters(
[westLng, southLat, eastLng, northLat],
zoom
)
this.setState({clusters: clusters})
И теперь мы можем визуализировать кластеры в Mapbox Shapesource.
renderPoints = () => {
const { clusters } = this.state;
return (
<MapboxGL.ShapeSource
id="symbolLocationSource"
hitbox={{ width: 18, height: 18 }}
onPress={this.onMarkerSelected}
shape={{ type: "FeatureCollection", features: superClusterClusters }}
>
<MapboxGL.SymbolLayer
id="pointCount"
minZoomLevel={6}
style={mapStyles.clusterCount}
/>
<MapboxGL.CircleLayer
id="clusteredPoints"
minZoomLevel={6}
belowLayerID="pointCount"
filter={[">", "point_count", 1]}
style={mapStyles.clusteredPoints}
/>
<MapboxGL.SymbolLayer
id="symbolLocationSymbols"
minZoomLevel={6}
filter={["!", ["has", "point_count"]]}
style={mapStyles.icon}
/>
</MapboxGL.ShapeSource>
);
}
Итак, теперь последний кусок головоломки, мы можем получить фактические листья кластера. В последней части приведенного выше кода я уже добавил метод onMarkerPressed для onPress. Здесь мы получаем листья кластера.
onMarkerSelected = event => {
const point = event.nativeEvent.payload;
const { name, cluster } = point.properties;
if (cluster) {
const sc = this.state.superCluster;
const points = sc
.getLeaves(point.properties.cluster_id, Infinity)
//This will output an array with all leaves of the selected cluster
console.log(points);
}
}
Решение 2
Таким образом, упомянутое выше решение - это решение, которое я выбрал для моей собственной ситуации. Поэтому я не исследовал решение разветвления репродукции Mapbox и добавления к нему функциональности. Однако я нашел несколько указателей, которые помогут вам начать работу по ссылке здесь и здесь
person
MikeSli
schedule
16.10.2019