写在前面的话
公司项目需求要在微信小程序上实现地图marker点聚合的功能,百度苦寻无果,故自己实现。
最终效果
功能演示核心思路
- marker标签中的callout属性用来显示聚合点的数量
- 点击聚合点时,以聚合点为中心放大地图,不需要再次请求后台接口
- 根据map组件scale缩放级别将地图分成一个一个的小格子,计算小格子中marker点的数量
- 由于小程序无法像网页端那样处理庞大的数据量,为了提高用户体验,地图状态为缩放或者范围缩小时缓存上次marker数据,无需请求后台接口
关键js文件
- MapUtil.js (判断是否为缩放状态,根据后台接口数据格式化成地图聚合类型marker数据等)
- ZjMarker.js(maker点基类,根据简单的参数构建单个marker及聚合marker)
具体实现
MapUtil.js
import {
zjMarker
} from '../../utils/mapUtil/ZjMarker';
import {
transformFromWGSToGCJ
} from '../WSCoordinate';
export class MapUtil {
constructor(northeast, southwest, scale) {
this.northeast = northeast;
this.southwest = southwest;
this.scale = scale;
console.log('初始化mapUtil成功');
console.log(this.northeast, 'northeast');
}
//设置初始化范围
setInitData(northeast, southwest, scale) {
this.northeast = northeast;
this.southwest = southwest;
this.scale = scale;
console.log('刷新mapUtil成功');
}
//判断是否为缩放,
checkRefresh(northeast, southwest) {
console.log('检测是否可以刷新接口');
console.log(this.northeast, 'northeast');
console.log(northeast, 'currentNortheast');
let result = true;
if (this.northeast.latitude > northeast.latitude) {
console.log('东北纬度缩小');
}
if (this.southwest.latitude < southwest.latitude) {
console.log('西南纬度增高');
}
if (this.northeast.longitude > northeast.longitude) {
console.log('东北经度增大');
}
if (this.southwest.longitude < southwest.longitude) {
console.log('西南经度缩小');
}
if (this.northeast.latitude > northeast.latitude && this.southwest.latitude < southwest.latitude &&
this.northeast.longitude > northeast.longitude && this.southwest.longitude < southwest.longitude) {
console.log('地图缩放,不请求接口');
result = false
}
return result;
}
//根据东北 西南经纬度 以及后台返回标记点 格式化成小程序marker点
getFortMatMarkerList(northeast, southwest, scale, backendMarkerList) {
//屏幕中显示的经度的长度和纬度的长度
let mapWidth = southwest.longitude - northeast.longitude;
let mapHeight = northeast.latitude - southwest.latitude;
//将屏幕中地图分割的横向 格子数和 纵向格子数
let widthSize = scale;
let heightSize = widthSize + parseInt(scale / 2);
//计算每个格子的经纬度的长度
let unitWidth = mapWidth / widthSize;
let unitHeight = mapHeight / heightSize;
let pointData = {};
backendMarkerList.forEach(latLng => {
//如果点在显示范围内
if (latLng.latitude < northeast.latitude && latLng.latitude > southwest.latitude &&
latLng.longitude < northeast.longitude && latLng.longitude > southwest.longitude) {
let relativeX = latLng.longitude - northeast.longitude;
let relativeY = latLng.latitude - southwest.latitude;
//计算出这个点,处于哪个格子
let x = parseInt(Math.floor(relativeX / unitWidth));
let y = parseInt(Math.floor(relativeY / unitHeight));
if (x < 0 || y < 0) {
console.log('点位不在格子内', '失败');
}
//生成单元格点位数据
let pointKey = x + ',' + y;
if (pointData[pointKey] == undefined) {
pointData[pointKey] = [];
}
pointData[pointKey].push(latLng);
}
});
let resultMapArray = [];
for (let y = 0; y < heightSize; y++) {
for (let x = 0; x < widthSize; x++) {
let pointKey = x + ',' + y;
//筛选没有充电站点位的格子
if (pointData[pointKey] != undefined) {
let markerItem = {};
//聚合点与单点共存 , 长度等于一 不聚合点
if (pointData[pointKey].length == 1) {
let iconPath = pointData[pointKey][0].ScanAndCharge == 1 ? '/img/scanMarkerIcon.png' : '/img/markerIcon.png';
markerItem = new zjMarker(pointData[pointKey][0].longitude, pointData[pointKey][0].latitude, pointData[pointKey][0].StationID, {
iconPath: iconPath
})
//长度大于一 聚合点
} else if (pointData[pointKey].length > 1) {
let iconPath = pointData[pointKey][0].ScanAndCharge == 1 ? '/img/cluScanMarkerIcon.png' : '/img/cluMarkerIcon.png';
markerItem = new zjMarker(pointData[pointKey][0].longitude, pointData[pointKey][0].latitude, pointData[pointKey][0].StationID, {
type: 'cluster',
iconPath: iconPath,
num: pointData[pointKey].length
})
}
resultMapArray.push(markerItem);
}
}
}
console.log(resultMapArray, 'resultMapArray');
return resultMapArray;
}
//获取中心纬度
getCenterLocation(northeast, southwest) {
let mapWidth = southwest.longitude - northeast.longitude;
let mapHeight = northeast.latitude - southwest.latitude;
let longitude = northeast.longitude + mapWidth;
let latitude = southwest.latitude + mapHeight;
return {
latitude: latitude,
longitude: longitude
}
}
}
ZjMarker.js
//地图marker标记点基类 (单点`聚合)
export class zjMarker {
constructor(longitude, latitude, id, options = {}) {
this.longitude = longitude;
this.latitude = latitude;
this.id = id;
this.width = options.width ? options.width : 30;
this.height = options.height != undefined ? options.height : 36;
let type = options.type == undefined ? 'single' : options.type;
this.iconPath = options.iconPath == undefined ? '/img/markerIcon.png' : options.iconPath;
if (type != 'single') {
this.callout = {
content: options.num, //文本
color: '#000', //文本颜色
borderRadius: 3, //边框圆角
borderWidth: 0, //边框宽度
bgColor: 'transparent', //背景色
padding: 0, //文本边缘留白,
display: 'ALWAYS',
textAlign: 'center', //文本对齐方式。有效值: left, right, center,
anchorY: 62 //可能需要根据各个手机做出相应的适配
}
}
}
}
最后,在map组件中实现bindregionchange方法获取东北以及西南经纬度,根据经纬度范围判断是否需要请求后台接口重新获取点位信息
if (mapUtil.checkRefresh(res.northeast, res.southwest)) {
console.log('开始刷新接口');
let location = mapUtil.getCenterLocation(res.northeast, res.southwest);
that.loadMapData(location.latitude, location.longitude, markerList => {
markerList.forEach(item => {
item.longitude = item.StationLng;
item.latitude = item.StationLat;
});
oriMarkerList = markerList;
that.setData({
markerList: mapUtil.getFortMatMarkerList(res.northeast, res.southwest, scale, markerList)
});
});
mapUtil.setInitData(res.northeast, res.southwest, scale);
} else {
that.setData({
markerList: mapUtil.getFortMatMarkerList(res.northeast, res.southwest, scale, oriMarkerList)
});
}
详情请咨询我 vx:a21544182123
网友评论