uniapp小程序使用高德地图api实现路线规划
uniapp小程序使用高德地图api实现路线规划
Posted on 2023-01-10 11:18 书中枫叶 阅读(1387) 评论(3) 编辑 收藏 举报路线规划
简介
路线规划常用于出行路线的提前预览,我们提供4种类型的路线规划,分别为:驾车、步行、公交和骑行,满足各种的出行场景。
高德开放平台
本例是驾车路线规划功能和位置选择地图api:chooseLocation
示例:
1、在页面的 js 文件中,实例化 AMapWX 对象,请求进行驾车路线规划。
首先,引入 amap-wx.js 文件(amap-wx.js 从相关下载页面下载的 zip 文件解压后得到)。
import amapFile from "@/libs/amap-wx.js"; |
然后在 onLoad 实例化 AMapWX 对象
onLoad() { | |
this.myAmapFunT = new amapFile.AMapWX({ | |
key: 你申请的key | |
}) | |
}, |
最后生成请求进行驾车路线规划数据
/** | |
*@author ZY | |
*@date 2023/1/9 | |
*@Description:生成规划路线 | |
*@param {string} start 开始位置 | |
*@param {string} end 结束位置 | |
*@param {number} strategy 10 默认多策略 策略 https://lbs.amap.com/api/webservice/guide/api/direction#driving | |
* | |
10,返回结果会躲避拥堵,路程较短,尽量缩短时间,与高德地图的默认策略也就是不进行任何勾选一致 | |
* 4,躲避拥堵,但是可能会存在绕路的情况,耗时可能较长 | |
2,距离优先,仅走距离最短的路线,但是可能存在穿越小路/小区的情况 | |
*/ | |
getPlanningRoute(start, end, strategy = 10) { | |
let that = this | |
uni.showLoading({ | |
title: '加载中' | |
}); | |
that.myAmapFunT.getDrivingRoute({ | |
origin: start, | |
destination: end, | |
strategy: strategy, //备选方案 | |
success: function(data) { | |
// console.log('所有路径',data) | |
if (data.paths && data.paths[0] && data.paths[0].steps) { | |
// 默认 10 会 对返回多条路径的方案 按照时间短的 | |
let goodRouter = data.paths.sort((a, b) => { | |
return a.duration - b.duration | |
})[0] | |
that.distance = (goodRouter.distance * 0.001).toFixed(2) + '公里' | |
that.duration = '大约' + (goodRouter.duration / 60).toFixed(2) + '分钟' | |
let steps = goodRouter.steps | |
let points = [] | |
for (var i = 0; i < steps.length; i++) { | |
var poLen = steps[i].polyline.split(';'); | |
for (var j = 0; j < poLen.length; j++) { | |
points.push({ | |
longitude: parseFloat(poLen[j].split(',')[0]), | |
latitude: parseFloat(poLen[j].split(',')[1]) | |
}) | |
} | |
} | |
that.polyline = [{ | |
points: points, | |
color: strategy === 10 ? '#0ee532' : strategy === 2 ? '#0742d9' : | |
'#ee6b06', | |
width: 8, | |
}] | |
} | |
uni.hideLoading(); | |
}, | |
fail: function(info) { //失败回调 | |
console.log('路线规划失败') | |
console.log(info) | |
uni.hideLoading(); | |
uni.showToast({ | |
title: '路线规划失败', | |
icon: 'error' | |
}); | |
}, | |
}) | |
}, |
2.完整源码组件
<template> | |
<view class="content"> | |
<view class="back-button" @click="toBack"> | |
<image src="http://img.wisdomtaxi.com/toBack.png" style="width: 100%; height: 100%;"></image> | |
</view> | |
<map class="order-map" :latitude="startPoint.latitude" :longitude="startPoint.longitude" show-location | |
:polyline="polyline" @markertap="markertap" :key="polyline.length + new Date().getTime()" | |
:markers="markers"> | |
<cover-view slot="callout"> | |
<block v-for="(item,index) in markers" :key="index"> | |
<cover-view class="customCallout" :marker-id="item.id"> | |
<cover-view class="customCalloutContent"> | |
{{item.title}} | |
</cover-view> | |
</cover-view> | |
</block> | |
</cover-view> | |
</map> | |
<view class="order-box"> | |
<view class="search-start" v-if="endPoint.address"> | |
<view class="custom-style" v-for="item in btnList" :key="item.value" | |
:class="{active:flag === item.value}" @click="selectRouteType(item.value)"> | |
{{item.name}} | |
</view> | |
</view> | |
<view class="search-start" v-if="distance || duration"> | |
<u-icon name="file-text-fill" color="#FFA500" size="17"></u-icon> | |
<view class="start-name"> | |
距离:{{distance}} 时间:{{duration}} | |
</view> | |
</view> | |
<view class="search-start"> | |
<u-icon name="map-fill" color="#33a63b" size="17"></u-icon> | |
<view class="start-name"> | |
您将在 <text style="color: #33a63b">{{startPoint.name | fmtEndAddr}}</text> 上车 | |
</view> | |
</view> | |
<view class="search-start" v-if="endPoint.name"> | |
<u-icon name="map-fill" color="#ee642b" size="17"></u-icon> | |
<view class="start-name"> | |
{{endPoint.name|fmtEndAddr}} | |
</view> | |
</view> | |
<view class="search-box" @click="openChooseLocation"> | |
<u-icon name="search" color="#ffa602" size="23"></u-icon> | |
<view class="search-placeholder"> | |
请选择目的地 | |
</view> | |
</view> | |
<view v-if="endPoint.name" @click="submitToDriver" class="send-btn"> | |
发送给司机 | |
</view> | |
</view> | |
</view> | |
</template> | |
<script> | |
import uniIcons from "@/components/uni-icons/uni-icons.vue"; | |
import amapFile from "@/libs/amap-wx.js"; | |
export default { | |
components: { | |
uniIcons | |
}, | |
data() { | |
return { | |
markers: [], | |
tripInfo: {}, | |
polyline: [], | |
startPoint: { | |
latitude: 26.56045894387685, //纬度 | |
longitude: 106.68005128661751, //经度 | |
name: '', | |
address: '' | |
}, | |
endPoint: {}, | |
myAmapFunT: null, | |
distance: 0, //距离 | |
duration: 0, //时间 | |
flag: 10, | |
btnList: [{ | |
name: '推荐', | |
value: 10 | |
}, | |
{ | |
name: '躲避拥堵', | |
value: 4 | |
}, | |
{ | |
name: '距离短', | |
value: 2 | |
}, | |
] | |
} | |
}, | |
filters: { | |
fmtEndAddr(val) { | |
if (val === null || val === '' || val === undefined) { | |
return '未知地址'; | |
} | |
return val; | |
}, | |
}, | |
onLoad() { | |
this.myAmapFunT = new amapFile.AMapWX({ | |
key: 你申请的key | |
}) | |
this.getCurrentLocation(); | |
}, | |
methods: { | |
//返回 | |
toBack() { | |
uni.navigateBack({}); | |
}, | |
//获取当前定位 | |
getCurrentLocation() { | |
let that = this | |
uni.getLocation({ | |
type: 'gcj02', | |
success: function(res) { | |
// console.log('当前:' , res); | |
// console.log('当前位置的经度:' + res.longitude); | |
// console.log('当前位置的纬度:' + res.latitude); | |
that.startPoint.longitude = res.longitude; | |
that.startPoint.latitude = res.latitude; | |
that.getAddress(that.startPoint.longitude + ',' + that.startPoint.latitude) | |
} | |
}); | |
}, | |
// 解析地址 | |
getAddress(loc) { | |
var that = this; | |
var myAmapFun = this.myAmapFunT | |
if (loc !== null && loc !== '' && loc !== undefined) { | |
myAmapFun.getRegeo({ | |
iconPath: 'http://img.wisdomtaxi.com/amap_icon.png', | |
width: '37.5rpx', | |
height: '37.5rpx', | |
location: loc, | |
success: function(data) { //成功回调 | |
// console.log('地址解析',data) | |
that.startPoint.name = data[0].name | |
that.startPoint.address = data[0].desc | |
that.initMap() | |
}, | |
fail: function(info) { //失败回调 | |
console.log(info) | |
}, | |
}); | |
} | |
}, | |
//初始化地图数据 | |
initMap() { | |
this.markers.push({ | |
id: 1, | |
latitude: this.startPoint.latitude, //纬度 | |
longitude: this.startPoint.longitude, //经度 | |
iconPath: '/static/images/home/start.png', //显示的图标 | |
rotate: 0, // 旋转度数 | |
width: 30, //宽 | |
height: 30, //高 | |
title: this.startPoint.name, //标注点名 | |
// alpha: 0.5, //透明度 | |
joinCluster: true, | |
customCallout: { | |
anchorY: 0, | |
anchorX: 0, | |
display: "ALWAYS", | |
}, | |
}, ) | |
}, | |
/** | |
*@author ZY | |
*@date 2023/1/9 | |
*@Description:选择位置 | |
*@param {Object} opt https://uniapp.dcloud.net.cn/api/location/location.html | |
* | |
opt : { | |
latitude Number 否 目标地纬度 | |
longitude Number 否 目标地经度 | |
} | |
*/ | |
openChooseLocation(opt) { | |
let that = this | |
uni.chooseLocation({ | |
latitude: opt?.latitude || that.startPoint.latitude, | |
longitude: opt?.longitude || that.startPoint.longitude, | |
success: function(res) { | |
// console.log(res) | |
// console.log('位置名称:' + res.name); | |
// console.log('详细地址:' + res.address); | |
// console.log('纬度:' + res.latitude); | |
// console.log('经度:' + res.longitude); | |
if (!res.name) { | |
return uni.showToast({ | |
title: '请重新选择位置', | |
icon: 'none' | |
}); | |
} | |
//设置终点 | |
that.endPoint = { | |
longitude: res.longitude, | |
latitude: res.latitude, | |
name: res.name, | |
address: res.address | |
} | |
//设置终点标记 | |
that.markers[1] = { | |
id: 2, | |
latitude: res.latitude, //纬度 | |
longitude: res.longitude, //经度 | |
iconPath: '/static/images/home/endd.png', //显示的图标 | |
rotate: 0, // 旋转度数 | |
width: 30, //宽 | |
height: 30, //高 | |
title: res.name, //标注点名 | |
// alpha: 0.5, //透明度 | |
joinCluster: true, | |
customCallout: { | |
anchorY: 0, | |
anchorX: 0, | |
display: "ALWAYS" | |
}, | |
} | |
let start = that.startPoint.longitude + ',' + that.startPoint.latitude | |
let end = res.longitude + ',' + res.latitude | |
//每次选取位置完成后都会默认 10 策略 | |
that.flag = 10 | |
//生成规划路线 | |
that.getPlanningRoute(start, end, 10) | |
}, | |
fail: function(info) { //失败回调 | |
console.log('调取失败') | |
console.log(info) | |
}, | |
}) | |
}, | |
// 按钮选择策略 | |
selectRouteType(idx) { | |
this.flag = idx | |
let start = this.startPoint.longitude + ',' + this.startPoint.latitude | |
let end = this.endPoint.longitude + ',' + this.endPoint.latitude | |
this.getPlanningRoute(start, end, idx) | |
}, | |
/** | |
*@author ZY | |
*@date 2023/1/9 | |
*@Description:生成规划路线 | |
*@param {string} start 开始位置 | |
*@param {string} end 结束位置 | |
*@param {number} strategy 10 默认多策略 策略 https://lbs.amap.com/api/webservice/guide/api/direction#driving | |
* | |
10,返回结果会躲避拥堵,路程较短,尽量缩短时间,与高德地图的默认策略也就是不进行任何勾选一致 | |
* 4,躲避拥堵,但是可能会存在绕路的情况,耗时可能较长 | |
2,距离优先,仅走距离最短的路线,但是可能存在穿越小路/小区的情况 | |
*/ | |
getPlanningRoute(start, end, strategy = 10) { | |
let that = this | |
uni.showLoading({ | |
title: '加载中' | |
}); | |
that.myAmapFunT.getDrivingRoute({ | |
origin: start, | |
destination: end, | |
strategy: strategy, //备选方案 | |
success: function(data) { | |
// console.log('所有路径',data) | |
if (data.paths && data.paths[0] && data.paths[0].steps) { | |
// 默认 10 会 对返回多条路径的方案 按照时间短的 | |
let goodRouter = data.paths.sort((a, b) => { | |
return a.duration - b.duration | |
})[0] | |
that.distance = (goodRouter.distance * 0.001).toFixed(2) + '公里' | |
that.duration = '大约' + (goodRouter.duration / 60).toFixed(2) + '分钟' | |
let steps = goodRouter.steps | |
let points = [] | |
for (var i = 0; i < steps.length; i++) { | |
var poLen = steps[i].polyline.split(';'); | |
for (var j = 0; j < poLen.length; j++) { | |
points.push({ | |
longitude: parseFloat(poLen[j].split(',')[0]), | |
latitude: parseFloat(poLen[j].split(',')[1]) | |
}) | |
} | |
} | |
that.polyline = [{ | |
points: points, | |
color: strategy === 10 ? '#0ee532' : strategy === 2 ? '#0742d9' : | |
'#ee6b06', | |
width: 8, | |
}] | |
} | |
uni.hideLoading(); | |
}, | |
fail: function(info) { //失败回调 | |
console.log('路线规划失败') | |
console.log(info) | |
uni.hideLoading(); | |
uni.showToast({ | |
title: '路线规划失败', | |
icon: 'error' | |
}); | |
}, | |
}) | |
}, | |
// 点击标记点 | |
markertap(e) { | |
let opt = this.markers.find(el => { | |
return el.id === e.detail.markerId | |
}) | |
this.openChooseLocation(opt) | |
}, | |
// 提交给司机 | |
submitToDriver() { | |
let p = {} | |
p.idCard = uni.getStorageSync('driverInfo').idCard || '' | |
p.startLocation = this.startPoint.longitude + ',' + this.startPoint.latitude | |
p.startAddr = this.startPoint.name || '未知' | |
p.endLocation = this.endPoint.longitude + ',' + this.endPoint.latitude | |
p.endAddr = this.endPoint.name || '未知' | |
p.plan = this.flag || 10 | |
p.locations = this.polyline[0].points || [] | |
if (!p.idCard) { | |
return uni.showToast({ | |
title: '司机信息获取失败', | |
icon: 'none' | |
}); | |
} | |
uni.showLoading({ | |
title: '提交中' | |
}); | |
let that = this | |
this.request('api_sendDestination', p).then(res => { | |
uni.hideLoading(); | |
uni.showToast({ | |
title: '发送成功' | |
}) | |
setTimeout(()=>{ | |
that.toBack() | |
},1000) | |
}).catch(err => { | |
console.log(err) | |
uni.hideLoading(); | |
uni.showToast({ | |
title: '发送失败', | |
icon: 'error' | |
}) | |
}) | |
} | |
}, | |
} | |
</script> | |
<style lang="scss" scoped> | |
.content { | |
display: flex; | |
flex-direction: column; | |
text-align: center; | |
align-content: center; | |
background: #f5f5f9; | |
height: 1600rpx; | |
} | |
.back-button { | |
z-index: 9; | |
position: fixed; | |
top: 95rpx; | |
left: 30rpx; | |
height: 50rpx; | |
width: 50rpx; | |
border-radius: 50%; | |
background-color: #FFA500; | |
/* box-shadow: 0 9.375rpx 28.125rpx 9.375rpx rgba(106, 66, 0, 0.2); */ | |
} | |
.order-map { | |
width: 100%; | |
height: 100%; | |
} | |
.order-box { | |
position: fixed; | |
bottom: 0rpx; | |
left: 0rpx; | |
width: 100%; | |
//height: 435rpx; | |
text-align: left; | |
background-color: #FFFFFF; | |
border-top-right-radius: 10rpx; | |
border-top-left-radius: 10rpx; | |
box-sizing: border-box; | |
padding: 18rpx; | |
padding-bottom: 80rpx; | |
box-shadow: 0 9.375rpx 28.125rpx 9.375rpx rgba(106, 66, 0, 0.2); | |
.send-btn { | |
margin-top: 30rpx; | |
width: 100%; | |
color: white; | |
background-color: #ffa602; | |
padding: 0 24rpx; | |
font-size: 28rpx; | |
height: 80rpx; | |
line-height: 80rpx; | |
box-sizing: border-box; | |
border-radius: 12rpx; | |
text-align: center; | |
} | |
/*box-shadow: 0 9.375rpx 28.125rpx 9.375rpx rgba(106, 66, 0, 0.2);*/ | |
.search-start { | |
font-size: 30rpx; | |
margin: 18rpx 0; | |
padding-left: 15rpx; | |
display: flex; | |
justify-content: flex-start; | |
align-items: center; | |
box-sizing: border-box; | |
.start-name { | |
width: 550rpx; | |
padding-left: 10rpx; | |
overflow: hidden; | |
/*文本不会换行*/ | |
white-space: nowrap; | |
/*当文本溢出包含元素时,以省略号表示超出的文本*/ | |
text-overflow: ellipsis; | |
} | |
.custom-style { | |
margin-right: 10rpx; | |
border-radius: 6rpx; | |
border: 1rpx solid #ebedf0; | |
font-size: 24rpx; | |
padding: 8rpx 24rpx; | |
&:last-child { | |
margin-right: 0; | |
} | |
&.active { | |
color: #FFFFFF; | |
background-color: #ffa602; | |
border-color: #ffa602; | |
} | |
} | |
} | |
.search-box { | |
background-color: #f3f3f3; | |
border-radius: 36rpx; | |
height: 80rpx; | |
display: flex; | |
justify-content: flex-start; | |
align-items: center; | |
box-sizing: border-box; | |
padding: 0 25rpx; | |
.search-placeholder { | |
font-size: 28rpx; | |
color: #bbb9b9; | |
padding-left: 15rpx; | |
} | |
} | |
} | |
.addH { | |
height: 420rpx; | |
/*+100*/ | |
} | |
.row { | |
display: flex; | |
flex-direction: row; | |
} | |
.bot { | |
margin-bottom: 10rpx; | |
} | |
.license { | |
position: relative; | |
left: 30rpx; | |
height: 110rpx; | |
font-weight: bold; | |
font-size: 38rpx; | |
line-height: 130rpx; | |
letter-spacing: 1.125rpx; | |
/* border: 0.01rem solid #555555; */ | |
} | |
.time-icon { | |
height: 16rpx; | |
width: 16rpx; | |
position: relative; | |
left: 190rpx; | |
top: 59rpx; | |
} | |
.time-text { | |
height: 110rpx; | |
line-height: 130rpx; | |
position: relative; | |
left: 200rpx; | |
font-size: 30rpx; | |
color: #666666; | |
/* border: 0.01rem solid #555555; */ | |
} | |
.route-icon { | |
height: 12rpx; | |
width: 12rpx; | |
position: relative; | |
left: 42rpx; | |
top: 30rpx; | |
} | |
.route-text { | |
height: 65rpx; | |
width: 478rpx; | |
line-height: 65rpx; | |
position: relative; | |
left: 50rpx; | |
font-size: 30rpx; | |
color: #666666; | |
overflow: hidden; | |
text-overflow: ellipsis; | |
white-space: nowrap; | |
/* border: 0.01rem solid #555555; */ | |
} | |
.amt-box { | |
width: calc(100% - 558rpx); | |
margin-left: 40rpx; | |
display: flex; | |
flex-direction: row; | |
justify-content: flex-start; | |
align-items: center; | |
/* border: 1rpx solid #555555; */ | |
} | |
.amt-icon { | |
margin-top: 5rpx; | |
line-height: 65rpx; | |
height: 20rpx; | |
width: 20rpx; | |
} | |
.amt { | |
margin-left: 10rpx; | |
line-height: 65rpx; | |
/*line-height: 80rpx;*/ | |
font-size: 30rpx; | |
color: #666666; | |
} | |
.todo { | |
position: relative; | |
height: 165rpx; | |
width: 640rpx; | |
margin-left: 30rpx; | |
border-top: 0.375rpx solid #E9EAEC; | |
} | |
.todo-item { | |
height: 100%; | |
width: 50%; | |
text-align: center; | |
align-content: center; | |
/* border: 0.01rem solid #555555; */ | |
} | |
.todo-item>image { | |
height: 60rpx; | |
width: 60rpx; | |
margin-top: 30rpx; | |
} | |
.todo-item>view { | |
color: #3F3F3F; | |
font-size: 30rpx; | |
letter-spacing: 0.375rpx; | |
/* border: 0.01rem solid #555555; */ | |
} | |
</style> | |
<style> | |
/* *************************************** */ | |
.customCallout { | |
box-sizing: border-box; | |
background-color: #fff; | |
border: 1px solid #ccc; | |
border-radius: 30px; | |
padding: 5px 10px; | |
} | |
.customCalloutContent { | |
font-size: 20rpx; | |
word-wrap: break-word; | |
} | |
</style> | |
本文来自博客园,作者:书中枫叶,转载请注明原文链接:https://www.cnblogs.com/zy-mg/p/17039609.html
漫思