Vue2实现高德地图自定义索引聚合+海量点展示

需求分析

目前项目中预实现以下功能:

  1. 分级(省、市、区、海量点)显示点位数据,区县及以上显示聚合信息,包括聚合信息名(省、市、区)和点位数量
  2. 海量点层级下根据设备状态显示不同颜色图标。
  3. 聚合点可点击,省市聚合点点击显示下一级聚合情况,区级聚合点点击后显示区县范围。

功能实现

  1. 搭建地图,初始化省市区数据及点位数据(由后端接口获取,代码省略)。
<template>
    <div id="amapcontainer" class="map-container"> 
    </div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
window._AMapSecurityConfig = {
 	securityJsCode: '「申请的安全密钥」',
}
export default {
    name: "amap",
    data: function() {
        return {
            points:[],
            areaData:[],
            clusterIndexSet:{
                province:{
                    minZoom: 2,
                    maxZoom: 5,
                },
                city: {
                    minZoom: 5,
                    maxZoom: 10,
                },
                district: {
                    minZoom: 10,
                    maxZoom: 12,
                },                                
            },
            polygon:null,
            pointStyles:[
            	{
                    url: require('../../assets/online.png') , 
                    anchor: [25, 50],
                    size: [50, 50],
                    zIndex: 1,
                },{
                    url: require('../../assets/offline.png') , 
                    anchor: [25, 50],
                    size: [50, 50],
                    zIndex: 1,
                },{
                    url:require('../../assets/abnormal.png') ,  
                    anchor:  [25, 50],
                    size: [50, 50],
                    zIndex: 1,
                },{
                    url:  require('../../assets/onlineStar.png') ,
                    anchor: [15, 15],
                    size: [30, 30],
                    zIndex: 1,
                }
            ],
        };
    },
    mounted(){
      this.initAMap();
    },      
    methods: {
    	initAMap(){
    		AMapLoader.load({
                key: "申请好的Web端开发者Key", // 申请好的Web端开发者Key,首次调用 load 时必填
                version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
                plugins: ["AMap.Scale", "AMap.ToolBar", "AMap.ControlBar", 'AMap.Geocoder', 'AMap.Marker','AMap.CitySearch', 'AMap.Geolocation', 'AMap.AutoComplete', 'AMap.InfoWindow','AMap.IndexCluster','AMap.DistrictSearch'], // 需要使用的的插件列表, 
            }).then((AMap) => {
                // 获取到作为地图容器的DOM元素,创建地图实例
                window.map = new AMap.Map("amapcontainer", { //设置地图容器id
                    resizeEnable: true, //是否监控地图容器尺寸变化
                    zoomEnable: true, // 地图是否可缩放,默认值为true
                    dragEnable: true, // 地图是否可通过鼠标拖拽平移,默认为true
                    doubleClickZoom: true, // 地图是否可通过双击鼠标放大地图,默认为true
                    zoom: 11, //初始化地图级别
                    center: [121.59996, 31.197646], // 初始化中心点坐标 上海
                    mapStyle: "amap://styles/dark", // 设置颜色底层
                })
                this.initDistrict();
                this.initPoints();
                this.executeConditionRender();
                //监听地图缩放或者地图平移事件,当缩放或平移时判断层级展示聚合点或海量点
                window.map.on('zoomend', () => { // 监听地图缩放结束后的等级
		            this.executeConditionRender();
		         });
		        window.map.on('moveend', () => { // 监听地图中心点的位置变化
		            this.executeConditionRender();
		        })
            }).catch(e => {
                console.log(e)
            })
    	},
    	//调用后端接口初始化省市区数据返回this.areaData;
    	/*
    	返回的数据格式如下
    	areaData:[
    	   '上海':{
		    	adcode:'310000',   //高德提供的adcode数据
		    	center:'121.473667,31.230525',
				...  //其他隐藏
			},
			...//其他省市区类似
		]
		*/
    	initDistrict(){
   			...  
    		return this.areaData
    	},
    	//调用后端接口初始化省市区数据返回this.points;
    	/*
    	返回的数据格式如下
    	points:[
    		{
		    	lnglat:"121.59996, 31.197646", //经纬度数据
		    	style:0,  //用于海量点样式数组中使用哪一个数据
				id:'1',  //数据ID
				...  //其他隐藏
			},
			...//其他点位类似
		]
		*/
    	initPoints(){
    		...  
    		return this.points;
    	}
	}
}
  1. 自定义索引聚合及其样式,并且聚合点点击效果,参考高德示例按索引聚合
//初始化聚合对象
initIndexCluster(){
    var Vuethis=this;
    window.indexCluster?(window.indexCluster.setMap(null),window.indexCluster =null):"";
    window.map.plugin(['AMap.IndexCluster'],function(){
        window.indexCluster = new AMap.IndexCluster(window.map, Vuethis.points,{
            renderClusterMarker: Vuethis._renderClusterMarker,
            clusterIndexSet: Vuethis.clusterIndexSet        
        });
    })
},
//聚合效果样式
getStyle(context) {
    var clusterData = context.clusterData; // 聚合中包含数据
    var index = context.index; // 聚合的条件
    var count = context.count; // 聚合中点的总数
    var marker = context.marker; // 聚合绘制点 Marker 对象
    var color = [
        '8,60,156',
        '66,130,198',
        '107,174,214',
        '78,200,211',
    ];
    var indexs = ['province','city','district'];
    var i = indexs.indexOf(index['mainKey']);
    var text = clusterData[0][index['mainKey']];
    var size =85
    if(i <= 2){
        text = '<span class="showName">'+ text+'('+context.count +')'+'</span>';
    } else {
        size = 12 * text.length + 20;
    }
    var style = {
        bgColor: 'rgba(' + color[i] + ',.8)',
        borderColor: 'rgba(' + color[i] + ',1)',
        text: text,
        size: size,
        index: i,
        color: '#ffffff',
        textAlign: 'center',
        boxShadow: '0px 0px 5px rgba(0,0,0,0.8)'
    }
    return style;
},
//聚合显示位置
getPosition(context) {
    var key = context.index.mainKey;
    var dataItem = context.clusterData && context.clusterData[0];
    var districtName = dataItem[key];
    if(!this.areaData[districtName]) {
        return null;
    }
    
    var center = this.areaData[districtName].center.split(',');
    var centerLnglat = new AMap.LngLat(center[0], center[1]);
     
    return centerLnglat;
},

// 自定义聚合点样式
_renderClusterMarker (context) {
    var Vuethis=this;
    var clusterData = context.clusterData; // 聚合中包含数据
    var index = context.index; // 聚合的条件
    var count = context.count; // 聚合中点的总数
    var marker = context.marker; // 聚合点标记对象
    var styleObj = this.getStyle(context);
    // 自定义点标记样式
    var div = document.createElement('div');
    div.className = 'amap-cluster';
    div.style.backgroundColor = styleObj.bgColor;
    div.style.width = styleObj.size + 'px';
    if(styleObj.index <= 2) {
        div.style.height = styleObj.size + 'px';
        //添加聚合点点击事件,省市聚合点点击显示下一级聚合情况,区级聚合点点击后显示区县范围。
        context.marker.on('click', function(e) {
            var curZoom = window.map.getZoom();
            switch(index.mainKey){
                case 'province':
                    curZoom=6;
                    break;
                case 'city':
                    curZoom=9;
                    break;
                default:
                    curZoom=11;
                    break;
            }
            window.map.setZoomAndCenter(curZoom, e.lnglat);
            if(index.mainKey=='district'){
                Vuethis.getDistrictBoundary(clusterData[0]['district'])
            }
        });
    }
    div.style.display='flex';
    div.style.justifyContent="center";
    div.style.alignItems="center";
    div.style.border = 'solid 1px ' + styleObj.borderColor;
    div.style.borderRadius = styleObj.size + 'px';
    div.innerHTML = styleObj.text;
    div.style.color = styleObj.color;
    div.style.textAlign = styleObj.textAlign;
    div.style.boxShadow = styleObj.boxShadow;
    context.marker.setContent(div)
    // 自定义聚合点标记显示位置
    var position = this.getPosition(context);
    if(position){
        context.marker.setPosition(position);
    }
    context.marker.setAnchor('center');
},
//通过区县名查询区县范围并展示
getDistrictBoundary(name){
    var Vuethis=this;
    var opts = {
        level :'country',   //关键字对应的行政区级别, country表示全国
        extensions: 'all',  //返回行政区边界坐标组等具体信息
        level: 'district'  //查询行政级别为 区
    };
    var district = new AMap.DistrictSearch(opts);//注意:需要使用插件同步下发功能才能这样直接使用
    district.search(name, function (status, result) {
        if (Vuethis.polygon) {
            window.map.remove(Vuethis.polygon)//清除上次结果
            Vuethis.polygon = null;
        }
        if (!result || !result.districtList || !result.districtList[0]) {
            Vuethis.$message({ message: '请确认区县名称是否正确', type: "error" });
            return
        }
        var bounds = result.districtList[0].boundaries;
        if (bounds) {
        //生成行政区划polygon
            for (var i = 0; i < bounds.length; i += 1) {//构造MultiPolygon的path
                bounds[i] = [bounds[i]]
            }
            Vuethis.polygon = new AMap.Polygon({
                strokeWeight: 1,
                path: bounds,
                fillOpacity: 0.4,
                fillColor: '#80d8ff',
                strokeColor: '#0091ea'
            });
            window.map.add(Vuethis.polygon)
            window.map.setFitView(Vuethis.polygon);//视口自适应
        }
    })
},
  1. 初始化海量点及其样式
//初始化海量点对象
initMassMarks(points,style,zooms){
     var mass= new AMap.MassMarks(points, {
         opacity:1,
         style:style,
         zooms:zooms
     })
     mass.on('click',function(e){
         Vuethis.showWindow(e.data);  //点击海量点展示数据窗口,代码省略。
     })
     mass.setMap(window.map);
},
  1. 实现分级显示聚合点或海量点
    思路:判断当前层级,如果层级<10(省市区层级),则初始化聚合对象病展示在地图上。若层级>10则初始化海量点,这里出现过卡顿,故而选择分片渲染方式。具体可见高德地图海量点MassMarks使用卡顿问题记录及解决办法
executeConditionRender() {
    let zoom=window.map.getZoom();
    this.currentZoom=zoom;
    if(zoom<10){    //省市区层级
        if(window.indexCluster==null){
            this.initIndexCluster()
        }
        if(zoom<8 && window.polygon){  //省市层级
            window.map.remove(window.polygon)//清除上次结果
            window.polygon = null;
        }
    }else{    //设备层级
        let screenCoordinateRange = window.map.getBounds()
        let northEast = [screenCoordinateRange.northEast.lng, screenCoordinateRange.northEast.lat]
        let southEast = [screenCoordinateRange.southWest.lng, screenCoordinateRange.northEast.lat]
        let southWest = [screenCoordinateRange.southWest.lng, screenCoordinateRange.southWest.lat]
        let northWest = [screenCoordinateRange.northEast.lng, screenCoordinateRange.southWest.lat]

        let screenList = this.points.filter(item => {  //选择在浏览器视框区域内点位数据
            return item.lnglat!=undefined?AMap.GeometryUtil.isPointInRing(item.lnglat, [northEast, southEast, southWest, northWest]):false
        })
        window.mass!=undefined&&window.mass!=null?window.mass.clear():""  //海量点存在则清除
        window.mass=this.initMassMarks(screenList,this.pointStyles,[10,20])
    }
},

实现效果

  1. 省级截图
    在这里插入图片描述

  2. 市级截图
    在这里插入图片描述

  3. 区级截图
    在这里插入图片描述
    区级点击效果
    在这里插入图片描述

  4. 海量点截图
    在这里插入图片描述

小结

1.记录开发过程中遇到的问题,多研究开发手册。
2.样式效果有些不好看,初始版暂定这个,其他样式效果在此版本上更新。

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue中使用高德地图聚合功能,首先需要安装并引入高德地图JavaScript API。 1. 在`index.html`文件中,添如下代码引入高德地图的API: ```html <script src="https://webapi.amap.com/maps?v=1.4.15&key=your_api_key"></script> ``` 其中,`your_api_key`是你在高德地图开放平台申请的API Key。 2. 在Vue组件中,首先在`mounted`生命周期钩子中初始化地图,并创建一个地图实例: ```javascript mounted() { // 初始化地图 AMap.initAMapApiLoader({ key: 'your_api_key', plugin: ['AMap.MarkerClusterer'] }); // 创建地图实例 this.map = new AMap.Map('mapContainer', { center: [lng, lat], // 地图中心经纬度 zoom: 13 // 地图缩放级别 }); } ``` 3. 在数据载完成后,将需要聚合数据添到地图上: ```javascript addMarkers() { this.points.forEach(point => { let marker = new AMap.Marker({ position: [point.lng, point.lat] // 标记位置经纬度 }); this.map.add(marker); }); } ``` 其中,`this.points`是包含标记经纬度的数组。 4. 最后,启用聚合功能,将添标记进行聚合: ```javascript clusterMarkers() { let cluster = new AMap.MarkerClusterer(this.map, this.map.getAllOverlays(), { gridSize: 80, // 聚合的像素大小 renderCluserMarker(cluster) { let count = cluster.getMarkers().length; let div = document.createElement('div'); div.className = 'cluster-marker'; div.innerHTML = count; return new AMap.Icon({ size: new AMap.Size(40, 40), image: 'cluster.png', imageSize: new AMap.Size(40, 40), // 自定义聚合的样式和内容 div: div }); } }); } ``` 通过`AMap.MarkerClusterer`类创建一个聚合器对象,将地图实例、添标记聚合选项传入。 以上就是在Vue中使用高德地图聚合功能的基本步骤。根据实际需求,可以进一步添交互、自定义样式等功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值