百度地圖BMap實現在行政區域內做標註

菜小牛發表於2022-01-11

使用環境

  1. vue
  2. bmap.js
  3. element-ui

頁面展示

前提步驟

  1. 在index中引入百度地圖提供的js庫

  1. 在使用的vue頁面中例項化地圖
<!-- 給id隨便起給名字 -->
<div id="map"></div> 
<el-button :loading="btnLoading" @click="save">儲存</el-button>

程式碼實現

  1. 需要的基礎資料和初次載入方法
data(){
  return {
    map: null,
    point: null,
    center: {
      lng: '',
      lat: '',
      address: '',
    },
    btnLoading: false, // 按鈕loading
    polygonArr: [], // 行政區域顯示的多邊形資料,比對點在不在區域內使用
  }
}
async mounted() {
  await this.getCenterInfo(); // 傳送請求獲取儲存的座標資訊,獲取到資料給center賦值,自行實現。
  this.initMap();
},
  1. 初始化地圖程式碼
initMap() {
  this.map = new BMap.Map("map", {
    minZoom: 6,
    enableMapClick: false
  });

  this.map.enableScrollWheelZoom(true);
  // 初次渲染頁面的獲取之前儲存的地址資訊,如果有的話,就新增區域,打標記
  if (this.center.address) {
    this.addDistrict(this.center.address)
  }

  this.map.addEventListener("click", (e) => {
    this.setMarker(e.point)
  })

  // 也可以放在addDistrict 函式中,但是這樣每次都會呼叫
  setTimeout(() => {
    if (this.center.lat) {
      this.setMarker(this.center)
    }
  }, 1000)
},
  1. 實現區域框選效果
/**
  * 新增行政區域邊界
  * @param districtName 行政區域查詢名稱,類似:安徽省合肥市包河區
*/
addDistrict(districtName) {
  let boundary = new BMap.Boundary();
  boundary.get(districtName, (rs) => {  //獲取行政區域
    this.polygonArr = []
    let regionLevel = this.getRegionInfo('id').length
    // 不是所有的行政區域都有返回值
    if (regionLevel === 1 && rs.boundaries.length === 0) {
      // 沒有區域範圍的,清空地圖所有標記,且定位到所選位置
      this.map.clearOverlays();
      this.locateCenter()
    } else if (regionLevel > 1 && rs.boundaries.length === 0) {  
      // 如果已經選到 第二級 地址,沒有返回rs區域,直接定位到所選位置,不清空之前的圖層
      this.locateCenter()
    } else if (rs) {
      this.map.clearOverlays();
      // 查詢最大的區域範圍,設定為中心展示區域
      let idx = rs.boundaries.findIndex(item => item === this.findLargest(rs.boundaries))
      for (let i = 0; i < rs.boundaries.length; i++) {
        let ply = new BMap.Polygon(rs.boundaries[i], {
          strokeStyle: 'dashed',
          strokeWeight: 2,   //邊框寬度
          strokeColor: "#CB7C93",   //邊框顏色
          fillOpacity: 0.1,
          fillColor: " #3A2B5D" //填充顏色
        }); //建立多邊形覆蓋物
        this.polygonArr.push(ply)
        this.map.addOverlay(ply);  //新增覆蓋物
        if (i === idx) {
          this.map.setViewport(ply.getPath());    //調整視野
        }
      }
    }
  });
},
/**
  * 當選中的省市區沒有行政區域範圍的時候,設定頁面居中顯示
  */
locateCenter() {
  let searchRegion = new BMap.LocalSearch(this.map, {
    onSearchComplete: (result) => {
      this.map.centerAndZoom(result.getPoi(0).point, 12);
      this.setMarker(result.getPoi(0).point)
    }
  })
  searchRegion.search(this.getRegionInfo('name'))
},

注意事項:

  • 一級區域可能沒有行政區域邊界,比如:澳門
  • 一級、二級區域都有行政區域邊界,但是三級區域可能沒有行政區域邊界返回值,比如:廣東省東莞市常平鎮
  • 行政區域邊界返回值不一定是一條,可能幾十條或者幾百條,比如安徽省只有5條資料,浙江省有800多條資料,沿海區域的省份資料很多。獲取到資料,設定頁面居中展示的時候,大部分情況下選擇居中到單條資料最大的展示不會出錯。
  • 返回的行政區域邊界不一定正確,比如:臺灣省,百度地圖上,搜尋其他省份會給出行政區域,但是臺灣不會
  1. 打標註方法
// 設定標註的方法
setMarker(position) {
  this.removeMarker()
  let pt = new BMap.Point(Number(position.lng), Number(position.lat));
  let positionIcon = new BMap.Icon("./static/position.png", new BMap.Size(35, 35));
  let marker = new BMap.Marker(position, {
    icon: positionIcon,
    offset: new BMap.Size(-2, -15),
  });
  // 判斷標註點位在不在我們設定的區域範圍內,如果沒有行政區域則不判斷
  if (this.polygonArr.length > 0) {
    let isPointInPolygonValid = this.polygonArr.some(item => BMapLib.GeoUtils.isPointInPolygon(pt, item))
    if (isPointInPolygonValid) {
      this.map.addOverlay(marker);
    } else {
    this.$message.error("請在區域範圍內設定座標點")
    }
  } else {
    this.map.addOverlay(marker);
  }
},
removeMarker() {
  // 地圖上所有的標註都會被獲取
  let markers = this.map.getOverlays()
  // 保證最後一個是我們自己打的標註且只有一個標註點位
  if (markers.length > 0 && markers[markers.length - 1].DQ === 'Marker') {
    this.map.removeOverlay(markers[markers.length - 1])
  }
},
  1. 儲存方法部分程式碼
// 獲取地圖上打標註的經緯度
let gc = new BMap.Geocoder();
let point = new BMap.Point(markers[markers.length - 1].point.lng, markers[markers.length - 1].point.lat)

gc.getLocation(point, (res) => {
  if (res) {
    let params = {
    longitude: point.lng.toString(),
    latitude: point.lat.toString(),
    address: this.center.address
  }
});

需要自行實現的方法

  1. findLargest

有的省市區域的行政範圍比較複雜,返回的資料很多,設定居中顯示最大的區域範圍

  1. getRegionInfo

自行封裝的地址元件不一定通用

參考

https://lbsyun.baidu.com/index.php?title=jspopularGL

https://mapopen-pub-jsapi.bj.bcebos.com/jsapi/reference/jsapi_webgl_1_0.html

https://github.com/huiyan-fe/BMapGLLib

相關文章