需求分析
目前项目中预实现以下功能:
- 分级(省、市、区、海量点)显示点位数据,区县及以上显示聚合信息,包括聚合信息名(省、市、区)和点位数量
- 海量点层级下根据设备状态显示不同颜色图标。
- 聚合点可点击,省市聚合点点击显示下一级聚合情况,区级聚合点点击后显示区县范围。
功能实现
- 搭建地图,初始化省市区数据及点位数据(由后端接口获取,代码省略)。
<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;
}
}
}
- 自定义索引聚合及其样式,并且聚合点点击效果,参考高德示例按索引聚合
//初始化聚合对象
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);//视口自适应
}
})
},
- 初始化海量点及其样式
//初始化海量点对象
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);
},
- 实现分级显示聚合点或海量点
思路:判断当前层级,如果层级<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.样式效果有些不好看,初始版暂定这个,其他样式效果在此版本上更新。
发表评论