最近接到一个新的需求,要在高德地图实现marker点的聚合,想实现的功能是能够按缩放比例或者按省市区级别实现聚合。
翻了一下高德API,发现示例里面只有【 AMap.MarkerClusterer】 插件实现的点聚合。【 AMap.MarkerClusterer】的点聚合通过一些简单的算法通过网格的像素大小来实现聚合,当然也可以通过maxZoom的设置来设置最大的聚合级别,大于该级别就不进行相应的聚合(要理解到位:聚合级别越小,同屏下展示的地图越大)。这并不是我们想要的效果。
下面贴2个图理解下maxZoom的配置:
下面贴上我的代码,看看我是如何实现的,有问题大家及时交流:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<style type="text/css">
body,html,#container{height: 100%;margin: 0px;font:12px Arial;}
.circle{border-radius: 50%;border: solid 1px silver;width: 50px;height: 50px;padding: 3px;text-align: center;line-height: 25px;max-width: 50px;color:#fff;}
.showtitle{background:#393;width:150px;height:30px;line-height:30px;color:#fff;border-radius:5px;padding-left:5px;}
.showtitle i{font-size:16px;}
.showcontent{background:#62ab00;width:300px;font-size:12px;margin-left:-80px;border-radius:5px;color:#fff;position:absolute;display:none;bottom:30px;z-index:99;}
.showcontent .p{line-height:30px;padding-left:10px;margin-top:-0px;}
.showcontent i.triangle_i{color:#62ab00;font-size:25px;display:block;width:100%;background:#fff;text-align:center;height:25px;}
.showcontent i.close_i{position: absolute;right: 5px;top:5px;font-size:25px;z-index:99999;}
</style>
<link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.css">
<link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
<script src="http://www.w3school.com.cn/jquery/jquery.js"></script>
<title>高德地图Marker实现聚合效果</title>
</head>
<body>
<div id="container" tabindex="0"></div>
<div id="tip">可以缩放地图,得到缩放级别哦!<br><span id="info"></span></div>
<script src="./marker.js"></script>
<script src="https://webapi.amap.com/maps?v=1.4.1&key=de46cac2667f7b246a14192b88ba619d"></script>
<script type="text/javascript">
$(function(){
//弹出框关闭
$('.showtitle').live('click',function(){
$(this).prev('.showcontent').toggle();
})
$('.close_i').live('click',function(){
$(this).parent().hide();
})
})
//初始化地图容器
var map = new AMap.Map('container', {
resizeEnable: true,
zoom: 5,
zooms:[4,18],
center: [106.49, 34.60]
});
//设置地图比例尺
AMap.plugin(['AMap.Scale'],
function(){
map.addControl(new AMap.Scale());
});
//添加监听时间,当前缩放级别
AMap.event.addListener(map,'zoomend',function(){
document.getElementById('info').innerHTML = '当前缩放级别:' + map.getZoom();
});
var markersTwo;
var markersThree;
var createMarker = function(data,hide) {
var div = document.createElement('div');
div.className = 'circle';
var r = Math.floor(data.count / 1024);
div.style.backgroundColor = hide ?'#393':'#09f';
var htmlData='<div>'+data.name+'</div><div>'+data.count+'</div>';
div.innerHTML = htmlData;
var marker = new AMap.Marker({
content: div,
title:data.name,
position: data.center.split(','),
offset: new AMap.Pixel(-24, 5),
zIndex: data.count,
});
marker.subMarkers = [];
if(data.name==='山东省'||data.name==='河南省'||data.name==='济南市'||data.name==='天桥区'){
marker.setLabel({content:'←请点击',offset:new AMap.Pixel(45,0)})
map.setCenter(marker.getPosition());
}
if(!hide){
marker.setMap(map)
}
if(data.subDistricts&&data.subDistricts.length){
for(var i = 0 ; i<data.subDistricts.length;i+=1){
marker.subMarkers.push(createMarker(data.subDistricts[i],true));
}
}
return marker;
}
var _onZoomEnd = function(e) {
console.log('监听地图缩放')
if (map.getZoom() < 7) {//全国下的省份
for (var i = 0; i < markers.length; i += 1) {
map.remove(markers[i].subMarkers);
}
map.add(markers);
}else if((map.getZoom() < 9) && (map.getZoom() > 7)){//省份下的市
for (var i = 0; i < markersTwo.length; i += 1) {
map.remove(markersTwo[i].subMarkers);
}
map.add(markersTwo);
}else if(map.getZoom() < 14 && map.getZoom() > 9){//市下面的区或县
for (var i = 0; i < markersThree.length; i += 1) {
map.remove(markersThree[i].subMarkers);
}
map.add(markersThree);
}
}
var _onClick = function(e) {
console.log(e)
if(e.target.subMarkers.length){
map.add(e.target.subMarkers);
map.setFitView(e.target.subMarkers);
markersTwo=e.target.subMarkers;
var subMarkersTwo=e.target.subMarkers;
for (var j = 0; j < subMarkersTwo.length; j += 1) {
AMap.event.addListener(subMarkersTwo[j], 'click', _onClickTwo);
AMap.event.addListener(subMarkersTwo[j], 'mouseover', _onMouseoverTwo);
AMap.event.addListener(subMarkersTwo[j], 'mouseout', _onMouseoutTwo);
}
map.remove(markers)
}
}
var _onMouseover = function(e) {
var div = e.target.getContent();
div.style.backgroundColor = '#393';
e.target.setContent(div);
}
var _onMouseout = function(e) {
var div = e.target.getContent();
div.style.backgroundColor = '#09f';
e.target.setContent(div);
}
var _onClickTwo = function(e) {
if(e.target.subMarkers.length){
map.add(e.target.subMarkers);
map.setFitView(e.target.subMarkers);
map.setZoom(11);
markersThree=e.target.subMarkers;
var subMarkersThree=e.target.subMarkers;
for (var j = 0; j < subMarkersThree.length; j += 1) {
AMap.event.addListener(subMarkersThree[j], 'click', _onClickThree);
AMap.event.addListener(subMarkersThree[j], 'mouseover', _onMouseoverThree);
AMap.event.addListener(subMarkersThree[j], 'mouseout', _onMouseoutThree);
}
map.remove(markersTwo)
}
}
var _onMouseoverTwo = function(e) {
var div = e.target.getContent();
div.style.backgroundColor = '#09f';
e.target.setContent(div);
}
var _onMouseoutTwo = function(e) {
var div = e.target.getContent();
div.style.backgroundColor = '#393';
e.target.setContent(div);
}
var _onClickThree = function(e) {
if(e.target.subMarkers.length){
map.add(e.target.subMarkers);
map.setFitView(e.target.subMarkers);
var subMarkersFour=e.target.subMarkers;
for (var j = 0; j < subMarkersFour.length; j += 1) {
var title = e.target.subMarkers[j].getTitle();
var html='<div class="showcontent"><div class="p">公司名称:'+title+'</div><div class="p">联系方式:'+title+'</div><i class="fa triangle_i"></i><i class="fa close_i"></i></div><div class="showtitle"><i class="fa"></i> '+title+'</div>';
e.target.subMarkers[j].setContent(html);
}
map.remove(markersThree)
}
}
var _onMouseoverThree = function(e) {
var div = e.target.getContent();
div.style.backgroundColor = '#09f';
e.target.setContent(div);
}
var _onMouseoutThree = function(e) {
var div = e.target.getContent();
div.style.backgroundColor = '#393';
e.target.setContent(div);
}
var markers = []; //province见Demo引用的JS文件
for (var i = 0; i < provinces.length; i += 1) {
var marker = createMarker(provinces[i]);
markers.push(marker);
AMap.event.addListener(marker, 'click', _onClick);
AMap.event.addListener(marker, 'mouseover', _onMouseover);
AMap.event.addListener(marker, 'mouseout', _onMouseout);
}
map.setFitView();
AMap.event.addListener(map, 'zoomend', _onZoomEnd);
</script>
<script type="text/javascript" src="https://webapi.amap.com/demos/js/liteToolbar.js"></script>
</body>
</html>
到这里其实还有一个很重要的一步,就是从后台拿数据,类似于这样的数据,即可实现不同的级别下展示该级别下的marker:
var provinces = [ {
"id": "15",
"name": "山东省",
"center": "117.000923,36.675807",
"count": 12500,
"subDistricts": [{
"id":370100,
"name": "济南市",
"center": "117.000923,36.675807",
"count": 10000,
"subDistricts": [
{
"name": "历下区",
"center": "117.0768,36.66661",
"count": 10000
},
{
"name": "市中区",
"center": "116.99741,36.65101",
"count": 10000
},
{
"name": "槐荫区",
"center": "116.90075,36.65136",
"count": 10000
},
{
"name": "天桥区",
"center": "116.98749,36.67801",
"count": 10000,
"subDistricts": [
{
"name": "济南长途客运中心",
"center": "116.984658,36.677631",
"count": 10000
},
{
"name": "山东交通学院东区",
"center": "116.964788,36.68152",
"count": 10000
},
{
"name": "西苑小区(中区)",
"center": "116.966677,36.687509",
"count": 10000
},
{
"name": "金牛建材",
"center": "116.97659,36.694391",
"count": 10000
},
{
"name": "济南师范小学",
"center": "116.990752,36.694804",
"count": 10000
},
]
},
{
"name": "历城区",
"center": "117.06509,36.67995",
"count": 10000
},
{
"name": "长清区",
"center": "116.75192,36.55352",
"count": 10000
},
{
"name": "平阴县",
"center": "116.45587,36.28955",
"count": 10000
},
{
"name": "济阳县",
"center": "117.17327,36.97845",
"count": 10000
},
{
"name": "商河县",
"center": "117.15722,37.31119",
"count": 10000
},
{
"name": "章丘市",
"center": "117.53677,36.71392",
"count": 10000
},
]
}];