背景
最近在开发 H5 页面,需求是在地图中显示行驶轨迹,在 H5 中调起地图app,轨迹经纬度列表由接口提供,坐标系为国际标准的坐标体系 WGS84,刚开始并未注意这个坐标系问题,在使用中发现位置加载出来会存在定位偏移,记录一下使用过程
需求
-
在地图中显示行驶轨迹,自定义标记点图标
地图厂商使用高德地图,使用目前最新的高德地图JSAPI 2.0 -
在自己的 H5 中调起多个地图app,显示标记点位置
由于地图 APP 并不支持在自己的网页中直接打开,因此需要通过地图 URI API 调用厂商H5地图,在厂商H5地图调起地图app
参考文章
地图厂商 URL API,调起H5地图:
高德地图
百度地图
腾讯地图
h5跳转到移动端地图网页打开地图app
实现过程
H5 UI 框架使用 Vant
详细高德地图引入方式参考高德地图文档
这里记录一下主要内容
在 html 文件中引入地图 js
<script src="https://webapi.amap.com/maps?v=2.0&key=申请的key值&plugin=AMap.Driving"></script>
主页面
// index.vue
<template>
<div class="index">
<template >
<v-map :data="dataList"></v-map>
<v-detail :statrLocation="statrLocation" :endLocation="endLocation"/>
</template>
</div>
</template>
<script>
import Map from './mMap.vue' // 地图
import Detail from './detail.vue'
export default {
name: 'index',
data() {
return {
dataList: [],
statrLocation: {
},
endLocation: {
},
}
},
components: {
"v-map": Map,
"v-detail": Detail
},
mounted() {
this.dataList = [
{
longitude: 116.478346,
latitude: 39.997361
},
{
longitude: 116.402796,
latitude: 39.936915
}
]
this.statrLocation = this.dataList[0]
this.endLocation = this.dataList[this.dataList.length-1]
},
methods: {
}
};
</script>
<style scoped lang="scss">
.index {
position: relative;
width: 100%;
height: 100%;
background: #fcf9f2;
}
</style>
地图组件
// mMap.vue
<template>
<div class="m-map">
<div id="map-box"></div>
</div>
</template>
<script>
export default {
props: ['data'],
data() {
return {
map: {
},
lineArr: [],
};
},
created() {
this.initMap()
},
methods: {
initMap() {
this.$nextTick(() => {
this.map = new AMap.Map('map-box', {
resizeEnable: true, //是否监控地图容器尺寸变化
zoom: 14, //初始化地图层级
center: [116.397428, 39.90923], //初始化地图中心点
animateEnable: true// 地图平移过程中是否使用动画
});
if(this.lineArr.length) {
this.drawLine() //绘制路线
}
});
},
drawLine(){
AMap.convertFrom(this.lineArr, 'gps', (status, result) => {
if (result.info === 'ok') {
const paths = result.locations;
this.map.clearMap()
this.startMarker = new AMap.Marker({
map: this.map,
position: paths[0], //起点经纬度
icon: new AMap.Icon({
image: require('@/assets/img/icon/icon-start.png'),
size: new AMap.Size(120, 120), //图标所处区域大小
imageSize: new AMap.Size(120,120) //图标大小
}), //起点ico
offset: new AMap.Pixel(-60, -60),
autoRotation: true,
// angle:-90,
});
this.endMarker = new AMap.Marker({
map: this.map,
position: paths[paths.length-1], //终点经纬度
icon: new AMap.Icon({
image: require('@/assets/img/icon/icon-end.png'),
size: new AMap.Size(60, 60), //图标所处区域大小
imageSize: new AMap.Size(60,60) //图标大小
}), //终点ico
offset: new AMap.Pixel(-30, -30),
autoRotation: true,
});
// 绘制轨迹
var polyline = new AMap.Polyline({
map: this.map,
path: paths,
showDir: true,
strokeColor: '#28F', //线颜色
// strokeOpacity: 1, //线透明度
strokeWeight: 6, //线宽
// strokeStyle: "solid" //线样式
});
this.map.add([this.startMarker, this.endMarker]);
this.map.setFitView(); //自适应缩放级别
}
})
}
},
watch: {
data: {
handler(newValue, oldValue) {
this.lineArr = [];
if(newValue.length) {
newValue.map((item, index) => {
if( item.longitude != null && item.latitude != null ) {
this.lineArr.push(new AMap.LngLat(item.longitude,item.latitude));
}
});
this.drawLine();
}
},
immediate: true
},
},
};
</script>
<style scoped lang ="scss">
@import '@/assets/scss/mixin.scss';
.m-map {
width: 100%;
height: 100vh;
#map-box {
width: 100%;
height: 100%;
}
}
</style>
代码解析
在使用中发现标记点位置显示不对,存在一定的偏移,怀疑是坐标系问题,看文档查了一下其他坐标转高德坐标方法,参考了这篇坐标变换文章,还可以实现批量转换。
在绘制轨迹之前先转换为高德坐标,然后再删除地图上所有的覆盖物,
AMap.convertFrom(this.lineArr, 'gps', (status, result) => {
if (result.info === 'ok') {
const paths = result.locations;
this.map.clearMap()
// ...
}
})
在查询时也找到了一个处理地理坐标系的js库gcoord,用来修正百度地图、高德地图及其它互联网地图坐标系不统一的问题。
应该也可以,不过我还没有尝试。
调起地图H5 组件
// detail.vue
<template>
<div class="m-detail-box">
<div class="m-btn-wrapper">
<van-button class="open-btn" round @click="openShow = true">导航至车辆当前位置</van-button>
</div>
<van-action-sheet
class="m-sheet-box"
v-model="openShow"
:actions="actions"
cancel-text="取消"
close-on-click-action
@select="onSelect"
/>
</div>
</template>
<script>
import {
Toast
} from 'vant';
export default {
props: {
statrLocation: {
type: Object,
default: () => ({
})
},
endLocation: {
type: Object,
default: () => ({
})
},
},
data() {
return {
openShow: false,
actions: [
{
name: '使用苹果地图导航', value: 'iosamap', color: '#007AFF' },
{
name: '使用百度地图导航', value: 'bmap', color: '#007AFF' },
{
name: '使用高德地图导航', value: 'amap', color: '#007AFF' }
],
}
},
filters: {
},
mounted() {
},
methods: {
onSelect(item) {
this.openShow = false;
let startLocation = this.startLocation
let endLocation = this.endLocation
if (endLocation.longitude && endLocation.latitude) {
let url = ''
switch (item.value) {
case 'iosamap':
url = `iosamap://navi?sourceApplication=applicationName&backScheme=applicationScheme&poiname=${
location}&poiid=BGVIS&lat=${
endLocation.latitude}&lon=${
endLocation.longitude}&dev=1&style=2`
break;
case 'bmap':
// 单点标注
url = `http://api.map.baidu.com/marker?location=${
endLocation.latitude},${
endLocation.longitude}&title=车辆位置&content=实时定位&output=html&coord_type=wgs84&src=webapp.baidu.openAPIdemo`
// 路径规划
// url = `http://api.map.baidu.com/direction?origin=latlng:${startLocation.latitude},${startLocation.longitude}|name:我的位置&destination=latlng:${endLocation.latitude},${endLocation.longitude}|name:实时定位&mode=driving&coord_type=wgs84&src=webapp.baidu.openAPIdemo`
break;
case 'amap':
// 单点标注
url = `https://uri.amap.com/marker?position=${
endLocation.longitude},${
endLocation.latitude}&name=实时定位&src=mypage&coordinate=wgs84&callnative=1`
// 路径规划
// url = `https://uri.amap.com/navigation?from=${startLocation.longitude},${startLocation.latitude},我的位置&to=${endLocation.longitude},${endLocation.latitude},实时定位&mode=car&policy=1&coordinate=wgs84&callnative=1`
break;
}
window.open(url)
} else {
Toast({
message: '暂无车辆定位',
type: 'fail',
})
}
},
},
beforeDestroy() {
clearInterval(this.timer)
}
}
</script>
<style scoped lang="scss">
@import "@/assets/scss/mixin.scss";
.m-detail-box {
position: absolute;
bottom: 0;
padding: 20px 0 0;
border-radius: 20px 20px 0px 0px;
width: 100%;
background: #FEFFFE;
box-shadow: 0 4px 40px 4px rgba(135, 119, 145, 0.36);
z-index: 160;
.van-cell-group {
&::after {
border: none;
}
}
.van-cell {
padding: 12px 24px;
font-size: 16px;
font-weight: 600;
&::after {
left: 24px;
right: 24px;
}
.van-cell__title {
flex: none;
color: #757AB5;
}
.van-cell__value {
color: #292929;
}
}
.m-btn-wrapper {
border-top: 1px solid #EFF2F9;
background: #FFF;
.open-btn {
display: block;
margin: 10px auto;
padding: 14px;
width: 90%;
font-size: 18px;
color: #FEFFFE;
background: #85D4D9;
}
}
/deep/.van-overlay {
background: rgba(33, 34, 51, 0.5);
}
.m-sheet-box {
padding: 0 8px;
background: transparent;
.van-action-sheet__content {
border-radius: 14px;
background: rgba(255, 255, 255, 0.92);
}
.van-action-sheet__gap {
height: 20px;
background: transparent;
}
.van-action-sheet__cancel {
margin-bottom: 20px;
border-radius: 14px;
font-size: 20px;
color: #007AFF;
background: rgba(255, 255, 255, 0.92);
}
}
}
</style>
打开地图 H5 时需要指定坐标系参数,不指定的话在地图H5 中的定位也会存在偏移
记录
之前写的时候没有发现定位偏移问题,重新整理记录一下