效果图
介绍
这是一个百度地图自定义聚合样式和图层控制拓展方法的API。
在百度官方版本的基础上拓展了自定义方法,具体见下方说明。
百度地图聚合原理
百度的点聚合算法 是基于方格和距离的聚合算法,即开始的时候地图上没有任何已知的聚合点,然后遍历所有的点,去计算点的外包正方形(由gridSize指定),若此点的外包正方形与现有的聚合点的外包正方形不相交,则新建聚合点,若相交就把该点加到该聚合点,巨日如下图:
实现源码
/**
* 根据所给定的标记,创建聚合点
* @return 无返回值
*/
MarkerClusterer.prototype._createClusters = function(){
var mapBounds = this._map.getBounds();
var extendedBounds = getExtendedBounds(this._map, mapBounds, this._gridSize);
for(var i = 0, marker; marker = this._markers[i]; i++){
if(!marker.isInCluster && extendedBounds.containsPoint(marker.getPosition()) ){
this._addToClosestCluster(marker);
}
}
};
/**
* 根据标记的位置,把它添加到最近的聚合中
* @param {BMap.Marker} marker 要进行聚合的单个标记
*
* @return 无返回值。
*/
MarkerClusterer.prototype._addToClosestCluster = function (marker){
var distance = 4000000;
var clusterToAddTo = null;
var position = marker.getPosition();
for(var i = 0, cluster; cluster = this._clusters[i]; i++){
var center = cluster.getCenter();
if(center){
var d = this._map.getDistance(center, marker.getPosition());
if(d < distance){
distance = d;
clusterToAddTo = cluster;
}
}
}
if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)){
clusterToAddTo.addMarker(marker);
} else {
var cluster = new Cluster(this);
cluster.addMarker(marker);
this._clusters.push(cluster);
}
};
拓展方法说明
MarkerClusterer.js
-
增加属性
type
{Number} 自定义类型,用于方便控制隐藏和显示
name
{String} 自定资源名称,用于方便控制隐藏和显示
markerControl
{Boolean} 是否需要控制maker显示/隐藏,需要控制maker会默认被隐藏,否则直接显示 -
拓展方法
addLabel()
// 对于单个点 添加自定义label
addCustomizeMarker()
// 对于单个点 添加自定义marker
TextIconOverlay.js
-
增加属性
type
{Number} type 表示资源类型 -
修改属性
text
由{String}改为{Json Object} // 表示该覆盖物显示的文字信息 -
拓展方法
_updateClassName()
// 更新覆盖物的类名
使用说明
- 引入资源
<script type="text/javascript" src="//api.map.baidu.com/api?v=3.0&ak=您的密钥"></script>
<script type="text/javascript" src="TextIconOverlay.js"></script>
<script type="text/javascript" src="MarkerClusterer.js"></script>
- Html部分
<!-- 地图容器 -->
<div id='map'></div>
- Js部分 (代码基于Vue)
// 定义地图
var map;
// 初始化百度地图
baiduMapInit: function() {
var self = this;
// 百度地图API功能
map = new BMap.Map(baidumapOptions.mapDiv,{
enableMapClick: false, // 禁用景点,场所等点击事件
minZoom: baidumapOptions.zoom
}); // 创建Map实例
map.centerAndZoom(new BMap.Point(baidumapOptions.center[1],baidumapOptions.center[0]), baidumapOptions.zoom); // 初始化地图,设置中心点坐标和地图级别
map.setMapStyle({ style: 'midnight' });
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
},
// 添加聚合点
createClustersMarker: function(markers,type,name){
var markerClusterer = new BMapLib.MarkerClusterer(map, {
markers: markers,
minClusterSize: 3, //最小的聚合数量,小于该数量的不能成为一个聚合,默认为2
type: type, // 资源类型
name: name, // 资源名称
markerControl: false, // 是否控制marker
styles: [{
textColor: '#fff',
backgroundColor: '#0080ff',
size: new BMap.Size(26, 26)
}]
});
},
// 获取警力(警员/警车/移动警务)
getPolice: function(){
var self = this;
// ... 省略无关代码
var policeMan = res.data.policeMan;
// 警力 [31|警员] - 地图点聚合需要
if(policeMan.length){
var markers = [];
var type = '31';
var name = 'jy';
policeMan.map(function(item){
if(item.jd && item.wd){
var point = new BMap.Point(item.jd, item.wd);
var marker = new BMap.Marker(point);
// marker携带自定义参数
marker.customData = {
"type": type,
"name": name,
"jd": item.jd,
"wd": item.wd,
"bmmc": item.bmmc,
"xm": item.xm,
}
marker.addEventListener('click', function(e){
// 绑定点击事件
});
markers.push(marker);
} else{
console.log('当前警员没有经纬度:', item);
}
});
// 给地图添加聚合点
self.createClustersMarker(markers,type,name);
}
// ... 省略无关代码
},
// 地图缩放、拖拽之后重新设置地图图层状态
chechMapLayerStatus(){
// 此处为控制marker显示/隐藏的方法,具体可参考以下示例,
if(item.type == 'xxbz'){ // 信息标识
if(item.checked){
$('.map .facility-xxbz-point').show();
$('.map .map-xxbz-cluster').show();
} else{
$('.map .facility-xxbz-point').hide();
$('.map .map-xxbz-cluster').hide();
}
}
// 说明,
// xxbz 为传递到js中的name属性
},
解决:添加超过2w+个点地图卡
MarkerClusterer.js
addMarker
删除来有打点方法- 新增
render
方法替换原有添加聚合点的方法
/**
* 向该聚合添加一个标记。
* @param {Marker} marker 要添加的标记。
* @return 无返回值。
*/
Cluster.prototype.addMarker = function(marker){
if(this.isMarkerInCluster(marker)){
return false;
}//也可用marker.isInCluster判断,外面判断OK,这里基本不会命中
if (!this._center){
this._center = marker.getPosition();
this.updateGridBounds();//
} else {
if(this._isAverageCenter){
var l = this._markers.length + 1;
var lat = (this._center.lat * (l - 1) + marker.getPosition().lat) / l;
var lng = (this._center.lng * (l - 1) + marker.getPosition().lng) / l;
this._center = new BMap.Point(lng, lat);
this.updateGridBounds();
} //计算新的Center
}
marker.isInCluster = true;
this._markers.push(marker);
/* 以下部分是去除代码
var len = this._markers.length;
if(len < this._minClusterSize ){
this._map.addOverlay(marker); // 官方原版添加marker
this.updateClusterMarker();
return true;
} else if (len === this._minClusterSize) {
for (var i = 0; i < len; i++) {
this._markers[i].getMap() && this._map.removeOverlay(this._markers[i]);
}
}
this._map.addOverlay(this._clusterMarker);
this._isReal = true;
this.updateClusterMarker();
return true;
*/
};
/**
* 进行dom操作
* @return 无返回值
*/
Cluster.prototype.render = function(){
var len = this._markers.length;
if (len < this._minClusterSize) {
for (var i = 0; i < len; i++) {
// this._map.addOverlay(this._markers[i]);
this.addCustomizeMarker(this._markers[i]); // obear 添加自定义marker
}
} else {
this._map.addOverlay(this._clusterMarker);
this._isReal = true;
this.updateClusterMarker();
}
}