使用高德地图的时候,是不是大量数据的时候就会卡顿,高德也出了一个海量点位的js了,不过太复杂了,要隐藏的点位也不给,事件也不好添加处理,所以我用简单逻辑实现了一个,返回展示的少量点位,这样可以自己添加地图框架的事件,这个js可以用到百度地图、高德地图、mapbox-gl、天地图等等的地图框架中,不依赖地图框架,监听地图框架的zoomend事件后获取我这边的数据然后塞进地图就行了。
1、使用高德地图、百度地图、天地图、mapbox-gl等地图框架
2、实例化我这个,可以配置一些参数,也可以不配置
* {
* xMin:100.3434,
* xMax:110.435243,
* yMin:19.434324,
* yMax:23.42324324,
* pointHeight:10,
* pointWidth:10
* }
* <br/>
* let dataDeal = bigDataDeal();
dataDeal.setData([数据]) // {lng:108.34324,lat:22.43432423}
3、监听地图框架的zoomend moveend事件
dataDeal.getData(zoom) , dataDeal.getData(zoom,bounds) // 传入zoom就能获取数据了 数据是数组 item.children 是同一区域隐藏的点位
// bounds 是地图边界,这样可以返回更少的展示点位
/**
*
* {
* xMin:100.3434,
* xMax:110.435243,
* yMin:19.434324,
* yMax:23.42324324,
* pointHeight:10,
* pointWidth:10
* }
* <br/>
* let dataDeal = bigDataDeal();
* dataDeal.setData([
* {
* lng:108.324324,
* lat:22.3432423
* ...
* }
* ])
*
* dataDeal.getData(8) // zoom 整数 其中children:[] 是同一区域隐藏的点位
* @param {} params
*/
function bigDataDeal(params) {
const pointHeight = params?.pointHeight || 10
const pointWidth = params?.pointWidth || 10
const xMin = params?.xMin || 0
const xMax = params?.xMax || 180
const yMin = params?.yMin || -85
const yMax = params?.yMax || 85
let dataList = []
let dataListShow = []
let bboxs = {}
function setData(data){
dataList = data
}
let bounds = {}
function getData(zoom,boundsParam){
bounds = boundsParam
dataListShow = []
bboxs = {}
setArea(zoom)
return dataListShow
}
let lengthRelateLng;
let lengthRelateLat;
let indexPoints = []
function setArea(zoom){
// 比例尺 1里面
const lengthRoot = levelZoom[Math.ceil(zoom)]|| 1000 * 100
// 换算成px 的比例尺 lng
lengthRelateLng = lengthRoot * prasePxToCm(pointWidth)
// 换算成px 的比例尺 lat
lengthRelateLat = lengthRoot * prasePxToCm(pointHeight)
const xCount = getDistance({
lng:bounds?.xMax || xMax,
lat:0
},{
lng:bounds?.xMin || xMin,
lat:0
})/lengthRelateLng + 1
const yCount = getDistance({
lng:108.44444,
lat:bounds?.yMax || yMax
},{
lng:108.44444,
lat:bounds?.yMin || yMin
})/lengthRelateLat + 1
const xItem = ((bounds?.xMax || xMax) - (bounds?.xMin || xMin))/xCount
const yItem = ((bounds?.yMax || yMax) - (bounds?.yMin || yMin))/yCount
dataList.forEach(point=>{
point.children = []
const lng = point.lng
const lat = point.lat
const xCount = Math.floor((lng - xMin)/xItem)
const yCount = Math.floor((lat - yMin)/yItem)
indexPoints.push({
xCount:xCount,
yCount:yCount
})
if(
lng > (bounds?.xMin || xMin)
&& lng < (bounds?.xMax || xMax)
&& lat > (bounds?.yMin || yMin)
&& lat < (bounds?.yMax || yMax)
){
if(!bboxs[xCount+"-"+yCount]){
bboxs[xCount+"-"+yCount] = point
dataListShow.push(point)
}else{
bboxs[xCount+"-"+yCount].children.push(point)
}
}
})
}
/**
* 计算距离 - 米
*
* {
* "lng":108.43324,
* "lat":22.435234
* }
*/
function getDistance(point1,point2) {
let lat1 = point1.lat, lon1 = point1.lng, lat2=point2.lat, lon2 = point2.lat
const R = 6371e3; // 地球半径,单位米
const phi1 = lat1 * Math.PI / 180; // 纬度1,弧度制
const phi2 = lat2 * Math.PI / 180; // 纬度2,弧度制
const phiDelta = (lat2 - lat1) * Math.PI / 180; // 两点纬度差,弧度制
const lambdaDelta = (lon2 - lon1) * Math.PI / 180; // 两点经度差,弧度制
const a = Math.sin(phiDelta / 2) * Math.sin(phiDelta / 2) +
Math.cos(phi1) * Math.cos(phi2) *
Math.sin(lambdaDelta / 2) * Math.sin(lambdaDelta / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c;
return distance;
}
/**
* 层级 对应的长度 1 厘米的比例尺
*
*/
const levelZoom = {
6: 1000 * 100,
7: 1000 * 50,
8: 1000 * 25,
9: 1000 * 20,
10: 1000 * 10,
11: 1000 * 5,
12: 1000 * 2,
13: 1000 * 1,
14: 500,
15: 200,
16: 100,
17: 50,
18: 20,
19: 10,
}
/**
* px 转 厘米
* @param {*} px
* @returns
*/
function prasePxToCm(px) {
var targetEleWidth = 1, cm;
var createEle = document.createElement('input');
var body = document.getElementsByTagName("body");
createEle.setAttribute("style", "width:1cm !important;height:1cm !important;border-width:0px !important;padding:0px !important;margin:0px !important;");
createEle.id = "elementId_" + new Date().getTime();
createEle.type = "hidden";
body[0].appendChild(createEle);
var targetEle = document.getElementById(createEle.id);
targetEleWidth = window.getComputedStyle(targetEle).width.match(/^\d+\.?\d*/)[0];
cm = px / targetEleWidth;
return cm;
}
return {
getData:getData,
setData:setData
};
}