当前位置 博文首页 > 一起来捉 Bug 呀~~:微信小程序 LBS 能力全面解析

    一起来捉 Bug 呀~~:微信小程序 LBS 能力全面解析

    作者:[db:作者] 时间:2021-09-02 10:13

    1 月 9 日随着小程序的发布,在技术圈内引起一大波浪潮,在已发布的小程序中大部分已经用到了腾讯位置服务能力,而且一部分小程序是强依赖位置服务能力的,如:摩拜单车、通勤助手等必须要获取用户位置才能进行后续的交互,吃喝玩乐类的小程序在店铺详情都会有地址位置展示页面。这些都是腾讯位置服务的地图能力体现。当然小程序里包含的地图能力还远不止这些,下面让我们对小程序里的位置服务能力一一进行分享。

    分享之前我们先来看看地图能力在小程序架构体现中所处的位置。

    小程序架构图解

    如图标黄处为地图能力所处的一个位置,举个例子,比如调用定位能力获取用户当前位置的一个流程:

    首先调用 JS API wx.getLocation 接口 -> 调用地图 sdk 获取位置接口 -> 地图 sdk 成功后回调 -> JS API 成功后回调。

    回归正题,了解了整体的调用流程,下面我们对具体的地图能力进行详细讲解。

    小程序位置服务能力

    目前微信小程序下,提供了丰富的组件和 API 供开发者使用,其中原生提供的位置服务已经包含核心位置能力 API 及地图组件。

    位置能力 API

    不仅包括基础的定位 API,也提供了位置展示和位置选择的调用 API,开发者只需要一个 API 就能直接调起原生能力,通过极低的成本就能完成相应的开发。

    wx.getLocation(OBJECT)

    获取当前的地理位置、速度。

    场景

    几乎任何一个应用都要获取用户当前的位置,大家应该经常会看到一个提示xxx要获取你当前的位置 允许 不允许,这就是获取当前位置的安全验证提示。知道了我的位置就可以实现周边的饭店、学校、厕所、出租车等等一系列周边相关的场景。

    示例代码:

    wx.getLocation({
      type: 'gcj02',
      success: function(res) {
        var latitude = res.latitude
        var longitude = res.longitude
        var speed = res.speed
        var accuracy = res.accuracy
      }
    })

    wx.chooseLocation(OBJECT)

    打开地图选择位置

    场景

    选择一个位置可以快速填写购物时的配送地址,选择另外一个位置去订外卖,一般在回家的路上提前订好,到家就正好可以吃了。出去旅游前我们要选择景点周边的住宿等等都离不开要选择另为一个位置的场景。

    效果

    示例代码:

    wx.chooseLocation({
        success: function (res) {
            var latitude = res.latitude
            var longitude = res.longitude
            var name= res.name
            var address= res.address
         },
         cancel: function () {
           console.log('取消')
         },
         fail: function () {
           console.log('失败');
         }
       })

    注意:在选点时如果是通过拖动地图并且选中的是默认的第一条,则很有可能 success 回调中 name 字段为空,因为这样标的点不一定能对应到 POI,列表中的非第一条内容则为以当前点的经纬度检索周边的 poi,所以除第一条其它都是有名称的,大家在使用的时候需要注意一下。

    POI(Point of Interest,兴趣点)。在地图表达中,一个 POI 可代表一栋大厦、一家商铺、一处景点等等。

    wx.openLocation(OBJECT)

    使用微信内置地图查看位置。

    场景

    展示一个位置的场景大家应该经常见到,比如:美团、点评里的店铺详情页面都有个店铺地址,点击进入会看到地图上标记了一个位置点。效果类似下图。

    效果

    代码示例:

    wx.openLocation({
         latitude: 39.908683,
         longitude: 116.397915,
         scale: 18,
         name: '天安门',
         address: '北京市东城区外桥',
         complete: function () {
           console.log('complete:', arguments);
         }
     });

    map 组件

    组件是小程序为开发者提供的基础组件,示例:, map组件包含以下四个功能性属性 markers、polyline、circles、controls。下边对以上四个属性分别介绍。接口详细说明见小程序 Map 组件文档。

    map 组件-markers

    在地图上显示位置点。

    场景

    相对上面的接口 wx.openLocation(OBJECT),此接口可以实现一个自定义的位置展示,而且也可以实现多个位置点同时显示到地图上。比如:周边的XXX在通过地图的形式展示。这里只说一个位置点,多点只是 markers 参数传入多个点。后面示例会涉及到,这里就不赘述了。

    效果

    代码示例

    // wxml 结构
    <view class="container">
        <map bindtap="tap" class="map-container" markers="{{markers}}" longitude="{{longitude}}" latitude="{{latitude}}"></map>
        <view class="marker-info">
            <text class="title weui-fs-17">{{markers[0].title}}</text>
            <text class="address weui-fs-14 weui-fc-grey">{{markers[0].address}}</text>
        </view>
    </view>
    // js 代码
    /**
     * 通过组件自定义marker
     */
    var app = getApp()
    Page({
      data: {},
      onReady: function () {
        this.setData({
          latitude: 39.984060,
          longitude: 116.307520,
          markers: [{
            id: 100,
            latitude: 39.984060,
            longitude: 116.307520,
            title: '中国技术交易大厦',
            address: '北京市海淀区北四环西路66号',
            iconPath: '/images/home_press.png'
          }]
        });
      }
    })

    注意: map 的 longitude、latitude 中心点坐标要与 markers 的数据一致这样位置点才能标记到地图视野的中心。

    map 组件-polyline

    画线,指定一系列坐标点,从数组第一项连线至最后一项。

    场景

    轨迹绘制,运动轨迹分享,经验路线分享等相关路线的功能。

    效果

    代码示例

    // WXML
    <map id="map" markers="{{markers}}" class="map-container" include-points="{{includePoints}}" polyline="{{lines}}" longitude="{{longitude}}" latitude="{{latitude}}"></map>
    // JS 这里只贴一下代码结构
    latitude: 39.984519,
    longitude: 116.307793,
    includePoints: [{
        latitude: 39.984519,
        longitude: 116.307793
    }, ...],
    lines: [{
        points: [{
            latitude: 39.984519,
            longitude: 116.307793
        },...],
        color: "#5c95e6FF",
        width: 8,
        dottedLine: false
    }],
    markers: [{
        latitude: 39.984519,
        longitude: 116.307793,
        iconPath: '/images/marker.png',
        width: 20,
        height: 30
    }, {
        latitude: 39.965938,
        longitude: 116.307793,
        iconPath: '/images/marker.png',
        width: 20,
        height: 30
    }]

    注意: include-points 属性是将所有的点展示到可视区域内,但是如果不设置中心点 latitude、longitude 会有不能展现到视野内的问题,开发时需要注意,include-points 属性可以通过计算所有点的最大矩形左下经纬度&右上经纬度来设置,这样可以减小 setData 的数据。因为小程序 setData 的数据传输有 1M 的限制。

    map 组件-circles

    场景

    周边某范围内XXX的展示,外卖配送范围的展示,比如:周边1000米有没有厕所,这家饭店送餐的区域等。

    效果

    代码示例

    // wxml
    <map id="map" bindtap="onMapTap" longitude="{{longitude}}" latitude="{{latitude}}" class="map-container" circles="{{circles}}" ></map>
    // js代码
    var map;
    Page({
        data: {
            latitude: 40.118246,
            longitude: 116.430135,
            circles: [{
                latitude: 40.118246,
                longitude: 116.430135,
                radius: 2000,
                fillColor: '#0079ffa0',
                color: '#000000ff',
                strokeWidth: 2
            }]
        }
    })

    map 组件-controls

    场景

    主要实现地图内的交互场景,下面以回到当前位置为例,点击地图右下方的控件执行回到当前的位置。当然也可以换成酒店、餐饮、娱乐等。

    效果

    示例代码

    var map;
    Page({
        data: {},
        onReady: function () {
            console.log('map实例', map);
            if (!map) {
                map = wx.createMapContext('map');
            }
            var info = wx.getSystemInfoSync();
            this.setData({
                controls: [{
                    id: 1,
                    position: { left: info.windowWidth - 70, top: info.windowHeight - 70, width: 50, height: 50 },
                    clickable: true,
                    iconPath: '/images/location.png'
    
                }]
            });
    
        },
    
        /**
         * 控件点击处理函数
         */
        onControlclick: function (e) {
            switch (e.controlId) {
                case 1: {
                    map.moveToLocation();
                }
            }
    
        }
    })

    注意: 在设置控件位置时要用wx.getSystemInfoSync()接口返回的逻辑宽windowWidthwindowHeight进行定位。控件点击处理函数中需要通过e.controlId对应控件设置的 id 进行区分处理。

    wx.createMapContext(mapId)

    创建并返回 map 上下文 mapContext 对象,主要包括方法有getCenterLocation、moveToLocation,控件示例已经涉及到就举例说明了,请参见小程序wx.createMapContext(mapId) API文档。

    小程序地图应用示例

    结合上述地图能力,分享一个找厕所的例子。

    需求

    实现一个找厕所的功能,找周边1000米内的厕所。并把厕所的位置点标到地图上。点击位置点对应icon放大并且在地图下方显示相应的名称、地址信息。

    实现

    主要分三个步骤:

    1. 获取当前位置
    2. 通过检索服务搜索当前位置周边的厕所
    3. 在地图视野内标记所有位置点以及位置的交互

    效果

    代码示例

    <view class="container">
        <map id="map" class="map-container" bindmarkertap="onMarkerclick" markers="{{markers}}" show-location include-points="{{points}}" ></map>
        <view class="marker-info">
            <text class="title weui-fs-17">{{markers[index].title}}</text>
            <text class="address weui-fs-14 weui-fc-grey">{{markers[index].address}}</text>
        </view>
    </view>

    获取当前位置

    // 通过小程序API接口wx.getLocation获取当前位置
    wx.getLocation({
        "type": 'gcj02',
        success: function (res) {
            console.log('微信定位成功:', res.latitude + ',' + res.longitude);
        },
        fail: function (res) {
            // ...
        }
    });

    通过检索服务WebService API搜索当前位置周边1000的厕所

    var that = this;
       var url = 'https://apis.map.qq.com/ws/place/v1/search';
        wx.request({
            url: url,
            data: {
                key: 'http://lbs.qq.com/ 平台申请',
                keyword: '公厕',
                address_format: 'short',
                boundary: 'nearby(' + lat + ',' + lng + ',1000,0)'
            },
            success: function (res) {
                console.log('检索数据:', res.data)
                cb && cb(res.data);
            }
        })

    在地图视野内标记所有位置点以及位置点的点击交互

    /**
     * 通过检索数据设置标注点
     */
    addMarkers: function (data) {
        var markers = [];
        var points = [];
        for (var i = 0; i < data.data.length; i++) {
            var d = data.data[i];
            var o = {};
            var p = {};
            p.latitude = d.location.lat;
            p.longitude = d.location.lng;
            o.id = i + 1;
            o.latitude = d.location.lat;
            o.longitude = d.location.lng;
            o.title = d.title;
            o.address = d.address;        o.iconPath = '/images/marker.png';
            o.width = 20;
            o.height = 30;
            markers.push(o);        points.push(o);    }
        this.setData({
           markers: markers,        points: points,
           index: 1
        });
    }
    
    onMarkerclick: function (e) {
        console.log('marker 点击', e);
        var markerId = e.markerId;    var markers = this.data.markers;    var index = 0;
        for (var i = 0; i < markers.length; i++) {
            markers[i].width = 20;
            markers[i].height = 30;
            if (markers[i].id == markerId) {
                markers[i].width = 30;
                markers[i].height = 40;
                index = i;
            }
        }
        this.setData({
           markers: markers,        index: index
        });
    }

    结语

    整体来看,目前小程序下的位置服务能力已经能够覆盖LBS应用的大部分场景,随着小程序生态的逐步完善,相信有更多的LBS场景会被挖掘,腾讯位置服务会联合小程序持续打造更加完善的LBS能力。


    了解最新移动开发、VR/AR 干货技术分享,请关注 mobilehub 微信公众号(ID: mobilehub)。

    cs