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
漫思
浙公网安备 33010602011771号