使用環境
- vue
- bmap.js
- element-ui
頁面展示
前提步驟
- 在index中引入百度地圖提供的js庫
- 在使用的vue頁面中例項化地圖
<!-- 給id隨便起給名字 -->
<div id="map"></div>
<el-button :loading="btnLoading" @click="save">儲存</el-button>
程式碼實現
- 需要的基礎資料和初次載入方法
data(){
return {
map: null,
point: null,
center: {
lng: '',
lat: '',
address: '',
},
btnLoading: false, // 按鈕loading
polygonArr: [], // 行政區域顯示的多邊形資料,比對點在不在區域內使用
}
}
async mounted() {
await this.getCenterInfo(); // 傳送請求獲取儲存的座標資訊,獲取到資料給center賦值,自行實現。
this.initMap();
},
- 初始化地圖程式碼
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)
},
- 實現區域框選效果
/**
* 新增行政區域邊界
* @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多條資料,沿海區域的省份資料很多。獲取到資料,設定頁面居中展示的時候,大部分情況下選擇居中到單條資料最大的展示不會出錯。
- 返回的行政區域邊界不一定正確,比如:臺灣省,百度地圖上,搜尋其他省份會給出行政區域,但是臺灣不會
- 打標註方法
// 設定標註的方法
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])
}
},
- 儲存方法部分程式碼
// 獲取地圖上打標註的經緯度
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
}
});
需要自行實現的方法
findLargest
有的省市區域的行政範圍比較複雜,返回的資料很多,設定居中顯示最大的區域範圍
getRegionInfo
自行封裝的地址元件不一定通用
參考
https://lbsyun.baidu.com/index.php?title=jspopularGL
https://mapopen-pub-jsapi.bj.bcebos.com/jsapi/reference/jsapi_webgl_1_0.html