背景

当需要在GIS地图上显示的点数据量比较大时,会考虑将多个点汇聚成一个点展示;汇聚后图标上显示一个数字,以表示当前汇聚点包含了多少个原始数据对象。用户可以鼠标点击这些汇聚点查看单个原始数据的详细信息。

GIS数据汇聚展示可以让地图呈现更简洁,美观(如果所有点展开,地图缩小时显示得密密麻麻)。另外更重要的一点是可以提升地图渲染的效率。

方案分析

汇聚算法与地图的放大级别(zoom

size),以及当前屏幕窗口边界范围有关。当地图缩小时,数据需要汇聚,地图放大时数据需要展开。经纬度落在屏幕边界范围外的数据不需要展示,这样可以减少加载的数据量,提升性能(坏处是拖动地图时需要重新加载数据,

实测几十万点的情况下延迟两到三秒,还可以接受)。

有两种实现方式:一种是采用空间搜索算法,在地图视窗变化时根据地图放大层级,搜索半径范围的点汇聚在一起;另一种是将屏幕范围内的地图区域划分多个网格,落到同一个网格类的点汇聚在一起(网格大小根据不同的放大层级指定)。

前一种方案实现复杂,地图放大和缩小时点数据汇聚和展开的效果很平滑。后一种画网格的方式实现比较简单,但效果比较差,数据量,位置分布,离群值都会影响汇聚效果。

汇聚算法只能解决点数据的汇聚,如果地图上同时有线数据,与点相连的;处理不好就会出现放大或者缩小时点与线脱节的情况,很影响呈现效果。这种情况通过画网格的方式是解决不了的。

基于空间搜索的方案,有成熟的开源组件SuperCluster(https://github.com/mapbox/supercluster)可用,实测效果也非常好。在使用的过程中发现有性能瓶颈(不是组件本身的算法瓶颈),由于SuperCluster组件用JS开发的,在前端应用。这就要求后端一次把所有的点数据传到前端,数据量大时传输时间很长。

为解决数据传输性能的问题,需要把汇聚算法放在后台实现,参考SuperCluster的实现逻辑,用。数据在后台汇聚后再传到前台,10几万个点汇聚后通常只有只百个点。传输数据量减小后,性能得到很大提升。