背景

最近在开发 H5 页面,需求是在地图中显示行驶轨迹,在 H5 中调起地图app,轨迹经纬度列表由接口提供,坐标系为国际标准的坐标体系 WGS84,刚开始并未注意这个坐标系问题,在使用中发现位置加载出来会存在定位偏移,记录一下使用过程

需求

  1. 在地图中显示行驶轨迹,自定义标记点图标
    地图厂商使用高德地图,使用目前最新的高德地图JSAPI 2.0

  2. 在自己的 H5 中调起多个地图app,显示标记点位置
    由于地图 APP 并不支持在自己的网页中直接打开,因此需要通过地图 URI API 调用厂商H5地图,在厂商H5地图调起地图app

参考文章

高德地图 JSAPI 2.0

地图厂商 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 中的定位也会存在偏移
截图
在这里插入图片描述

记录

之前写的时候没有发现定位偏移问题,重新整理记录一下

Logo

前往低代码交流专区

更多推荐