地图海量点位简单聚合

使用高德地图的时候,是不是大量数据的时候就会卡顿,高德也出了一个海量点位的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

  };

}












 












 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值