百度地图官方提供了点聚合的插件
image.png需要引入两个插件
一个是
MarkerClusterer
,TextIconOverlay
https://lbs.baidu.com/index.php?title=jspopular3.0/guide/conflux
通过这个文档里面的script标签引入
通过new BMapLib.MarkerClusterer
传入map实例,生成一系列的cluster专属的marker点,在地图缩放层级较低时聚合成一个大点,逐渐放大后散开成为一些小点。
类参考:http://api.map.baidu.com/library/MarkerClusterer/1.2/docs/symbols/BMapLib.MarkerClusterer.html
遇到的问题:
1. 如果两个点完全重合,即使放大到最大层级,也不想让它们散开,因为散开可能会给别人误以为只有一个点,聚合起来起码上面写着数字,不至于产生误解
解决:
在new的时候传入maxZoom: 20,因缩放层级最大是19,这个maxZoom的作用是放大级别超过多少时不再聚合,默认值是18,所以我们给到20,就能保证无论放大到多大,都会聚合相近的,如果还有问题,就传入 gridSize,调整聚合时计算的距离,例如 girdSize: 10
2. 希望点击聚合物的时候,能触发点击事件,并且拿到改聚合物下的marker,(一些业务数据可以写在marker上);
解决:
MarkerClusterer并没有提供点击事件,源码里面只设置了调整视口
- 找了一些网上的方法,循环给cluster加上click 的 eventListener,没生效
- https://segmentfault.com/q/1010000010479568, 有提供一些解决方案,但是尝试后没生效
思路:
-
没法侵入源码覆盖,因为这个是写在Cluster类上的,Cluster对外部来说是匿名的,所以如果要尝试修改源码,只能把这整个插件拉下来,不再用在线地址,作为自己的js代码,手动改,但是这应视项目情况而定。
-
可以监听整个map实例的点击,但是没法判断当前点击的是什么东西,即便是拿到click参数里的target,这个target也是map实例,没发区分点击的还是marker还是聚合物还是其他空地
但是可以拿到点击的坐标,另外我们能拿到所有的cluster,每个cluster有个_center
属性是一个坐标,我们以center坐标为中心,20px向外发散,形成一个正方形 Bounds,(20px是因为我的聚合物在地图上的图标是40px宽高)
这样子每个cluster都有一个Bounds,就是范围,我们判断点击的坐标是否在某个Bounds里面,那么符合条件的cluster就是我们要找的了。
抄一下扩散Bounds的源码,这个方法等会要用到
var getExtendedBounds = function(map, bounds, gridSize){
// bounds = cutBoundsInRange(bounds);
var pixelNE = map.pointToPixel(bounds.getNorthEast());
var pixelSW = map.pointToPixel(bounds.getSouthWest());
pixelNE.x += gridSize;
pixelNE.y -= gridSize;
pixelSW.x -= gridSize;
pixelSW.y += gridSize;
var newNE = map.pixelToPoint(pixelNE);
var newSW = map.pixelToPoint(pixelSW);
return new BMap.Bounds(newSW, newNE);
};
我们可以在 map点击中拿到point,
const target = this.markerClusterer._clusters.filter(clus=>clus._isReal).find(clus=>{
const bounds = getExtendedBounds(this.map, new BMap.Bounds(clus._center,clus._center), 20)
return bounds.containsPoint(arg.point)
})
markerClusterer
是new出来的聚合插件的实例,_clusters是地图上所有的聚合物(包括未展示的)的集合,cluster有个isReal属性,如果地图缩放导致聚合物散开了,这个属性就是false,反之聚合起来了的话,就又会变成true,所以通过这个属性过滤掉没展示的,然后再通过cluster的中心点生成bounds,通过bounds.containsPoint判断点击的point是否在区域范围内
如果找到了target的话,可以通过target._markerClusterer._markers
拿到该聚合物下的所有marker
网友评论