使用高德地图添加点标记及聚合标记(滑动弹出气泡)

随着大数据发展,可视化在前端的应用越来越广泛。近期利用高德地图做了一个关于数据可视化展示的项目,由于数据量大,使用点标记加载慢、重叠多且不美观,随后采用聚合标记对问题进行解决。

一、点标记

使用AMap.Marker构造点标记对象,最后添加到地图上。


点标记.png
            /**绘制点标记
            *@params points {Array}  待渲染的点标记数据
           */
            handleMarker(points) {
              for(let i = 0; i < points.length; i++) {
                // 如果点标记的经纬度信息没有,则不进行渲染
                if (!points[i].lng) {
                    continue
                }
                let marker = new AMap.Marker({
                    name: points[i].name,   // 点标记名称
                    position: new AMap.LngLat(points[i].lng, points[i].lat),   // 点标记经纬度
                     // 点标记样式 
                    content: `<div style="background-color: #5366c3; height: 30px; width: 30px; border: 2px solid #ffffff; border-radius: 15px; box-shadow: 0px 0px 12px rgba(0,0,0,0.3);"></div>`,
                     // 位置偏置量,由于默认以左上角为基点,因此x和y方向都偏置一个半径的距离,将基点移至图形中心
                    offset: new AMap.Pixel(-15, -15),  
                })
                // 添加点标注滑入事件
                marker.on('mouseover', (e) => {
                   console.log(e.target.w.name)
                    .......
                })
                // 添加点标注滑出事件
                marker.on('mouseout', (e) => {
                    .......
                })
                // 将所有点标记存入数组中,后续改造成聚合标记时需要用到
                this.markers.push(marker)
            }
          }
二、聚合标记

当需要绘制的点数量级非常大时,上述的普通点标记渲染的方式就不适用了,在高德地图可通过AMap.MarkerClusterer这个插件对海量点标记进行聚合显示。


聚合标记.png
        /**绘制点标记
        */
         handleCluster() {
             // 聚合标注滑入事件
            let hanldeBubble = (e) => {
               // 滑入聚合标记需要执行的事件
                 ......
            }
            // 聚合标注滑出事件
            let cancleBubble = (e) => {
               // 滑出聚合标记需要执行的事件
                ......
            }
            AMap.plugin('AMap.MarkerClusterer', () => {
                let count = this.markers.length;
                // 设置聚合标记样式
                let _renderClusterMarker = (context) => {
                    //移除上一次添加的滑入滑出事件,由于每次移动、放大缩小地图都会重新计算渲染聚合标注,因此必须移除之前的事件,否则事件会不断叠加导致重复
                    context.marker.off('mouseover', hanldeBubble)
                    context.marker.off('mouseout', cancleBubble)
                    //添加本次产生的新聚合标记的滑入滑出事件
                    context.marker.on('mouseover', hanldeBubble)
                    context.marker.on('mouseout', cancleBubble)
                    let extData = []
                    context.markers.forEach((item) => {
                        extData.push({
                            name: item.w.name
                        })
                    })
                    // 将标记名称等存入marker的拓展信息字段extData中
                    context.marker.extData = extData
                    let factor = Math.pow(context.count / count, 1 / 18);
                    let div = document.createElement('div');
                    let Hue = 180 - factor * 180;
                    let bgColor = this.bgColor
                    let fontColor = '#ffffff';
                    let borderColor = '#ffffff';
                    let shadowColor = 'rgba(0,0,0,0.3)';
                    div.style.backgroundColor = bgColor;
                    //标记的大小可以固定写,也可以根据聚合点的数量来决定大小
                    let size = 30
                    // let size = Math.round(30 + Math.pow(context.count / count, 1 / 5) * 20);
                    div.style.width = div.style.height = size + 'px';
                    div.style.border = 'solid 2px ' + borderColor;
                    div.style.borderRadius = size / 2 + 'px';
                    div.style.boxShadow = '0 0 12px ' + shadowColor;
                    div.innerHTML = context.count;
                    div.style.lineHeight = (size - 2) + 'px';
                    div.style.color = fontColor;
                    div.style.fontSize = '14px';
                    div.style.textAlign = 'center';
                    context.marker.setOffset(new AMap.Pixel(-size / 2, -size / 2));
                    context.marker.setContent(div)
               }
               this.cluster = new AMap.MarkerClusterer(
                    this.map,   //指定地图对象
                    this.markers,  //指定需要聚合的点标记对象
                    {
                        // averageCenter: false,   // 聚合点的图标位置是否是所有聚合内点的中心点
                        gridSize: 100,   //聚合计算时网格的像素大小,默认60
                        renderClusterMarker: _renderClusterMarker,   //聚合点的自定义绘制
                        zoomOnClick: false,  //点击聚合点时,是否散开
                    })
            }
三、滑动标记弹出气泡

设计气泡的思路是:以固定定位写好气泡样式,当鼠标滑入点标记时,获取滑入标记的经纬度并转换为屏幕x和y方向上的像素位置,赋给气泡的left和top值,滑出标记时隐藏气泡即可。


聚合标记气泡.png

1、气泡样式
html 代码

<div class="bubble-box" v-show="showBubble" :style="{left: bubleLeft + 'px', bottom: bubleTop + 'px'}">
       <div class="bubble-wrap">
            <div class="bubble-content" v-for="(item, index) in bubleList" :key="index">
                        <span></span>
                <span>{{item.content}}</span>
            </div>
      </div>
</div>

css 代码

    .bubble-box {
        position: absolute;
        margin-left: -6.375rem;
        margin-bottom: 1.5625rem;
        z-index: 990;
        .bubble-wrap {
            box-shadow: 0 0 .75rem  rgba(0, 62, 255, 0.1);
            position: relative;
            width: 12.8125rem;
            padding: .875rem;
            font-size: 1rem;
            color: $fontColor;
            border-radius: .875rem;
            background: #fff;
            .bubble-content {
                p {
                    line-height: 1.3;
                    & span:nth-child(1) {
                        margin-right: .375rem;
                        width: .5rem;
                        height: .5rem;
                        border-radius: .25rem;
                        display: inline-block;
                                                background: $fontColor;
                    }
                    & span:nth-child(2) {
                        margin-right: .625rem;
                    }
                }
            }
            &::after {
                content: '';
                display: inline-block;
                width: .625rem;
                height: .625rem;
                background: #fff;
                position: absolute;
                bottom: -0.3125rem;
                left: 50%;
                margin-left: -0.3125rem;
                transform: rotate(45deg);
                border-radius: .125rem;
            }
        }
    }

2、滑入事件--显示气泡
高德地图的聚合标记是基于点标记实现的,每一次进行地图平移、缩放操作时,AMap.MarkerClusterer插件都会调用renderClusterMarker里的方法对点标记根据gridSize设置的像素范围进行计算和渲染,点标记若在聚合范围内,则渲染成一个聚合点,不在范围内的点标记则不做处理(维持原样式和属性)。
因此需要对点标记和聚合标记分别添加滑入、滑出事件。

/* 点标记滑入事件*/
marker.on('mouseover', (e) => {
    this.bubleList = []
    //将点标记的name字段存入数组中,点标记的自定义数据都存放在e.target.w对象下
    this.bubleList.push({
        content: e.target.w.name
    })
    //获取点标记的经纬度
    let lon = e.target.w.position.R
    let lat = e.target.w.position.Q
    //通过高德API中的lngLatToContainer将经纬度转换为屏幕对应x和y方向的坐标
    let lnglat = new AMap.LngLat(lon, lat)
    let pixel = this.map.lngLatToContainer(lnglat)
    //将转换的坐标赋给气泡的left和top值,显示气泡
    this.bubleLeft = pixel.x
    this.bubleTop = document.body.clientHeight - pixel.y
    this.showBubble = true
})


/*聚合标记滑入事件*/
let hanldeBubble = (e) => {
    this.bubleList = []
    //将点标记的name字段存入数组中,聚合标记的自定义数据都存放在e.target.extData对象下
    e.target.extData.forEach((item) => {
        this.bubleList.push({
            content: item.name
        })
    })
    //获取聚合后标记的经纬度
    let lon = e.target.De.position.R
    let lat = e.target.De.position.Q
    //通过高德API中的lngLatToContainer将经纬度转换为屏幕对应x和y方向的坐标
    let lnglat = new AMap.LngLat(lon, lat)
    let pixel = this.map.lngLatToContainer(lnglat)
    this.bubleLeft = pixel.x
    this.bubleTop = document.body.clientHeight - pixel.y
    this.showBubble = true
}

3、滑出事件--隐藏气泡
点标记和聚合标记滑出隐藏气泡的方法是一样的,不过由于二者绑定事件的方法不同,还是需要分开写。

/*隐藏气泡*/
hideBubble() {
    this.showBubble = false
    this.bubleList = []
}

/* 点标记滑出事件*/
marker.on('mouseout', (e) => {
    this.hideBubble()
})

/*聚合标记滑出事件*/
let cancleBubble = (e) => {
    this.hideBubble()
}

**4、聚合标记绑定滑入、滑出事件

高德地图的点标记本身支持滑入、滑出事件,直接使用marker.on(eventType, function())即可绑定相应的事件。而对于聚合标记,官方文档给出的支持事件只有click点击事件,因此聚合标记的其它事件绑定都需要特殊处理。

上面提到过,聚合标记是基于点标记的,每一次对地图进行缩放等操作时,都会重新调用renderClusterMarker方法计算和渲染聚合标记,而实际上这个聚合的标记是一个重新计算了经纬度和赋予特殊样式的点标记,因此可以在renderClusterMarker方法中为聚合标记绑定事件。

            AMap.plugin('AMap.MarkerClusterer', () => {
                // 设置聚合标记样式
                let _renderClusterMarker = (context) => {
                    //移除上一次添加的滑入滑出事件,由于每次移动、放大缩小地图都会重新计算渲染聚合标注,因此必须移除之前的事件,否则事件会不断叠加导致重复
                    context.marker.off('mouseover', hanldeBubble)
                    context.marker.off('mouseout', cancleBubble)
                    //添加本次产生的新聚合标记的滑入滑出事件
                    context.marker.on('mouseover', hanldeBubble)
                    context.marker.on('mouseout', cancleBubble)
                    let extData = []
                    context.markers.forEach((item) => {
                        extData.push({
                            name: item.w.name
                        })
                    })
                    // 将标记名称等存入marker的拓展信息字段extData中
                    context.marker.extData = extData
                    ......
              })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容