最近外卖项目,需要实现一些地图的功能,前几天写了一个关于marker 和 InfoWindow、自定义label的文章,只是简单地例子。详情点击vue中使用google地图(自定义label、信息窗口)
有不懂的欢迎留言,我每天都上博客,一定及时回复大家,如有不足希望批评指正。
那么,今天在这里写一个曾经我可望而不可即的功能,外卖骑手实时在地图上运动。具体需求是点击按钮创建弹窗,并且创建地图与websocket创建长连接。这个功能的原理是什么呢,我在这里把我的思路一一介绍,也算是记录心得。需求如下图:
- 1、先创建地图实例,并在地图初始化的时候就渲染初始的骑手标记(也就是marker)
- 2、建立websocket连接,获取数据
- 3、在服务端给我数据的时候,清除地图上所有的marker,然后再重新添加,这里是最重要的一步,实现实时刷新标记的重要步骤,一定要先清除再进行添加
- 4、地图标记线,也就是骑手历史路径也要在websocket发送消息的时候进行添加,
以上就是主要的步骤。在写项目的时候,遇到一个异步的坑,因为初始化地图和websocket连接的过程有一些时间差,说白了就是异步了,导致websocket给我发送的消息并不能及时渲染到地图上,我这边是在请求一个接口拿到后端给的数据后再进行地图初始化,一定要在地图初始化之后再进行连接,不同项目有不同需求,我这里只以我的项目思路来介绍。所以我这里有一个处理异步的步骤,使用的是ES6的async await,之后会有代码进行介绍
标记的API地址:https://developers.google.com/maps/documentation/javascript/markers
折线的API地址:https://developers.google.com/maps/documentation/javascript/shapes
我这里并没有使用原生的websocket的API。用的是这个websocket插件sockjs-client
下载
npm insall sockjs-client --save
引入
import SockJS from 'sockjs-client'
data里
websock:null,
sockjs:null,
methods里
//建立连接,listen为websocket的方法
this.sockjs = new SockJS(`这里为服务端websocket的请求地址`)
this.listen(this.sockjs)
// websocket方法
listen (sockjs) {
sockjs.onopen = () => {
console.log('启动websocket')
}
sockjs.onmessage = (e) => {
let response = JSON.parse(e.data)
/**
这里去做你想做的判断,可以打印response去看看数据什么样
*/
}
sockjs.onclose = () => {
console.log('关闭websocket')
}
},
上面是websocket使用方法,下面是我写功能的逻辑,有基础的肯定能看懂,代码中有详细介绍,应该是比较详细的。
data和html我这里就不展示了,代码太多 都给也比较乱
created(){
this.orderList()
},
updated(){
//当弹窗dialogVisible 关闭的时候,清空websocket数组,我自己的项目逻辑
if(this.dialogVisible == false){
this.flightPlanCoordinates = []
this.center = {}
this.qishouPsoition = []
this.qishouPathShow = false
}
},
watch:{
// 监听websocket给的坐标点
flightPlanCoordinates(val,oldVal){
return this.qishouPsoition = val
}
},
methods:{
//这里做了异步处理,先执行请求的接口,执行完之后在建立websocket连接
async handleClick(id){
await this.$api.qishou.get_position(data=>{ //我自己项目的接口,可忽略这里重要的是,初始化地图和websocket的先后顺序,初始化地图为先
this.mapData = data;
this.mapBuild() //请求成功调用地图
},{
orderId:id
})
//websocket
this.sockjs = await new SockJS(`你的websocket请求地址`)
await this.listen(this.sockjs)
},
// 地图实例
mapBuild(){
//地图创建成功显示地图
this.qishouPathShow = true
//设置地图中心坐标点为请求接口的经纬度
this.center = { lng:Number(this.mapData.shoplong),lat:Number(this.mapData.shoplat) }
//创建地图实例
let map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 17,
center:this.qishouPsoition.length==0?this.center:this.qishouPsoition[this.qishouPsoition.length-1],
mapTypeId: google.maps.MapTypeId.ROADMAP
});
//给地图实例赋值,存起来
this.mapObj = map
//骑手标记
this.marker = new MarkerWithLabel({
position: this.qishouPsoition.length==0?this.center:this.qishouPsoition[this.qishouPsoition.length-1],
icon: this.qishouIcon, //标记图标
draggable: false, //不可拖动
map: map,
//这里是自定义label,不懂得看上一篇google地图的文章,开头有链接
labelContent: this.mapData.name,
labelAnchor: new google.maps.Point(22, 0),
labelClass: "labels", // the CSS class for the label
labelStyle: { background:'#fff',padding:'5px' }
});
//目的地标记显示,是个汉堡(这个是接口定死的值)
let position_destination = { lng:Number(this.mapData.conlong),lat:Number(this.mapData.conlat) }
let destination = new MarkerWithLabel({
position: position_destination,
icon: this.destinationIcon, //目的地标记图标
draggable: false, //不可拖动
map: map,
labelContent: 'Destination',
labelAnchor: new google.maps.Point(33, 0),
labelClass: "labels", // the CSS class for the label
labelStyle: { background:'#fff',padding:'5px' }
});
},
// websocket
listen (sockjs) {
sockjs.onopen = () => {
console.log('启动websocket')
}
sockjs.onmessage = (e) => {
let response = JSON.parse(e.data)
//判断给的状态
switch (response.event){
case "RESPONSE_POSITION":
this.lat = response.data.latitude
this.lng = response.data.longitude
let position = {lat:this.lat,lng:this.lng}
//向数组中添加从websocket中请求的数据
this.flightPlanCoordinates.push(position)
//websocket每次给值,那么就清空一次地图上原有的marker,清空后在创建一次marker,position为websocket最新的点
this.marker.setMap(null);
this.marker = new MarkerWithLabel({
position: position,
icon: this.qishouIcon, //骑手标记图标
draggable: false, //不可拖动
map: this.mapObj,
labelContent: this.mapData.name,
labelAnchor: new google.maps.Point(22, 0),
labelClass: "labels", // the CSS class for the label
labelStyle: { background:'#fff',padding:'5px' }
});
//创建路线,path是一个数组
let flightPath = new google.maps.Polyline({
path:this.qishouPsoition,
geodesic: true,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
flightPath.setMap(this.mapObj);
break
}
}
sockjs.onclose = () => {
console.log('关闭websocket')
}
},