实现原理
map地图能拿到当前地图显示范围和缩放比例,根据当前显示范围排除掉范围之外的marker,再根据缩放比例控制每个marker在一定的范围内只出现1个markers,来控制当前显示区域内marker过多的问题
<map id="map" longitude="{{center.longitude}}" latitude="{{center.latitude}}" show-location="{{true}}" bindregiοnchange="onRegionChange" ></map>
工具函数
/**
* 防抖函数
* @param func
* @param delay
* @returns {(function(...[*]): void)|*}
*/
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
}
}
/**
* 获取地图区域当前显示范围
* @param ctx
* @returns {Promise<{
* southwest
* northeast
* }>}
*/
export function getMapRegion(ctx){
return new Promise((resolve, reject)=>{
ctx.getRegion({
success(data){
resolve(data)
},
fail(err){
reject(err)
}
})
})
}
/**
* 获取地图当前缩放大小
* @param ctx
* @returns {Promise<unknown>}
*/
export function getMapScale(ctx){
return new Promise((resolve, reject)=>{
ctx.getScale({
success(data){
resolve(data)
},
fail(err){
reject(err)
}
})
})
}
/**
* 获取地图中心的位置坐标
* @param ctx
* @returns {Promise<unknown>}
*/
export function getCenterLocation(ctx){
return new Promise((resolve, reject)=>{
ctx.getCenterLocation({
success(data){
resolve(data)
},
fail(err){
reject(err)
}
})
})
}
/**
* 计算两点之间的距离
* @param lat1
* @param long1
* @param lat2
* @param long2
* @returns {number}
*/
export function calculateLongitudeDistance(lat1, long1, lat2, long2) {
const radius = 6371; // 地球半径,单位为千米
const deltaLatByRad = (lat2 - lat1) * (Math.PI / 180);
const deltaLongByRad = (long2 - long1) * (Math.PI / 180);
const a = Math.sin(deltaLatByRad / 2) * Math.sin(deltaLatByRad / 2) +
Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) *
Math.sin(deltaLongByRad / 2) * Math.sin(deltaLongByRad / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = parseFloat((radius * c * 1000).toFixed(2));
// const distance = radius * c;
return distance;
}
/**
* 设置两点之间的间距
* @param scale 当前地图的缩放比例
* @returns {number}
*/
export function setSpaceBetween(scale) {
if (scale <= 8) {
return 6000
}
if (scale > 8 && scale <= 9) {
return 5000
}
if (scale > 9 && scale <= 10) {
return 2500
}
if (scale > 10 && scale <= 11) {
return 1250
}
if (scale > 11 && scale <= 12) {
return 500
}
if (scale > 12 && scale <= 13) {
return 250
}
if (scale > 13 && scale <= 14) {
return 125
}
if (scale > 14 && scale <= 15) {
return 50
}
if (scale > 15 && scale <= 16) {
return 25
}
if (scale > 16 && scale <= 17) {
return 12.5
}
if (scale > 17 && scale <= 18) {
return 0
}
}
/**
* 判断当前点是否在范围之内
* @param point
* @param region
* @returns {boolean}
*/
export function pointIsInRange(point,region){
const range = {
leftLongitudeLine: region.northeast.longitude,
rightLongitudeLine: region.southwest.longitude,
topLatitudeLine:region.northeast.latitude,
bottomLatitudeLine:region.southwest.latitude,
}
return point.latitude >= range.bottomLatitudeLine &&
point.latitude <= range.topLatitudeLine &&
point.longitude <= range.leftLongitudeLine &&
point.longitude >= range.rightLongitudeLine
}
/**
* 过滤所有marker标记点,返回符合两点间隔的marker数组
* @param data
* @returns {*[]}
*/
export function filterSpaceBetweenPoint(data,scale){
let result = []
if (!data.length) return result
// 默认加载第一个marker
result.push(data[0])
for (let i = 1; i <data.length; i++) {
const item = data[i]
// 查看当前的标记点,看限定范围内是否存在其它标记点,有的话舍弃掉,没有则加入
if(
!result.find(_item=>calculateLongitudeDistance(item.latitude,item.longitude,_item.latitude,_item.longitude) < setSpaceBetween(scale))
){
result.push(item)
}
}
return result
}
业务代码
onLoad(){
this.mapContext = wx.createMapContext("map");
},
onRegionChange(e){
if(e.type==='end'){
this.updateMarkers()
},
updateMarkers:debounce(async function(data){
if(!this.mapContext){
return
}
const mapInfo = {
region:{},
scale:0,
}
const regionRes = await getMapRegion(this._mapContext)
mapInfo.region = {
northeast: regionRes.northeast,
southwest: regionRes.southwest
}
const scaleRes = await getMapScale(this._mapContext)
mapInfo.scale = scaleRes.scale
console.log('mapInfo:',mapInfo)
const inRangeMarkers= data..filter(item=>pointIsInRange({
latitude:item.latitude,
longitude:item.longitude
},mapInfo.region))
const needUpdateMarkers = filterSpaceBetweenPoint(inRangeMarkers,mapInfo.scale)
this.mapContext.addMarkers({
markers:needUpdateMarkers
clear:true
})
},500)