查看: 79|回复: 0

uniapp小程序使用高德地图api实现路线规划

[复制链接]

3

主题

4

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2023-1-14 10:02:34 | 显示全部楼层 |阅读模式
路线规划

简介

路线规划常用于出行路线的提前预览,我们提供4种类型的路线规划,分别为:驾车、步行、公交和骑行,满足各种的出行场景。 高德开放平台
本例是驾车路线规划功能和位置选择地图api:chooseLocation

<hr/>示例:



位置选择和路线规划

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.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.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>
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表