需求
当接口返回一连串地图坐标,需要根据这些坐标串联起来,形成一个线路图(本次使用步行导航线路图)。
思路
- 首先优先想到使用小程序Map组件的
polyline
属性去进行展示。但是我们发现直接使用该属性进行坐标绘制画出来的数据都是直线。所以想要根据地图上的线路图进行绘制必须使用第三方提供的绘制线路图的api。这里使用腾讯地图api - 将第三方api进行简单封装,然后根据后端返回的坐标组,两两相连调用api。
如上这样一组数据我们就应该传入demo[1], demo[2]拿到线路,然后再传入demo[2], demo[3]再次拿到下一段路线,知道拿到最后一个线路为止,最后进行拼接展示。const demo = [ { longitude: 1, latitude: 1 }, { longitude: 2, latitude: 2 }, { longitude: 3, latitude: 3 }, { longitude: 4, latitude: 4 }, ]
具体实现
1. 首先让我们对第三方的api进行简单封装
从官网给的参数列表来看,我们至少需要key,form,to三个参数,而且form跟to的传参方式比较特殊,而我们一般使用对象传递,所以需要我们进行参数转换
export const apiGetPolylineList = (data) => {
const [from, to] = data
return new Promise((resolve, reject) => {
uni.request({
url: `https://apis.map.qq.com/ws/direction/v1/walking/?from=${form.longitude},${form.latitude}&to=${to.longitude},${to.latitude}&key=${txMapKey}`,
complete: (res) => {
if (res.data.status === 0) {
resolve(res.data.result.routes[0])
}else {
uni.showToast({
title: '线路加载失败',
icon: 'error'
})
reject('线路加载失败')
}
}
})
})
}
2.接下来根据后端返回的坐标组,两两相连调用api。
// 创建测试数据
const testData = [
{
latitude: 30.868603,
longitude: 103.934669
},
{
latitude: 30.852555,
longitude: 103.934843
},
{
latitude: 30.851977,
longitude: 103.92361
},
{
latitude: 30.843044,
longitude: 103.962646
}
]
既然需要两两调用,我们在一开始就将他们分好。
const getTwoSpotList = (testData) => {
const list = []
testData.reduce((pre, next) => {
list.push([pre, next])
return next
})
return list
}
既然我们要进行接口的多次调用,那不如我们直接使用Promise.all
对结果进行统一处理
const getLineData = async () => {
const twoSpotList= getTwoSpotList(testData)
const apiList = twoSpotList.map(item => apiGetPolylineList(item))
const lineData = await Promise.all(apiList)
const polylineListRes = getLineData(lineData)
}
我们拿到的数据关于线路图的就是polyline
字段,格式为:[坐标1纬度 , 坐标1经度 , 坐标2纬度 , 坐标2经度 , 坐标3纬度 , 坐标3经度…],第一个坐标为原始未被压缩过的,之后的使用前向差分进行压缩,我们需要进行解压合并操作。
const getLineData = async (lineData) => {
//推荐使用lodash这样的成熟库里面的深拷贝方法,这里为了简单直接使用JSON.parse(JSON.stringify(lineData))
const polylineList = JSON.parse(JSON.stringify(lineData))
.map((item: any) => item.polyline)
.reduce((pre, next) => {
const newNext = next
for (var i = 2; i < newNext.length; i++) {
newNext[i] = newNext[i - 2] + newNext[i] / 1000000
}
let resList = []
for (var j = 0; j < newNext.length; j++) {
resList.push({
latitude: parseFloat(newNext[j].toFixed(5)),
longitude: parseFloat(newNext[j + 1].toFixed(5)),
})
j++
}
return pre.concat(resList)
}, [])}
return polylineList
虽然官网没有说,但是
polyline
其实是一个对象数组,每一个对象都是表示一段线段,所以我们线路一般有两种展示形式:1.直接合并在为一个数组放进points里面,这种方式适合每条线段样式一致,不需要单独处理的情况。如果我们需要针对每条线段做定制化的需求,可以创建多个对象的形式进行展示。本文使用第一种方式。
最后我们直接使用拿到的数据
<map
style="width: 100%; height: 800rpx"
:longitude="103.934669"
:latitude="30.868603"
:polyline="[
{
points: polylineListRes,
color: '#000',
width: 3,
dottedLine: false,
},
]"
></map>
不积跬步无以至千里,不积小流无以成江海。