4

当用户单击集群时,我试图显示所有标记。

这是我到目前为止所做的:

map.on('click', function (e) {
    var cluster_features = map.queryRenderedFeatures(e.point, {
        layers: [
            'cluster-0',
            'cluster-1',
            'cluster-2'
        ]
    });
    var cluster_feature = cluster_features[0];
    if (cluster_feature && cluster_feature.properties.cluster) {
        map.jumpTo({
            around: e.lngLat,
            zoom: map.getZoom() + 2
        });
    }
});

每次用户单击标记时,这都会增加 2 级缩放。它可以工作,但有时我需要放大更多才能看到标记。

关于如何通过单击放大到实际标记的任何建议?

4

3 回答 3

2

鉴于 Mapbox-gl 的当前版本,这是一个有点复杂的解决方案0.37.0

当用户单击集群时,我正在尝试显示所有标记

鉴于这一说法,有两种可能的解决方案。

  1. 在下一个缩放级别显示标记和集群或
  2. 显示所有标记(与缩放级别无关)。

其中mapbox-gl,集群功能由supercluster提供。

截至0.37.0目前,当您通过以下方式设置源时,没有直观的 API 可以自定义超集群的工作方式map.addSource...

因此,您可能需要在使用的入口文件中使用/导入超集群作为库依赖项mapbox-gl(通过 npm 或其他方式)。

1. 使用 supercluster 查找标记去簇时的下一个缩放级别。

在超集群中,您可以使用方法getClusterExpansionZoom(clusterId, clusterZoom),这将为您提供所选集群的下一次缩放,从中可以看到标记(无论是1,2,4,n zoomlevelscurrentZoomLevel.

var supercluster = require('supercluster');

let features;

map.on('load', function(e) {
  features = supercluster().load(FEATURES);
});

// helper function
function findNearestCluster(map, marker, i) {
  let clusterSelected = marker;
  // get bounds
  let south = map.getBounds()._sw;
  let north = map.getBounds()._ne;
  let bounds = [south.lng, south.lat, north.lng, north.lat];

  let currentClusters = i.getClusters(bounds, Math.floor(map.getZoom()));

  let compare = {
    lng: clusterSelected.geometry.coordinates[0],
    lat: clusterSelected.geometry.coordinates[1]
  };

  let minClusters = currentClusters.map(cluster => {
    let lng = cluster.geometry.coordinates[0];
    let lat = cluster.geometry.coordinates[1];

    return {
      id: cluster.properties.cluster_id,
      geometry: cluster.geometry,
      value: Math.pow(compare.lng - lng,2) * Math.pow(compare.lat-lat,2)
    };
  });

  return minClusters.sort(function(a,b) {
    return a.value - b.value;
  });
}

map.on('click', function (e) {
  var cluster_features = map.queryRenderedFeatures(e.point, {
    layers: [
      'cluster-0',
      'cluster-1',
      'cluster-2'
    ]
  });

  var cluster_feature = cluster_features[0];

  // we need to find the nearest cluster as 
  // we don't know the clusterid associated within supercluster/map
  // we use findNearestCluster to find the 'nearest' 
  // according to the distance from the click
  // and the center point of the cluster at the respective map zoom

  var clusters = findNearestCluster(map, cluster_feature, features);
  var nearestCluster = clusters[0];

  var currentZoom = Math.floor(map.getZoom());
  var nextZoomLevel = supercluster()
      .getClusterExpansionZoom(nearestCluster.id, currentZoom);  

  if (cluster_feature && cluster_feature.properties.cluster) {
    map.jumpTo({
      around: e.lngLat,
      zoom: nextZoomLevel
    });
  }
});

2. 显示所有标记(与缩放级别无关)。

我们做与上面类似的事情,但是我们可以使用. 而不是只使用nextZoomLevel/ 。getClusterExpansionZoomgetLeaves

getLeaves 返回集群中的所有标记 -

var clusters = findNearestCluster(map, cluster_feature, features);
var nearestCluster = clusters[0];

var currentZoom = Math.floor(map.getZoom());

var getLeaves = supercluster()
    .getLeaves(nearestCluster.id, currentZoom, Infinity);  

从这里,您可以根据mapbox.Markers需要渲染叶子,类似于leaflet.markercluster.

第二种解决方案的问题是,每当视图发生更改时,您都需要删除/更新标记,以反映地图视图的当前位置。

从自上而下的角度来看,这没问题,但是如果您开始旋转,视图渲染会有点卡顿,所以从 UI 角度来看,我不建议这样做。

于 2017-06-13T10:11:29.980 回答
0

正如@MeltedPenguin 所说(在MapBox - Cluster Zooming中)。你可以在没有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)

在我的页面上,我有 2 层基于相同的数据源但具有不同的属性。一种定义所有点(无簇),另一种定义点和簇。对于我的显示,我使用带有集群的“markers_layer”,并计算距离和我使用另一个的东西,作为点的数据库。

资源:

  @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]]
于 2018-07-13T12:28:50.813 回答
0

如果你从 cluster_features 中每个点的坐标构造一个 lineString 然后做了一个zoomTo-lingstring

于 2017-05-30T21:01:15.250 回答