微信小程序——定位、地图显示、线路规划导航

一、地图API选择

1、查看微信小程序自带的api和相关其他的api,微信团队自带的map组件理解不深,高德地图的api简明易理解使用。
2、原app开发采用的是高德地图组件,为了和app能够保持一致性,采取高德地图开发工具作为本次地图开发首选。

微信小程序地图map组件开发文档
微信小程序MapContext开发文档
高德地图开发文档

二、高德地图相关资料下载

2.1、js下载

amap-wx.js

2.2、高德key申请

key的申请

2.3、相关配置

高德官方配置

三、手写一个demo

3.1、再全局apps.js中注册全局key

App({
  d: {
    .....
  },
  gdMapProperties:{
    key:"xxxxxx"
  },
  ....

3.2、创建指定的页面和地图操作

创建指定的页面,并进行路由设置,要求能够跳转进页面。
3.2.1、在地图页面的js中,引入全局的js配置和高德自己的amap-wx.js文件。

var amapFile = require("../../../utils/amap-wx.js");
const apps = getApp();

3.2.2、在获取位置信息前,需要优先判断小程序是否开启了位置权限信息

app.json中,标识权限信息

 "permission": {
    "scope.userLocation": {
      "desc": "您的位置信息将用于设备定位和蓝牙操作"
    }
  },

在获取位置信息前,判断权限信息。

使用高德地图获取位置信息,失败时则判断是否具有权限信息

onLoad: function () {
    var that = this;
    this.data.myAmapFun = new amapFile.AMapWX({ key: apps.gdMapProperties.key });
    //授权检测
    getPermission(this);
  },
//授权检测函数封装
function getPermission(obj) {
  obj.data.myAmapFun.getPoiAround({
    success: function (data) {
      console.log("获取poi数据成功回调:" + JSON.stringify(data));
      markersData = data.markers;
      //判断获取的位置信息数
      if(markersData.length > 0){
        //存在数据  取第一条数据作为当前用户的位置信息值
        obj.setData({
          latitude: markersData[0].latitude,
          longitude: markersData[0].longitude,
        });
      }else{
        //不存在位置信息时,采取微信自带地图实现定位效果
        wx.getLocation({
          type: 'gcj02',
          success: function(res) {
            //显示经纬度信息
            obj.setData({
              latitude: res.latitude,
              longitude: res.longitude
            });
          },
          fail: function () {
            //失败则采取中国北京作为地图显示
            obj.setData({
              latitude: 39.909729,
              longitude: 116.398419
            });
          }
        })
      }

    },
    fail: function (info) {
      console.log("获取poi数据失败回调:" + info);
      //如果失败 则先检测权限是否给予
      wx.getSetting({
        success: function (res) {
          var statu = res.authSetting;
          if (!statu['scope.userLocation']) {
            wx.showModal({
              title: '是否授权当前位置',
              content: '需要获取您的地理位置,请确认授权,否则地图功能将无法使用',
              success: function (tip) {
                if (tip.confirm) {
                  wx.openSetting({
                    success: function (data) {
                      if (data.authSetting["scope.userLocation"] === true) {
                        wx.showToast({
                          title: '授权成功',
                          icon: 'success',
                          duration: 1000
                        })
                        //授权成功之后,再调用定位进行位置获取
                        getPermission(obj);
                      } else {
                        wx.showToast({
                          title: '授权失败',
                          icon: 'success',
                          duration: 1000
                        })
                      }
                    }
                  })
                }
              }
            })
          }
        },
        fail: function (res) {
          wx.showToast({
            title: '调用授权窗口失败',
            icon: 'success',
            duration: 1000
          })
        }
      })

    }
  })
}

3.2.3、marker显示

<view class="map_container">
  <map class="map" id="map" 
  longitude="{{longitude}}" 
  latitude="{{latitude}}" 
  scale="18" 
  show-location="true" 
  markers="{{markers}}" 
  bindmarkertap="makertap" 
  bindtap='onclickMap'>
  </map>
</view>
data: {
    myAmapFun: null,//高德地图对象
    //marker 设备位置信息
    markers: [{ id: "1", latitude: "30.499488", longitude:"114.342586"}],
    latitude: '',
    longitude: '',
    textData: {}
  }

当自定义data属性中的marker属性时,采取微信 map 组件实现地图显示,能够将marker信息显示在地图指定的区域内。
如果是公司自己的开发设备,需要在地图上显示设备信息时,则可以在onload 页面加载完成时,请求服务器获取相关的设备的经纬度信息。

注意:

此处采取的是 微信的 map组件 和 marker标识 组件信息,所以设定信息,需要采取微信官方文档的要求来,比如marker需要给定不同的id,可以提升响应速率等。
微信map组件和marker组件文档

3.2.4、线路规划操作

此时需求为:点击地图对应的marker标识时,需要在地图上显示对应的线路规划信息。
线路规划有很多种类,包括 步行、驾车、打车、乘骑等,我们目前只考虑两种方式,步行和驾车出行。

<view class="gotoView">
    <view class="gotobyDriver" bindtap="gotobyDriver">驾车</view>
    <view class="gotobywalk" bindtap="gotobywalk" >步行</view>
  </view>

1、采取驾车出行方式显示线路规划

gotobyDriver:function(){
    console.log("驾车出行");
    //通过api  获取线路点数
    var that = this;
    this.data.myAmapFun.getDrivingRoute({
      origin:that.data.longitude+","+that.data.latitude,
      destination: that.data.markers[0].longitude + "," + that.data.markers[0].latitude,
      success:function(data){
        //获取当前经纬度信息到目标经纬度信息间无数个经纬度点位
        var points = [];
        if (data.paths && data.paths[0] && data.paths[0].steps) {
          var steps = data.paths[0].steps;
          //保存信息详情
          that.setData({
            detailSteps: steps
          });
          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.setData({
          polyline: [{
            points: points,
            color: "#0091ff",
            width: 6
          }]
        });
      },
      fail: function (info) {

      }
    });
  },

2、选择步行的出行方式线路规划

//步行出行
  gotobywalk:function(){
    console.log("步行出行");
    //通过api  获取线路点数
    var that = this;
    this.data.myAmapFun.getWalkingRoute({
      origin: that.data.longitude + "," + that.data.latitude,
      destination: that.data.markers[0].longitude + "," + that.data.markers[0].latitude,
      success: function (data) {
        //获取当前经纬度信息到目标经纬度信息间无数个经纬度点位
        var points = [];
        if (data.paths && data.paths[0] && data.paths[0].steps) {
          var steps = data.paths[0].steps;
          console.log(JSON.stringify(steps));
          //保存信息详情
          that.setData({
            detailSteps: steps
          });
          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.setData({
          polyline: [{
            points: points,
            color: "#0091ff",
            width: 6
          }]
        });
      },
      fail: function (info) {

      }
    });
  },

四、整体完整代码

github小程序定位、地图显示、线路规划完整demo

五、2019.10.31 对定位代码进行修改操作

昨晚用微信开发者工具测试,地图都能正常显示,也能进行相应的线路规划操作,但采取微信最新版本+小米8se实现真机实测时,却出现了定位到了非洲西边的海域,通过查询日志发现:

1、obj.data.myAmapFun.getPoiAround 无成功和失败回调,但有时也有回调信息,具体问题还在分析。
2、map组件出现位置点位是 show-location设置为true时,自动显示的,但依旧无经纬度信息(注意点)
当无当前手机所在区域的位置信息时,线路规划是无法正常进行的,设置初始的经纬度信息测试发现,可以进行线路规划操作,证明此时的想法是正确的。
我们的小程序开发,客户的使用范围是全国各地都有,我们的初始经纬度信息不可能写死吧,所以我们还得继续死磕,如何获取动态的、具体的经纬度信息!!

通过阅读文档发现:
在微信api 位置 中,有一个接口,wx.getLocation(Object object),在微信给予的demo中,并未写明fail回调信息,通过我的测试发现,当未授予位置信息获取权限时,此接口会进入失败回调。那如何能够具体实现动态的定位呢?我们修改 getPermission(obj) 函数。

function getPermission(obj) {
  console.log("getPermission");
  wx.getLocation({
    type: 'gcj02',
    success: function (res) {
      console.log("success  === "+JSON.stringify(res));
      //显示经纬度信息
      obj.setData({
        latitude: res.latitude,
        longitude: res.longitude
      });
    },
    fail: function (res) {
      console.log("fail == "+JSON.stringify(res));
      //获取位置信息失败,判断是否存在位置权限未给予,造成的影响
      if (!obj.data.getLocationFailAgain){
        console.log("首次失败  查询位置权限的授权情况");
        obj.setData({
          getLocationFailAgain:true
        });
        wx.getSetting({
          success: function (res) {
            var statu = res.authSetting;
            if (!statu['scope.userLocation']) {
              wx.showModal({
                title: '是否授权当前位置',
                content: '需要获取您的地理位置,请确认授权,否则地图功能将无法使用',
                success: function (tip) {
                  if (tip.confirm) {
                    wx.openSetting({
                      success: function (data) {
                        if (data.authSetting["scope.userLocation"] === true) {
                          wx.showToast({
                            title: '授权成功',
                            icon: 'success',
                            duration: 1000
                          })
                          //授权成功之后,再调用定位进行位置获取
                          getPermission(obj);
                        } else {
                          wx.showToast({
                            title: '授权失败',
                            icon: 'success',
                            duration: 1000
                          });
                          obj.setData({
                            latitude: 39.909729,
                            longitude: 116.398419
                          });
                        }
                      }
                    })
                  }else{
                    //点击取消操作
                    wx.showToast({
                      title: '授权失败',
                      icon: 'success',
                      duration: 1000
                    });
                    obj.setData({
                      latitude: 39.909729,
                      longitude: 116.398419
                    });
                  }
                }
              })
            }
          },
          fail: function (res) {
            wx.showToast({
              title: '调用授权窗口失败',
              icon: 'success',
              duration: 1000
            })
            //失败则采取中国北京作为地图显示
            obj.setData({
              latitude: 39.909729,
              longitude: 116.398419
            });
          }
        })
      }
      
    }
  })
}

修改后的函数判断相对简单,为了防止不断进入死循环,所以在全局data中加入了一个标识,如果请求了设置信息接口,则表示不会继续走权限获取操作流程。具体的代码还是去看我的github代码吧。

————————————————
作者:「专注写bug」
原文链接:https://blog.csdn.net/qq_38322527/article/details/102800670

推荐阅读更多精彩内容