Loading

百度地图BMap实现在行政区域内做标注

使用环境

  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 districtNames {Array} 行政区域查询名称,类似:["安徽省","合肥市","包河区"]
  */
async addDistrict(districtNames) {
  this.polygonArr = []
  let boundary = new BMap.Boundary();
  boundary.get(districtNames.join(""), rs => {
    if (rs.boundaries.length !== 0) {
      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 && districtNames.length === this.regionInfo.regionDesc.length) {
          this.map.setViewport(ply.getPath());    //调整视野
        }
      }
    } else if (districtNames.length > 1) {
       this.addDistrict(districtNames.slice(0, districtNames.length - 1))
    } else {
       this.removeMarker()
       this.locateCenter(this.regionInfo.regionDesc.join(''))
    }
		// 如果行政区域和选择的行政区域对应不上,则定位到选择的位置上
    if (districtNames.length !== this.regionInfo.regionDesc.length) {
      this.locateCenter(this.regionInfo.regionDesc.join(''))
    }
  })
},
/**
  * 当选中的省市区没有行政区域范围的时候,设置页面居中显示
  */
locateCenter() {
	let searchRegion = new BMap.LocalSearch(this.map, {
		onSearchComplete: (result) => {
			this.map.centerAndZoom(result.getPoi(0).point, 12);
		}
	})
	searchRegion.search(this.getRegionInfo('name'))
},

注意事项:

  • 一级区域可能没有行政区域边界,比如:澳门
  • 一级、二级区域都有行政区域边界,但是三级区域可能没有行政区域边界返回值,比如:广东省东莞市常平镇
  • 行政区域边界返回值不一定是一条,可能几十条或者几百条,比如安徽省只有5条数据,浙江省有800多条数据,沿海区域的省份数据很多。获取到数据,设置页面居中展示的时候,大部分情况下选择居中到单条数据最大的展示不会出错。
  • 返回的行政区域边界不一定正确,比如:台湾省,百度地图上,搜索其他省份会给出行政区域,但是台湾不会
  • 给addDistrict 传参传数组的原因为了反显,在当前数据没有行政区域的时候,执行查上一级的行政区域范围,boundary构造函数接收的是字符串,所以还得转成字符串
  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

posted @ 2022-01-11 12:16  菜小牛  阅读(1294)  评论(0编辑  收藏  举报