是否有可能重新创建点击以放大像Craigslist Mapview一样的MapBox集群?单击时,它会缩放到包含这些位置点的区域。
这是我的群集代码:
map.on('load', function() {
map.addSource("location", {
type: "geojson",
data: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/73873/test.geojson",
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 100
});
map.addLayer({
id: "clusters",
type: "circle",
source: "location",
filter: ["has", "point_count"],
paint: {
"circle-color": {
property: "point_count",
type: "interval",
stops: [
[0, "#71AAC6"],
[100, "#71AAC6"],
[750, "#71AAC6"],
]
},
"circle-radius": {
property: "point_count",
type: "interval",
stops: [
[0, 20],
[100, 30],
[750, 40]
]
}
}
});
这是我的演示
答案 0 :(得分:1)
我认为你不能在纯Mapbox中做到这一点,至少不容易。
但对于那些特定于群集的用法,有Supercluster(一个官方的Mapbox地理空间点聚类库),它正是您想要的:
getClusterExpansionZoom(clusterId)
给定群集的
cluster_id
,返回群集扩展为多个子项的缩放(对“单击缩放”功能很有用)。
编辑:实际上你可以在没有超级集群的情况下完成:
使用此JsFiddle example,您可以检索所点击的群集的点数。
map.on('click', function(e) {
const cluster = map.queryRenderedFeatures(e.point, { layers: ["cluster"] });
if (cluster[0]) {
// features: from the added source that are clustered
const pointsInCluster = features.filter(f => {
const pointPixels = map.project(f.geometry.coordinates)
const pixelDistance = Math.sqrt(
Math.pow(e.point.x - pointPixels.x, 2) +
Math.pow(e.point.y - pointPixels.y, 2)
);
return Math.abs(pixelDistance) <= clusterRadius;
});
console.log(cluster, pointsInCluster);
}
});
然后,您可以使用所有这些点创建mapboxgl.LngLatBounds
和extend
。
fitBounds
,这样就可以了。答案 1 :(得分:1)
正如@MeltedPenguin所说。您无需使用SuperCluster
就可以做到。我搜索了几个答案,最后使用coffeescript做了自己的解决方案(您可以使用http://js2.coffee/之类的工具将其转换回JS):
@clusterRadius = 30
@map.on 'click', (e) =>
features = @map.queryRenderedFeatures(e.point, { layers: ['markers_layer'] });
if features && features.length > 0
if features[0].properties.cluster
cluster = features[0].properties
allMarkers = @map.queryRenderedFeatures(layers:['markers_layer_dot']);
self = @ #just a way to use 'this' un a function, its more verbose then =>
#Get all Points of a Specific Cluster
pointsInCluster = allMarkers.filter((mk) ->
pointPixels = self.map.project(mk.geometry.coordinates) #get the point pixel
#Get the distance between the Click Point and the Point we are evaluating from the Matrix of All point
pixelDistance = Math.sqrt((e.point.x - (pointPixels.x)) ** 2 + (e.point.y - (pointPixels.y)) ** 2)
#If the distant is greater then the disance that define a cluster, then the point si in the cluster
# add it to the boundaries
Math.abs(pixelDistance) <= self.clusterRadius
)
#build the bounding box with the selected points coordinates
bounds = new (mapboxgl.LngLatBounds)
pointsInCluster.forEach (feature) ->
bounds.extend feature.geometry.coordinates
return
#Move the map to fit the Bounding Box (BBox)
@map.fitBounds bounds, {padding:45, maxZoom: 16}
else
window.open('/en/ad/' + features[0].properties.propertyId)
在我的页面上,我有两个基于相同数据源但具有不同属性的图层。一个定义所有点(无簇),另一个定义点和簇。 对于我的显示,我使用带有簇的“ markers_layer”,为了计算距离和东西,我使用另一个作为点的DB。
来源:
@map.addSource "markers_source_wo_cluster",
type: "geojson"
data:
type: "FeatureCollection"
features: []
cluster: false
clusterMaxZoom: 10
clusterRadius: @clusterRadius
@map.addSource "markers_source",
type: "geojson"
data:
type: "FeatureCollection"
features: []
cluster: true
clusterMaxZoom: 60
clusterRadius: @clusterRadius
图层:
##============================================================##
## Add marker layer (Layer for QueryRender all dot without cluster)
##============================================================##
@map.addLayer
id: 'markers_layer_dot'
source: 'markers_source_wo_cluster'
type: "circle"
paint:
"circle-radius": 0 #This are 1 pixel dot for ref only
##============================================================##
## Add marker layer
##============================================================##
@map.addLayer
id: 'markers_layer'
source: 'markers_source'
type: 'symbol'
layout:
'icon-allow-overlap': true
'icon-image':'pin_map'
'icon-size':
stops: [[0,0.4], [40,0.4]]
答案 2 :(得分:0)
我这样解决https://github.com/mapbox/mapbox-gl-js/issues/9707
const handleClusterOnClick = React.useCallback(
(event: LayerMouseEvent) => {
if (event && rawMap) {
const feature = event?.features?.[0];
const source = rawMap.getSource(SOURCE_ID);
if (
feature &&
feature.properties !== null &&
// @ts-ignore
typeof source.getClusterExpansionZoom === "function"
) {
rawMap
.getSource(SOURCE_ID)
// @ts-ignore
.getClusterExpansionZoom(
feature.properties.cluster_id,
(err: Error, expansionZoom: number) => {
if (!err) {
rawMap.flyTo({
// @ts-ignore
center: feature.geometry.coordinates,
zoom: expansionZoom,
animate: true,
essential: true,
});
}
},
);
} else {
rawMap.flyTo({
animate: true,
essential: true,
center: event.lngLat,
zoom: rawMap.getZoom() + 3, // This is bad UX, requires multiple clicks
});
}
}
},
[rawMap],
);