美文网首页开发那点事微信小程序开发
开发那点事(十一)微信小程序地图聚合功能实现

开发那点事(十一)微信小程序地图聚合功能实现

作者: 极客简讯 | 来源:发表于2020-05-11 22:51 被阅读0次

    写在前面的话

    公司项目需求要在微信小程序上实现地图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

    相关文章

      网友评论

        本文标题:开发那点事(十一)微信小程序地图聚合功能实现

        本文链接:https://www.haomeiwen.com/subject/bqdmnhtx.html