作者:webTF,来自原文地址
自从小程序发布以来,一直负责着公司有关小程序的开发工作,也一直很顺利,期间也完成了一个项目的上线,现在该项目要迭代第二个版本实现路线规划的功能。最开始认为应该和网页端一样呢,其实不然。网页端是引入官方提供的JS库文件,然后根据api文档提供的接口调用相关接口,路线自动会渲染在页面上,而小程序这个则需要我们自己去处理路线数据,组装成小程序能识别的数据结构。下面将本人实现过程中的总结汇报给大家,希望对大家有帮助。
一、场景描述这是一个连锁加盟的企业,数据库里储存了各经销商的位置,要求系统具备可以让用户点击位置规划出从用户所在位置到该经销商的路线图。在传统web端实现起来比较轻松,我们只需要通过H5的位置接口获取用户当前位置。然后引入第三方地图组件库,调用相关api。路线自然会渲染到页面中。 <script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp"></script> <script> var start; // 起点位置 var drivingService; // 驾车服务实例 var option = JSON.parse(sessionStorage.getItem("end")); var end = new qq.maps.LatLng(option['lat'],option['lnt']); //数据库存储的位置 function callback( res ){ start = new qq.maps.LatLng(res.coords.latitude, res.coords.longitude); var map = new qq.maps.Map(document.getElementById("container"), { center: start }); //设置获取驾车线路方案的服务 drivingService = new qq.maps.DrivingService({ map: map, //展现结果 panel: document.getElementById('infoDiv') }); search(); } //设置搜索地点信息、驾车方案等属性 function search( ) { var type = ["LEAST_TIME","LEAST_DISTANCE","AVOID_HIGHWAYS","REAL_TRAFFIC","PREDICT_TRAFFIC"]; /** * LEAST_TIME => 最少时间 * LEAST_DISTANCE => 最短距离 * AVOID_HIGHWAYS => 避开高速 * REAL_TRAFFIC => 实时路况 * PREDICT_TRAFFIC => 预测路况 */ //设置驾车方案 drivingService.setPolicy(qq.maps.DrivingPolicy[type[0]]); //设置驾车的区域范围 drivingService.setLocation("天津"); //设置回调函数 drivingService.setComplete(function(result) { if (result.type == qq.maps.ServiceResultType.MULTI_DESTINATION) { alert("起终点不唯一"); } }); //设置检索失败回调函数 drivingService.setError(function(data) { alert(data); }); //设置驾驶路线的起点和终点 drivingService.search(start, end); } window.onload=function () { if (navigator.geolocation) { //判断浏览器是否支持地理位置接口 navigator.geolocation.getCurrentPosition(callback,function () { var citylocation,map,marker = null; var init = function() { var center = new qq.maps.LatLng(39.916527,116.397128); var city = document.getElementById("city"); map = new qq.maps.Map(document.getElementById('container'),{ center: center, zoom: 13 }); //获取 城市位置信息查询 接口 citylocation = new qq.maps.CityService({ //设置地图 map : map, complete : function(results){ console.log(results.detail.latLng); var latlng = results.detail.latLng; callback({coords:{"latitude": latlng.getLat(),"longitude":latlng.getLng()}}); } }); } init(); citylocation.searchCityByIP("{$ip}"); }); } } </script> 二、小程序实现思路同样的功能我们要放到小程序里实现,自然要先看看小程序是否提供了相关的接口了呢。
上图就是小程序提供的位置地图相关api。我尝试调用了openLocation接口。 var address = wx.getStorageSync('latlng');//数据库存储的位置 wx.openLocation({ latitude: address.lat, longitude: address.lng, name:"茶业精品店", address:"河北省胡家庄兴园路567号", scale: 28 })
正如上图所示出现了我想要的去这里按钮,但是在苹果手机(iphone 6 ios9.3.2)上是调不起该组件的。后面经过一番查阅在社区里面找到了答案,苹果上会默认把参数当成字符串解析,我们需要手动转成Number类型。调整后代码如下: var address = wx.getStorageSync('latlng');//数据库存储的位置 wx.openLocation({ latitude: Number(address.lat), longitude: Number(address.lng), name:"茶业精品店", address:"河北省胡家庄兴园路567号", scale: 28 })
我们可以点击右下角调用手机自带地图或者导航软件,进行路线规划。 三、需求升级我们想直接一次性点击展现路线,在展现路线的同一页页面展现一些自定义的别的内容,控制地图的展现大小,或者要求不能让用户离开我们的小程序,那我们该怎么做呢?这个时候我们就需要借助小程序提供的map组件。
该组件的具体使用方法就不在这详述了,还没掌握的请参考@SoberLi小李君著的小程序入门教程,我在这里只介绍如何组成polyline参数并传给map组件。百度路线规划接口我这里采取的方式是小程序通过请求后端接口将起点和终点坐标传给后端,然后我在通过后端去和百度对接(方法不唯一)。 wx.request({ url: API+"/index.php?s=/Home/Address/wxaddress",//后端接口地址 data:{ "fromlat" : res.latitude,//起点纬度 "fromlng" : res.longitude,//起点经度 "tolat" : address.lat,//终点纬度 "tolng" : address.lng//终点经度 }, method: 'GET', success: function(ress){} }); 以下是服务端php请求接口处理数据,如果不懂php得可以直接跳过看返回的json数据。 public function wxaddress(){ $fromlat = $_GET['fromlat'];//接收起点纬度 $fromlng = $_GET['fromlng'];//接收起点经度 $tolat = $_GET['tolat'];//接收终点纬度 $tolng = $_GET['tolng'];//接收终点经度 $url = "http://api.map.baidu.com/direction/v2/transit?origin=$fromlat,$fromlng&destination=$tolat,$tolng&ak=l51Pp7gkTg8aqPNIgUh3UlClq8NBBeza";//接口地址 $datajson = $this -> curl( "" , $url,"GET");//发送请求并接收结果 $obj = json_decode($datajson,true);//将返回的json转换成php能操作的对象; if ( $obj && $obj['status'] ==0 ) { apiResponse( "success" , "返回成功!" , $obj['result']['routes'][0] );//返回给小程序端。 }else{ apiResponse( "error" , "返回错误!" ); } } 后端处理完成的返回数据,我后端只返回了一条路线,如果大家想在这个地图上绘制多条路线,可以不做这个过滤。 { "distance": 23270, "duration": 10677, "arrive_time": "2017-04-26 20:44:00", "price": 129.5, "price_detail": [], "steps": [ [ { "distance": 1277, "duration": 1021, "instructions": "步行1277米", "path": "116.94460025367,36.63355502879;116.94460025367,36.63355502879;116.94469906728,36.633236457119;116.94454635534,36.630839886738;116.9444744909,36.627690201059;116.94443855868,36.627552625622;116.94437567729,36.627444013259;116.94434872813,36.627393327437;116.94181550659,36.629724840449;116.94146516744,36.6299710209;116.94062974332,36.630673354884;116.94056686193,36.630246162817;116.9405129636,36.62979000594", "traffic_condition": [], "start_location": { "lng": 116.94528296586, "lat": 36.633772235985 }, "end_location": { "lng": 116.94048601443, "lat": 36.62979000594 }, "vehicle_info": { "type": 5, "detail": null } }, { "distance": 3828, "duration": 878, "instructions": "前魏华庄站乘9路(火车站方向)经过8站到经十路段兴西路站", "path": "116.94048601443,36.62979000594;116.94055787888,36.632671713166;116.94045906527,36.635176827602;116.94089923497,36.641895341563;116.94060279415,36.645609093992;116.94040516694,36.64725959265;116.94048601443,36.647599822587;116.940252455,36.651009277163;116.9400727939,36.651972004283;116.94000991251,36.656937456611;116.94080042136,36.656951932676;116.94708855993,36.65657555409;116.94730415326,36.656691363083;116.94893906928,36.656568316022", "traffic_condition": [], "start_location": { "lng": 116.94048601443, "lat": 36.62979000594 }, "end_location": { "lng": 116.94893906928, "lat": 36.65657555409 }, "vehicle_info": { "type": 3, "detail": { "name": "9路", "type": 0, "stop_num": 8, "on_station": "前魏华庄站", "off_station": "经十路段兴西路站", "first_time": "05:30", "last_time": "21:00" } } } ] ] } // 以上steps数据只节选了一部分 以上数据的详细解析我就不写了,大家不明白的可以去百度地图文档查看,steps是该条路线的步骤集合类型是数组,经过简单分析我们需要拿到的是每一步里面的path路径经纬度集合,而微信文档里面给出的格式是这样的[{latitude: 0, longitude: 0}];所以我们需要循环遍历取出里面的每一个path,具体js代码实现如下: var steps = server.data.steps;//获取步骤集合 var polyline = []; steps.map(function(item,index){ //item 为路线里面的每一大步 if(item && item.length > 0){ item.map(function(step,index){ //step 为每一大步里面的每一小阶段 var path = step.path;//取出该阶段的path,关键点的经纬度集合。 if(path){ var arr = path.split(";");//通过上面的json数据,我们可以看到path存储的关键点使用“;”隔开的,这里我们通过这一项把它转换成数组进行操作。 arr.map(function(point,index){ //point为每一个坐标点,格式为"116.94048601443,36.62979000594",逗号前面是longitude,逗号后面是latitude; var pointarr = point.split(",");//我们再把每一个点转成数组,以方便我们操作。 if(pointarr.length == 2){ //把我们取到的每一个点以微信官方要求的数据结构push到一个polyline数组里面去。 polyline.push({ longitude : pointarr[0], latitude : pointarr[1] }); } }); } }) //最后我们将polyline数组setData到微信组件里去。 that.setData({ "polyline":[{ "points" : polyline, "color" : "#ff000088", "width" : 5 }] }); // wxml是这个样子的 <map polyline="{{polyline}}" longitude="{{centerlng}}" latitude="{{centerlat}}" scale="8"></map> 当你顺利完成以上步骤时,那么恭喜你就可以看到这个效果了。喜欢的话点个赞,关注一下小编吧。
补充: 1.以上方法仅供参考,实现方法各式各样。 2.小编开发过程中用的是百度地图,后来发现腾讯地图路线规划更好使一点。(腾讯地图direction API提供步行(walking),驾车(driving),公交(transit)三种出行方式的路线规划服务。)腾讯支持jsonp跨域请求。(建议尝试) |