最近公司需要内网开发,使用到高德地图,正好碰到,在这里记录一下。本博客中实现了离线高德地图显示,点聚合,非聚合点自定义图标,图标点击弹出信息框,框选,圈选区域这些功能。
效果图:
实现思路:
1、下载地图瓦片数据,gitee有个开源地图瓦片下载项目,我fork了一下,地图下载器。
如果有fork失败的兄弟,可以找我私信要。
2、下载高德地图离线2.0JS API,高德地图离线地图api地址。
amap文件夹放在public下边,和瓦片数据同一级。
声明
- 本离线包基于高德地图js-api2.0,在此基础进行修改。
- 本项目仅为个人兴趣开发,不收费,作者也不提供任何付费服务。
- 本项目仅供个人学习研究使用。
- 本项目禁止商用,禁止在企业项目开发中使用此地图离线包,禁止使用此离线包以及基于此项目二次开发的软件从事盈利活动。
3、第一步和第二步已经能实现简单的高德地图渲染了,但是我们加载地图肯定是需要别的操作,比如点聚合,非聚合点自定义图标,图标点击弹出信息框,框选,圈选区域这些功能。这时候就需要我们我们自带的AMap3.js可能没有或者对应的插件包报错,我们就应该添加新的插件对应的js。
下载方法,本地项目中引入在线的高德地图,plugins中把我们需要的插件添加进去。
然后运行起来,在网页端network中下载对应的js,然后查找关键字jsload,把我们新添加插件对应的这一串添加到我们本地AMap3.js的最下边就OK了。
基本步骤就说清楚了,下边是一些显示,点聚合,非聚合点自定义图标,图标点击弹出信息框的代码。
//初始化
async initData() {
//定义地图
const base_url = "../../";
const layers = [new AMap.TileLayer({
getTileUrl: function (x, y, z) {
return `${base_url}MAP_zxy/${z}/${x}/${y}.png`;
},
opacity: 1,
zIndex: 99,
})]
this.map = new AMap.Map('container', { // 设置地图容器id
zoom: 10,
resizeEnable: true,
rotateEnable: true,
pitchEnable: true,
// center: [104.96824,33.375687],
center: [103.847998, 36.067468],
defaultCursor: 'pointer',
showLabel: true, //是否显示文字标注
layers: layers
})
//聚合打点
this.addCluster();
//定义鼠标框选工具
this.mouseTool = new AMap.MouseTool(this.map);
const that = this;
this.mouseTool.on('draw', function (event) {
that.markerForFigure = [];
that.mouseTool.close(false);
// 获取所有点
var allMarkers = that.map.getAllOverlays('marker');
var eObject = event.obj;//obj覆盖物对象。
allMarkers.forEach((marker => {
var markerInPolygon = eObject.contains(marker.getPosition());//是否包含marker
if (markerInPolygon) {
that.markerForFigure.push(marker)
}
}));
console.log(that.markerForFigure, "被选中的标记")
});
},
addCluster() {
let pointers = [];
if (this.rawData) {
this.rawData.map((value, index) => {
if (value.longitude !== undefined && value.latitude !== undefined) {
pointers.push({
weight: 1,
lnglat: [
this.toFixedDigit(value.longitude - 0, 5),
this.toFixedDigit(value.latitude - 0, 5),
],
deviceId: value.deviceId,
deviceCode: value.channelId,
deviceName: value.channelName,
orgCode: value.orgCode,
isOnline: value.psOnlineState,
manufacture: value.manufacture,
});
this.allPointers = pointers;
}
});
}
if (this.cluster && this.cluster != null) { //1. 如果存在 cluster 说明已经初始化过了,直接使用,变更它的点的内容就可以了。
this.cluster.setData(pointers);
} else {//2. 如果没有 cluster 就进行初始化。
this.infoWindow = new AMap.InfoWindow({ closeWhenClickMap: true, offset: new AMap.Pixel(0, -30) });
this.cluster = new AMap.MarkerCluster(
this.map, // 地图实例
pointers, // 海量点数据,数据中需包含经纬度信息字段 lnglat
{
gridSize: 60,// 设置网格像素大小
// renderClusterMarker: this.renderClusterMarker, // 自定义聚合点样式
renderMarker: this.renderMarker, // 自定义非聚合点样式
}
)
}
this.cluster.on('click', (item) => {
//此处是通过包含点的数量判断是否是聚合点,不是聚合点就执行上方单个点的点击方式
if (item.clusterData.length <= 1) {
return;
}
//这里是计算所有聚合点的中心点
let alllng = 0, alllat = 0;
for (const mo of item.clusterData) {
alllng += mo.lnglat.lng;
alllat += mo.lnglat.lat;
}
const lat = alllat / item.clusterData.length;
const lng = alllng / item.clusterData.length;
//这里是放大地图,此处写死了每次点击放大的级别,可以根据点的数量和当前大小适应放大,体验更佳
this.map.setZoomAndCenter(this.map.getZoom() + 4, [lng, lat]);
});
},
//格式化经纬度
toFixedDigit(num, n) {
//保留n位
if (typeof num != "number") {
return false;
}
num = num.toString();
var result = "";
var zeroResult = function (n) {
var zero = "";
for (var i = 0; i < n; i++) {
zero += "0";
}
return zero;
};
if (num % 1 == 0) {
//整数
result = num + "." + zeroResult(n);
} else {
//小数
var num1 = num.split(".");
if (num1[1].length < n) {
result = num1[0] + "." + num1[1] + zeroResult(n - num1[1].length);
} else {
result = num1[0] + "." + num1[1].substring(0, n);
}
}
return result;
},
//自定义非聚合点样式
renderMarker(context) {
const { marker, data } = context;
let iconOn = new AMap.Icon({
size: new AMap.Size(66, 80), // 图标尺寸
image: require(`../../assets/images/video-online.png`), // Icon的图像
imageSize: new AMap.Size(38, 50), // 根据所设置的大小拉伸或压缩图片
});
let iconOff = new AMap.Icon({
size: new AMap.Size(66, 80), // 图标尺寸
image: require(`../../assets/images/video-offline.png`), // Icon的图像
imageSize: new AMap.Size(38, 50), // 根据所设置的大小拉伸或压缩图片
});
if (data[0].isOnline == '1') {
marker.setIcon(iconOn)
} else if (data[0].isOnline == '0') {
marker.setIcon(iconOff)
}
marker.on("click", (e) => {
this.singleData = [];
console.log(this.$refs.infoWindow);
this.allPointers.forEach(item => {
if (item.deviceId == data[0].deviceId) {
this.singleData.push(item)
}
})
console.log(this.singleData);
this.$nextTick(()=>{
this.openInfoWindow(e)
})
});
},
openInfoWindow(e) {
this.infoWindow = new AMap.InfoWindow({
isCustom: true,
autoMove: true,
avoid: [20, 20, 20, 20],
content: this.$refs.infoWindow,
closeWhenClickMap: true,
offset: new AMap.Pixel(16, -40)
})
this.infoWindow.open(this.map, e.target.getPosition())
},
// 线段
drawPolyline() {
this.mouseTool.polyline({
strokeColor: "#3366FF",
strokeOpacity: 1,
strokeWeight: 6,
// 线样式还支持 'dashed'
strokeStyle: "solid",
// strokeStyle是dashed时有效
// strokeDasharray: [10, 5],
})
},
// 多边形
drawPolygon() {
this.mouseTool.close(true)
this.mouseTool.polygon({
strokeColor: "#FF33FF",
strokeOpacity: 1,
strokeWeight: 6,
// strokeOpacity: 0.2,
fillColor: '#1791fc',
fillOpacity: 0.4,
// 线样式还支持 'dashed'
strokeStyle: "solid",
// strokeStyle是dashed时有效
// strokeDasharray: [30,10],
})
},
// 矩形
drawRectangle() {
this.mouseTool.close(true)
this.mouseTool.rectangle({
strokeColor: 'red',
strokeOpacity: 0.5,
strokeWeight: 6,
fillColor: 'blue',
fillOpacity: 0.5,
// strokeStyle还支持 solid
strokeStyle: 'solid',
// strokeDasharray: [30,10],
})
},