一、查看某個地區全部業務員的座標
二、點擊業務員座標可展現具體信息、當前具體地址
三、點擊某個業務員名字,自動關聯到地圖上的位置
四、查看業務員當天的行程軌跡
五、動態切換地圖上座標的自定義圖標
六、支持展現全部業務員在可視區內(自適應縮放地圖比例,展現全部業務員位置)javascript
之因此沒有選擇用vue-baidu-map,是由於有bug。。。php
若是你以前沒有接觸過地圖方面的開發,建議先去官網熟悉一下api。
百度地圖API(javascript API)
具體的參考類
大概會用到如下幾個api:css
先看一下最終的效果圖html
顯示軌跡的模塊vue
項目是vue項目 我貼一下map.vue的文件代碼
html代碼👇
只須要一個顯示地圖的divjava
<template> <div class="main"> <div id="container" class="bm-view"> </div> <div class="btn__group"> <button @click="changeType('all')" :class="{'active': item === 'all'}">所有</button> <button @click="changeType('path')" :class="{'active': item === 'path'}" v-show="currentItem==='car'">軌跡</button> </div> </div> </template>
js部分👇git
<script> import mapStyle from '@/assets/mapStyleJson.json' import { drawTrack } from '@/libs/util.js' export default { name: 'map-module', props: { currentItem: { type: String, default: '' } }, data() { return { stewardCoordList: [], zoom: 10, // 地圖樣式 mapStyle: { styleJson: mapStyle }, currentCity: '', myMap: null, item: '', mapShow: true, infoWindow: null, trackList: [] } }, watch: { list: { handler(newVal, oldVal) { if (!newVal.length) { this.myMap.clearOverlays() return } this.stewardCoordList = newVal // this.currentItem === 'car' && (this.item = 'all') let translateList = [] this.stewardCoordList.forEach(e => { // 數組中加icon的url e.url = this.currentItem === 'car' ? (!e.currentOrder.length ? ( '/static/img/normal.png') : ( '/static/img/warning.png')) : (e.currentOrder.length ? ('/static/img/servicer-busy.svg') : ( '/static/img/servicer-free.svg')) // 須要轉換的座標數組 translateList.push(new BMap.Point(e.geo.lng, e.geo.lat)) }) let convertor = new BMap.Convertor(); let myGeo = new BMap.Geocoder(); let that = this; // 百度地圖經緯度解析成具體地址 let geocodeSearch = (pt, item) => { myGeo.getLocation(pt, function (rs) { if (rs !== null) item.address = rs.address }); } let pageSize = 10, pageCount = translateList.length % 10 === 0 ? Math.floor(translateList.length / 10) : Math .floor(( translateList.length / 10) + 1); for (let i = 0; i < pageCount; i++) { let startIndex = pageSize * i; let sliceArr = translateList.slice(startIndex, pageSize * (i + 1)); convertor.translate(sliceArr, 1, 5, function (data) { if (data.status === 0) { for (let i = 0; i < data.points.length; i++) { const el = data.points[i]; that.stewardCoordList[startIndex + i].geo.lng = el.lng that.stewardCoordList[startIndex + i].geo.lat = el.lat geocodeSearch(sliceArr[i], that.stewardCoordList[startIndex + i]) } } // 添加圖標marker setTimeout(() => { that.addMarker(that.stewardCoordList) }, 100); }) } }, deep: true }, currentItem(val) { this.item = val === 'car' ? 'all' : '' } }, computed: { list() { return this.$store.getters.getter_stewardCoordList }, geo() { return this.stewardCoordList.map(e => { return new BMap.Point(e.geo.lng, e.geo.lat) }) }, }, mounted() { this.initMap() // 接收其餘組件傳過來的業務員座標 (是一個數組) 這裏實現的功能是:獲取業務員的軌跡、自動移動地圖當前可視區,定位到小哥的當前位置 //兄弟組件的事件分發 this.$emit('getCurpos', { arr}) 注意:這裏傳過來的數組座標是轉成百度地圖座標以後的 this.$bus.$on('getCurPos', async val => { if (!this.item || this.item === 'all') { //查看業務員座標 // 這裏從新渲染車和人的圖標要寫成異步的 await this.addMarker(this.stewardCoordList) setTimeout(() => { this.myMap.centerAndZoom(new BMap.Point(val.arr[0], val.arr[1]), 18); }, 300); } else { //查看軌跡 await this.getDataLoc(val.account) let translateList = [] if (this.trackList && this.trackList.length) { this.trackList.forEach(e => translateList.push(new BMap.Point(e.lng, e.lat))) } let convertor = new BMap.Convertor(); let myGeo = new BMap.Geocoder(); let that = this; let pageSize = 10, pageCount = translateList.length % 10 === 0 ? Math.floor(translateList.length / 10) : Math .floor(( translateList.length / 10) + 1); //這裏是由於百度地圖天天的計算量是有限的,因此就分批處理了 for (let i = 0; i < pageCount; i++) { let startIndex = pageSize * i; let sliceArr = translateList.slice(startIndex, pageSize * (i + 1)); convertor.translate(sliceArr, 1, 5, function (data) { if (data.status === 0) { for (let i = 0; i < data.points.length; i++) { const el = data.points[i]; that.trackList[startIndex + i].lng = el.lng that.trackList[startIndex + i].lat = el.lat } } setTimeout(() => { drawTrack(that.myMap, that.trackList, val.name) }, 100); }) } } }) this.$nextTick(this.setMapHeight()) }, methods: { initMap() { // 初始化地圖 this.myMap = new BMap.Map('container', { enableMapClick: false }); let lng, lat; if (this.list.length) { lng = this.list[0].geo.lng, lat = this.list[0].geo.lat; //設置地圖中心點以及zoom值 this.myMap.centerAndZoom(new BMap.Point(lng, lat), 12); } else{ //設置地圖默認中心點 this.myMap.centerAndZoom(new BMap.Point(116.406605, 39.921585), 10); } //是否容許鼠標滾輪縮放 // this.myMap.enableScrollWheelZoom(false); this.myMap.addControl(new BMap.NavigationControl({ offset: new BMap.Size(10, 45) })) // this.myMap.addControl(new BMap.OverviewMapControl()) //個性化地圖樣式 this.myMap.setMapStyle({ styleJson: mapStyle }); }, // 獲取每一個業務員軌跡座標 數據由後端接口提供 getDataLoc(account) { return api.***(account).then(res => { const data = res.data; if (data.resultCode === '0000') { this.trackList = data.resultData.map(v => { return { lng: '' + v.longitude, lat: '' + v.latitude } }) } }) }, addMarker(arr) { new Promise(_ => { let that = this //加標註以前,先清空以前的標註。避免數據更新以後,以前的標註還在 that.myMap.clearOverlays(); if (arr != undefined && arr.length > 0 && that.myMap !== null) { let len = arr.length, content, marker, markers = [] for (let i = 0; i < len; i++) { //自定義mark圖標 let myIcon = new BMap.Icon(arr[i].url, new BMap.Size(30, 26), { // 指定定位位置 offset: new BMap.Size(10, 25), // anchor: new BMap.Size(10, 30) // 當須要從一幅較大的圖片中截取某部分做爲標註圖標時,須要指定大圖的偏移位置 // imageOffset: new BMap.Size(0, 0 - i * 25) // 設置圖片偏移 }); let point = new BMap.Point(arr[i].geo.lng, arr[i].geo.lat); // 建立標註對象並添加到地圖 marker = new BMap.Marker(point, { icon: myIcon }); // 給圖標添加事件 marker.addEventListener('click', function (e) { let item = arr[i], html = '' // 如下是構造信息窗口裏的內容 具體的內容按照大家的需求來 const infoHtml = (!item.currentOrder.length) ? e => ` <p>${item.name} <span style="margin-left:5px;">${item.userMobile}</span><span style="color:#00bebebe;margin-left:5px;">${'空閒'}</span></p><br> ` : e => ` <p>${item.name} <span style="margin-left:5px;">${item.userMobile}</span><span style="color:#f00;margin-left:5px;">${'***'}</span></p><br> ` const orderHtml = (item.currentOrder.length) ? ( that.currentItem === 'car' ? addrs => ` <div> <p style="font-weight:bold;">***信息:</p> ${item.currentOrder.map(info => ` <div> <p><span style="margin-right:6px;">${info.startDate}</span><sapn>${info.endData === null ? '' : info.endData}</sapn></p> <p>信息1:${info.soType}</p> <p>信息2:${info.so}</p> <p>信息3:${info.cusName}</p> <p>信息4:${info.vin}</p> </div> `)} </div><br> ` : addrs => ` <div> <p style="font-weight:bold;">***信息:</p> ${item.currentOrder.map(info => ` <div> <p>信息1:${info.type}</p> <p>信息2:${info.so}</p> <p>信息3:${info.cusName}</p> </div> `)} </div><br> ` ) : addrs => `<p></p>` //------------------------結束----------------- html = `<div class="info__box"> ${infoHtml()} ${orderHtml()} <p style="font-weight:bold;">當前位置:<span style="font-weight:normal;">${item.address}</span></p> </div>` // 打開信息窗口 openInfo(html, point) }, false); markers.push(marker) that.myMap.addOverlay(marker); that.myMap.setViewport(that.geo) }; } else if (!arr.length) { that.myMap.clearOverlays(); // that.myMap.centerAndZoom(that.formItem.cityName, 10) } //開啓信息窗口 function openInfo(content, point) { var opts = { boxStyle: { width: "280px", minHeight: "195px", opacity: "0.8", }, enableAutoPan: true, // title: '信息', closeIconUrl: close, closeIconMargin: '0px', closeIconZIndex: 1, closeIconWidth: '15px' } // let point = new BMap.Point(e.target.point.lng, e.target.point.lat); let infoWindow = new BMap.InfoWindow(content, opts); // 建立信息窗口對象 that.myMap.openInfoWindow(infoWindow, point); //開啓信息窗口 return false } }) }, async changeType(e) { this.item = e; this.myMap.clearOverlays(); if (this.geo.length === 1) { let list = this.stewardCoordList; this.myMap.centerAndZoom(new BMap.Point(list[0].geo.lng, list[0].geo.lat), 18); } else { if (e === 'all') { await this.addMarker(this.stewardCoordList) this.myMap.setViewport(this.geo) } } }, // 設置地圖高度 setMapHeight() { let boxHeight = document.querySelector('.content-wrapper').offsetHeight; // document.querySelector('.bm-view').style.height = boxHeight * 2 + 'px' }, } } </script>
繪製軌跡的方法👇json
export const drawTrack = (map, arr, name) => { // 先清空以前的marker map.clearOverlays(); let driving = new BMap.DrivingRoute(map); //建立軌跡實例 // 生成座標點 let trackPoint = arr.map(v => new BMap.Point('' + v.lng, '' + v.lat)) for (let i = 0, len = trackPoint.length; i < len; i++) { if (i != trackPoint.length - 1) { driving.search(trackPoint[i], trackPoint[i + 1]); } } // icon的參數 let size = new BMap.Size(28, 32), offset = new BMap.Size(0, -13), imageSize = new BMap.Size(28, 32), icon = new BMap.Icon("/static/car.png", size, { imageSize: imageSize }); driving.setSearchCompleteCallback(() => { let pts = driving.getResults().getPlan(0).getRoute(0) .getPath(); //經過軌跡實例,得到一系列點的數組 let polyline = new BMap.Polyline(pts, { strokeColor: '#00bebebe', strokeOpacity: 1, }); map.addOverlay(polyline); let labStyle = { minWidth: '28px', height: '28px', lineHeight: '28px', textAlign: 'center', color: '#FFF', fontSize: '12px', backgroundColor: 'none', border: '1px solid #00bebebe', borderRadius: '4px', } // 畫圖標、想要展現的起點終點途經點 for (let i = 0, len = trackPoint.length; i < len; i++) { let marker = new BMap.Marker(trackPoint[i], { icon: icon, offset: offset }); let lab, nameLab; if (i == 0) { lab = new BMap.Label("起點", { position: trackPoint[i] }); lab.setStyle(labStyle) } else if (i == trackPoint.length - 1) { lab = new BMap.Label("終點", { position: trackPoint[i] }); lab.setStyle(labStyle) //添加一個名字label nameLab = new BMap.Label(name, { offset:new BMap.Size(0,-30), position: trackPoint[i] }) nameLab.setStyle(labStyle) } map.addOverlay(lab); map.addOverlay(nameLab); } map.setViewport(trackPoint); }); }
mapStyleJson.json
的內容我也貼出來後端
[{ "featureType": "water", "elementType": "all", "stylers": { "color": "#00253d" } }, { "featureType": "highway", "elementType": "geometry.fill", "stylers": { "color": "#000000" } }, { "featureType": "highway", "elementType": "geometry.stroke", "stylers": { "color": "#296f82ff" } }, { "featureType": "arterial", "elementType": "geometry.fill", "stylers": { "color": "#000000" } }, { "featureType": "arterial", "elementType": "geometry.stroke", "stylers": { "color": "#296f82" } }, { "featureType": "local", "elementType": "geometry", "stylers": { "color": "#000000" } }, { "featureType": "land", "elementType": "all", "stylers": { "color": "#011D32" } }, { "featureType": "railway", "elementType": "geometry.fill", "stylers": { "color": "#000000" } }, { "featureType": "railway", "elementType": "geometry.stroke", "stylers": { "color": "#296f82ff" } }, { "featureType": "subway", "elementType": "geometry", "stylers": { "lightness": -70 } }, { "featureType": "building", "elementType": "geometry.fill", "stylers": { "color": "#000000" } }, { "featureType": "all", "elementType": "labels.text.fill", "stylers": { "color": "#857f7fff" } }, { "featureType": "all", "elementType": "labels.text.stroke", "stylers": { "color": "#000000" } }, { "featureType": "building", "elementType": "geometry", "stylers": { "color": "#022338" } }, { "featureType": "green", "elementType": "geometry", "stylers": { "color": "#062032" } }, { "featureType": "boundary", "elementType": "all", "stylers": { "color": "#1e1c1c" } }, { "featureType": "manmade", "elementType": "geometry", "stylers": { "color": "#022338" } }, { "featureType": "poi", "elementType": "all", "stylers": { "visibility": "on" } }, { "featureType": "all", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "all", "elementType": "labels.text.fill", "stylers": { "color": "#2da0c6ff", "visibility": "on" } }, { "featureType": "highway", "elementType": "geometry", "stylers": { "visibility": "off" } }, { "featureType": "local", "elementType": "geometry", "stylers": { "color": "#00ff00ff", "visibility": "off" } }, { "featureType": "railway", "elementType": "geometry", "stylers": { "color": "#00ff00ff", "visibility": "off" } }, { "featureType": "subway", "elementType": "geometry", "stylers": { "color": "#00ff00ff", "visibility": "off" } }, { "featureType": "arterial", "elementType": "geometry", "stylers": { "color": "#073146", "visibility": "on" } } ]
css樣式代碼我就不貼出來了,大家隨意發揮~api
注意的問題點以下👇
GCJ02:又稱火星座標系,是由中國國家測繪局制訂的地理信息系統的座標系統。由WGS84座標系經加密後的座標系。
BD09:爲百度座標系,在GCJ02座標系基礎上再次加密。其中bd09ll表示百度經緯度座標,bd09mc表示百度墨卡托米制座標。
非中國地區地圖,服務座標統一使用WGS84座標。
百度對外接口的座標系爲BD09座標系,並非GPS採集的真實經緯度,在使用百度地圖JavaScript API服務前,需先將非百度座標經過座標轉換接口轉換成百度座標。
代碼有點亂, 我本身都有點難理清楚,若是有小夥伴遇到問題了能夠聯繫我QQ:602353272若是我分享的這個文章對你有幫助的話,不要吝嗇你的贊,給我點個贊吧。謝謝~~