Leaflet.MarkerCluster 0.1 发布
这是一篇来自 Dave Leaver 的客座文章,他是 Leaflet 的活跃贡献者(特别是,他实现了 0.4 版缩放动画改进),也是目前最好的标记聚类插件的作者,该插件将在本文中介绍。
几乎任何拥有地图和标记的人最终都会遇到标记重叠的问题。在我的日常工作中,在 Smartrak 公司,我们经常有客户在地图上拥有成千上万的点。当您缩小地图时,这些标记会重叠,使地图看起来杂乱无章。在某些情况下,即使在最大缩放级别上,标记也会重叠,这使得与它们进行交互变得不可能。此外,在地图上放置大量标记通常会导致性能降低到不可接受的水平。
为了改善这种情况,许多网站使用标记聚类,这是一种在每个缩放级别上将彼此靠近的标记分组在一起的技术。一个很好的例子是 Redfin。我们需要类似的东西,但在 Leaflet 中。本着开源的精神,我们开发并发布了我们的解决方案,以便每个人都能从中受益。因此,我们自豪地向大家介绍 Leaflet.MarkerCluster。
特性
聚类器具有各种很棒的内置行为
- 一切都以惊人的动画方式呈现。当您放大或缩小时,您可以直观地看到哪些聚类变成了哪些标记。
- 它非常快,例如 对 50,000 个点进行聚类 并不是问题。此外,所有繁重的计算都在页面首次加载时完成,之后地图运行流畅。
- 不需要聚类的标记不会被聚类,并且将在相关的缩放级别上可见。
- 当您将鼠标悬停在聚类上时,将显示该聚类中标记的边界。
- 单击聚类将使您放大到其子元素的边界。
- 在最低缩放级别上,如果仍然存在聚类,您可以单击它们以“蜘蛛化”它们,这使得与聚类中单个标记进行交互成为可能(基于 jawj 的 Overlapping MarkerSpidifer)。
- 距离视窗宽度超过一个屏幕宽度的聚类和标记将从地图中移除,以提高性能。
- 与 Leaflet 核心一样,所有功能都可以在移动和桌面浏览器上运行,并且经过测试,可以回溯到 IE6。
- 支持在添加到地图后添加和删除标记(请参阅下面的最佳实践!)。
- 它高度可定制,允许您轻松更改聚类的外观,禁用某些功能,并在聚类交互中添加自定义行为。
用法
使用标记聚类器很简单,只需将您现有的 LayerGroup 用法替换为 L.MarkerClusterGroup
var markers = new L.MarkerClusterGroup();
markers.addLayer(L.marker([175.3107, -37.7784]));
// add more markers here...
map.addLayer(markers);
您还可以对单个标记和聚类使用所有 FeatureGroup 事件(以及 clusterclick
)。
markers.on('clusterclick', function (a) { alert('Cluster Clicked'); });
markers.on('click', function (a) { alert('Marker Clicked'); });
最佳实践
- 为了从聚类器中获得最佳性能,您应该在将其添加到地图之前将所有标记添加到聚类器中(就像我们在示例中所做的那样)。
- 如果您要移动 L.MarkerClusterGroup 中的标记,则必须先将其移除,然后移动,最后重新添加。如果您在标记位于 MarkerClusterGroup 中时移动它,我们无法跟踪它,该标记将丢失。
- 尽管聚类器支持在它位于地图上时添加和删除标记,但它的性能不如在它不在地图上时添加标记时好。如果您需要对
MarkerClusterGroup
中的标记进行大量更新,您可能需要将其从地图中移除,更改标记,然后重新添加。
获取它
您可以在 github 下载页面 上下载最新版本。
技术细节
底层的聚类算法 (MarkerClusterGroup._cluster
) 是简单的贪婪聚类。
foreach marker
if there is a cluster within the clustering distance, join it.
else if there is an unclustered marker within the clustering distance, form a cluster with it.
我们对最大(最底层)缩放级别执行的第一个聚类步骤,然后我们对所有生成的标记和聚类进行聚类,以生成下一个更高的缩放级别,以此类推,直到我们到达顶部。这些聚类存储在一个树中(一个聚类包含其子聚类),具有良好的地理空间特性。我们使用这棵树来优化识别在任何特定缩放级别上屏幕上的标记和聚类。
L.DistanceGrid
L.DistanceGrid
在聚类时提供了一些不错的优化(由 Leaflet 维护者 Vladimir 贡献)。
为了对标记进行聚类,我们需要将每个标记与其他所有标记进行比较,以尝试形成聚类。为了加快这个过程,我们需要减少需要比较的标记集。 DistanceGrid
通过将所有标记放在与我们需要搜索的距离相同的网格上,来实现这一点。然后,当寻找要聚类的标记时,我们只需要查看我们所在的网格方块及其相邻的网格方块中的标记。这可能是一个很大的性能提升,因为我们只查看可能形成聚类的标记。 (查看最初的 PR 以获取数据)
结语
我希望您喜欢使用聚类器并从中学到您想要的一切。如果您在公共网站上使用它,请 给我发电子邮件,以便我查看它,并可能将其链接到 github 网站上。
如果您有任何问题,请在 github 页面 上提交错误报告。
享受!
Dave Leaver。