高德地图Marker实现聚合效果

最近接到一个新的需求,要在高德地图实现marker点的聚合,想实现的功能是能够按缩放比例或者按省市区级别实现聚合。
翻了一下高德API,发现示例里面只有【 AMap.MarkerClusterer】 插件实现的点聚合。【 AMap.MarkerClusterer】的点聚合通过一些简单的算法通过网格的像素大小来实现聚合,当然也可以通过maxZoom的设置来设置最大的聚合级别,大于该级别就不进行相应的聚合(要理解到位:聚合级别越小,同屏下展示的地图越大)。这并不是我们想要的效果。

下面贴2个图理解下maxZoom的配置:


缩放级别为4时的地图
缩放级别为7时的地图

下面贴上我的代码,看看我是如何实现的,有问题大家及时交流:

<!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:'&larr;请点击',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">&#xf0d7</i><i class="fa close_i">&#xf057</i></div><div class="showtitle"><i  class="fa">&#xf1ba</i>&nbsp;&nbsp;'+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
            },
        ]
    }];
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 第三章 幼稚傲娇的向阳先生 在橙子小姐的心里,咱们的向阳先生是个什么样的人呢?那还用问吗?当然是成熟稳重、温柔...
    南橘爱北枳阅读 343评论 0 21
  • 今天又不自觉的发脾气了,无法自控,又一次成为了情绪的奴隶。其实道理我都懂,就是在现实生活中,怎么就那么难实现呢?唉...
    bu离bu弃阅读 646评论 0 0
  • 许是生长在北方的缘故,对水总是有着难以割舍的渴求,去年九月和老公一起来到水乡苏州。从无锡下飞机,开车去苏州的路上随...
    文艺囡阅读 336评论 0 0
  • 记不清何时开始听你的歌 记不清何时开始喜欢你的歌 那时你是情歌的天后 而我喜欢上你却是在你离开以后 开始把你的歌当...
    利君理疗阅读 198评论 0 0
  • Nice to meet u!
    Skye0601阅读 170评论 0 0