uniapp之map组件+高德实现路径规划

2,144 阅读3分钟

前言

最近需要实现一个需求,通过起点终点的名称实现路径规划,还需要对特定的点进行标记。最后使用高德提供的API+uniapp的map组件进行实现。

1. 实现思路

使用uniapp的map组件实现路径规划,需要使用map中的属性polyline,而polyline需要知道途径点的坐标信息。我们就需要使用高德提供的API获取起始点的经纬度,去获取途径点经纬度,就可以实现路径规划功能。

在线体验:

image.png

2. 实现准备工作

  1. 首先你需要去申请一个属于自己的高德地图key,高德开放平台应用管理,成为开发者,创建应用,类型是web服务,就可以得到key
  2. 需要使用的API文档高德开放平台API文档
    1. 通过地理编码获取经纬度API
    2. 路径规划API
  3. 需要添加小程序域名白名单https://restapi.amap.com

3. 具体代码实现

3.1 map基本使用

新建一个uniapp的空白页 使用map组件渲染地图,注意地图组件需要设置宽高

<map id='map' :longitude="118.045616" :latitude="24.366646" :markers="markers"></map>
  	
const markers = [{
    latitude: 24.366646,
    longitude: 118.045616,
    width: 40,
    height: 40,
    callout: {
            content: '起点',
            display:'ALWAYS'
    },
    iconPath: '../../../../static/addrs.png'
}]

恭喜你,完成了地图的基本使用。

路径规划需要使用polyline,对应的使用文档如下:

image.png

3.2 获取路径规划经纬度

我们需要借助高德地图的路径规划查询获取到全部的路径规划,已经知道起点终点:

  1. 获取高德key

image.png 2. 使用API获取数据

根据地址获取经纬度

// 获取地理位置
const getLocation = (address: string): Promise<string> => {
  return new Promise((resolve) => {
    uni.request({
      url: `https://restapi.amap.com/v3/geocode/geo?address=${address}&key=${key}`,
      success: (res) => {
        if (res.data.geocodes.length) {
          resolve(res.data.geocodes[0].location)
        }
      }
    });
  })
}

获取起始点和终点的路径规划:


const getDriving = async () => {
  const origin = await getLocation('杭州三墩')
  const destination = await getLocation('萧山机场')
  uni.request({
    url: `https://restapi.amap.com/v3/direction/driving?origin=${origin}&destination=${destination}&key=${key}`,
    success: (res) => {
      const data = res.data.route
      if (data.paths?.[0]?.steps) {
        washData(data.paths[0].steps)
      }
    }
  });
}

获取到全部路径规划的数据,但是还是要洗一下数据,需要对应polyline格式数据。

let polyline = ref([])
const washData = (steps) => {
    let points = []
    steps.forEach(item => {
            const polen = item.polyline.split(';')
            polen.forEach(vv => {
                    let splits = vv.split(',')
                    points.push({
                            longitude: parseFloat(splits[0]),
                            latitude: parseFloat(splits[1])
                    })
            })
   })

    polyline.value = [{
            points: points,
            width: 3,
            arrowLine: true,
            arrowIconPath: true,
            color: '#204CF1',
    }]
}

使用

<map id='map' :longitude="118.045616" :latitude="24.366646" :markers="markers" :polyline="polyline"></map>

image.png

至此路线图就完成,但是有一点问题,路线没有缩小可以直接预览全部。

3.3 处理居中问题

可以使用include-points进行缩放视野以包含所有给定的坐标点

image.png

可以在清洗数据时添加边界点

const bounds = ref([])
const washData = (steps) => {
  let points = []
  let minLat = Infinity, maxLat = -Infinity
  let minLng = Infinity, maxLng = -Infinity

  steps.forEach(item => {
    const polen = item.polyline.split(';')

    polen.forEach(vv => {
      const [lngStr, latStr] = vv.split(',')
      const lng = parseFloat(lngStr)
      const lat = parseFloat(latStr)

      points.push({ longitude: lng, latitude: lat })

      // 更新边界范围
      minLat = Math.min(minLat, lat)
      maxLat = Math.max(maxLat, lat)
      minLng = Math.min(minLng, lng)
      maxLng = Math.max(maxLng, lng)
    })
  })

  // 设置地图中心点为路线中心(但不添加标记)
  longitude.value = (minLng + maxLng) / 2
  latitude.value = (minLat + maxLat) / 2

  // 添加边界缓冲
  const latBuffer = (maxLat - minLat) * 0.05
  const lngBuffer = (maxLng - minLng) * 0.05

  bounds.value = [
    { latitude: minLat - latBuffer, longitude: minLng - lngBuffer },
    { latitude: maxLat + latBuffer, longitude: maxLng + lngBuffer }
  ]

  polyline.value = [{
    points,
    width: 4,
    arrowLine: true,
    color: '#204CF1',
  }]
}

使用

<map id="map" :longitude="longitude" :latitude="latitude" :markers="markers" :polyline="polyline"
      :include-points="bounds"></map>

image.png

3.4 添加起点终点点击导航

使用markertap事件,可以进行弹框导航。

image.png

具体实现:

<map id="map" :longitude="longitude" :latitude="latitude" :markers="markers" :polyline="polyline" :include-points="bounds" @markertap="handleMarker"></map>
<div v-if="showMarker" class="bottom flex justify-end items-center">
  <wd-button size="small" class="text-12px" @click="openMap">
    导航
  </wd-button>
</div>

const handleMarker = (e) => {
  const id = e.detail.markerId
  const find = markers.find(item => item.id === id)
  currentLocation.value.latitude = find?.latitude
  currentLocation.value.longitude = find?.longitude
  showMarker.value = !showMarker.value
}

const openMap = () => {
  uni.openLocation({
    latitude: currentLocation.value.latitude,
    longitude: currentLocation.value.longitude,
    // scale: 28
  });
}

使用uni.openLocation进行导航即可。

image.png

总结

最后总结一下:整体流程就是获取高德的key->调用接口获取起始点和终点坐标->调用接口获取路径规划->清洗数据(获取边界以获取缩放视野)-> 渲染 -> 添加点导航,至此就完成了全部流程。希望能对你有所帮助,如有错误,请指正O^O!