開發那點事(十一)微信小程序地圖聚合功能實現

寫在前面的話

公司項目需求要在微信小程序上實現地圖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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章