首页 > 解决方案 > Leaflet + Supercluster:L.marker 的 autoPan 不工作

问题描述

我正在使用 mapbox 超集群库来聚类相当大量的点数据,并在闪亮的应用程序中使用传单将其绘制出来。如果位置错误,则显示这些点maxZoom并且可以为用户拖动。Mapbox supercluster 使用静态 kdbush 空间索引,因此每次L.marker移动 a 时,都会重新加载集群(在我的情况下这不是问题,因为 supercluster 非常快)。

但是,只能L.marker在可见地图边界内拖动使用超集群。这是有道理的,因为L.marker's 仅针对可见地图边界动态生成。如果L.marker使用选项定义,则在将其拖到可见地图范围之外{draggable:true,autoPan:true}时会发生错误:L.marker

Uncaught TypeError: t is null
  leaflet 1.3.3/dist/leaflet.js:5
  leaflet 1.3.3/dist/leaflet.js:5
  at https://unpkg.com/leaflet@1.3.3/dist/leaflet.js:5
  _adjustPan https://unpkg.com/leaflet@1.3.3/dist/leaflet.js:5
  _adjustPan self-hosted:891
  _adjustPan self-hosted:844

或在我闪亮的应用程序中,我收到以下错误:

Uncaught TypeError: Cannot set property '_leaflet_pos' of null
at Object.Lt [as setPosition] (eval at <anonymous> (jquery.min.js:2), <anonymous>:5:9959)
at e._adjustPan (eval at <anonymous> (jquery.min.js:2), <anonymous>:5:71149)

将某种 autopan forL.marker用于超集群会非常酷。我知道用户可以缩小以将点拖动到预期位置。在我的情况下,这并不是一个真正的选择,因为在可见地图范围内很快就会有太多的点会减慢地图的平移速度(这就是我首先使用聚类的原因)。

我试图在拖动事件期间使用panTo

layer.on('drag',function(e){
//console.log('marker dragstart event');
var position=e.target.getLatLng();
map.panTo(new L.latLng(position.lat,position.lng));
});

但这似乎以某种方式停止了拖动事件。

我的问题是:有没有办法让自动平移L.marker与超集群一起使用?

我在下面设置了一个最小的可重现示例。这个例子绘制了一个单点 ( var marker) 以及三个点 ( var markers) 与超集群。可以将单个点拖到可见地图范围之外,而聚类点则不能。

var map = L.map('map').setView([51.505, -1.09], 9);

L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);

var marker = new L.marker([51.505, -1.09],{
    draggable: true,
    autoPan:true
}).bindPopup('autopan working').addTo(map);

// Empty Layer Group that will receive the clusters data on the fly.
var markers = L.geoJson(null, {
  pointToLayer: createClusterIcon,
  onEachFeature: onEachFeature
}).addTo(map);

var clusterData = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties":{
        "id":0
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-1.0,51.5]
      }
    },
    {
     "type": "Feature",
     "properties":{
        "id":1
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-1.1,51.6]
      }
    },
    {
    "type": "Feature",
    "properties":{
        "id":2
      },
     "geometry": {
        "type": "Point",
        "coordinates": [-0.9,51.4]
     }
    }
    ]
}
        
function onEachFeature(f, layer) {          
    //add drag event
    layer.on('drag',function(e){
    //console.log('marker dragstart event');
    //var position=e.target.getLatLng();
    //map.panTo(new L.latLng(position.lat,position.lng));
    });
  layer.on('dragend',function(e){
    //console.log('marker dragend event');
    var changedPos = e.target.getLatLng();
    //console.log('new location '+changedPos);
    //load cluster again
    clusterData.features[f.properties.id].geometry.coordinates[1]=changedPos.lat;
    clusterData.features[f.properties.id].geometry.coordinates[0]=changedPos.lng;
    index.load(clusterData.features);
    update();
  });
}

     
// Update the displayed clusters after user pan / zoom.
map.on('moveend', update);

function update() {
    if (!ready) return;
    var bounds = map.getBounds();
    var bbox = [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];
    var zoom = map.getZoom();
    var clusters = index.getClusters(bbox, zoom);
    //console.log('clusters '+clusters);
    markers.clearLayers();
    markers.addData(clusters);
}


// Zoom to expand the cluster clicked by user.
markers.on('click', function(e) {
    //console.log('check data' + e.layer.feature.properties.cluster_id);
  var clusterId = e.layer.feature.properties.cluster_id;
  var center = e.latlng;
  var expansionZoom;
  if (clusterId) {
    expansionZoom = index.getClusterExpansionZoom(clusterId);
    map.flyTo(center, expansionZoom);
    } 
});


var ready = false;
//load data
const index = new Supercluster({
    radius: 150,
    maxZoom:10
});
index.load(clusterData.features);
ready= true;
update();


function createClusterIcon(feature, latlng) {
    if (!feature.properties.cluster){ 
        return L.marker(latlng,{draggable:true,autoPan:true}); //add autoPan:true
    }
  
  var count = feature.properties.point_count;
  var size =
    count < 100 ? 'small' :
    count < 1000 ? 'medium' : 'large';
  var icon = L.divIcon({
    html: '<div><span>' + feature.properties.point_count_abbreviated + '</span></div>',
    className: 'marker-cluster marker-cluster-' + size,
    iconSize: L.point(40, 40)
  });
  return L.marker(latlng, {
    icon: icon
  });
}
#map {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}
<script src="https://unpkg.com/supercluster@7.1.0/dist/supercluster.min.js"></script>
<link href="https://cdn.rawgit.com/mapbox/supercluster/v4.0.1/demo/cluster.css" rel="stylesheet"/>
<script src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css" rel="stylesheet"/>
<div id="map"></div>

标签: leafletmapbox

解决方案


推荐阅读