|
作者:webTF,來自原文地址
自從小程序發(fā)布以來,一直負(fù)責(zé)著公司有關(guān)小程序的開發(fā)工作,也一直很順利,期間也完成了一個項(xiàng)目的上線,現(xiàn)在該項(xiàng)目要迭代第二個版本實(shí)現(xiàn)路線規(guī)劃的功能。最開始認(rèn)為應(yīng)該和網(wǎng)頁端一樣呢,其實(shí)不然。網(wǎng)頁端是引入官方提供的JS庫文件,然后根據(jù)api文檔提供的接口調(diào)用相關(guān)接口,路線自動會渲染在頁面上,而小程序這個則需要我們自己去處理路線數(shù)據(jù),組裝成小程序能識別的數(shù)據(jù)結(jié)構(gòu)。下面將本人實(shí)現(xiàn)過程中的總結(jié)匯報(bào)給大家,希望對大家有幫助。
一、場景描述這是一個連鎖加盟的企業(yè),數(shù)據(jù)庫里儲存了各經(jīng)銷商的位置,要求系統(tǒng)具備可以讓用戶點(diǎn)擊位置規(guī)劃出從用戶所在位置到該經(jīng)銷商的路線圖。在傳統(tǒng)web端實(shí)現(xiàn)起來比較輕松,我們只需要通過H5的位置接口獲取用戶當(dāng)前位置。然后引入第三方地圖組件庫,調(diào)用相關(guān)api。路線自然會渲染到頁面中。
<script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp"></script>
<script>
var start; // 起點(diǎn)位置
var drivingService; // 駕車服務(wù)實(shí)例
var option = JSON.parse(sessionStorage.getItem("end"));
var end = new qq.maps.LatLng(option['lat'],option['lnt']); //數(shù)據(jù)庫存儲的位置
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
});
//設(shè)置獲取駕車線路方案的服務(wù)
drivingService = new qq.maps.DrivingService({
map: map,
//展現(xiàn)結(jié)果
panel: document.getElementById('infoDiv')
});
search();
}
//設(shè)置搜索地點(diǎn)信息、駕車方案等屬性
function search( ) {
var type = ["LEAST_TIME","LEAST_DISTANCE","AVOID_HIGHWAYS","REAL_TRAFFIC","PREDICT_TRAFFIC"];
/**
* LEAST_TIME => 最少時間
* LEAST_DISTANCE => 最短距離
* AVOID_HIGHWAYS => 避開高速
* REAL_TRAFFIC => 實(shí)時路況
* PREDICT_TRAFFIC => 預(yù)測路況
*/
//設(shè)置駕車方案
drivingService.setPolicy(qq.maps.DrivingPolicy[type[0]]);
//設(shè)置駕車的區(qū)域范圍
drivingService.setLocation("天津");
//設(shè)置回調(diào)函數(shù)
drivingService.setComplete(function(result) {
if (result.type == qq.maps.ServiceResultType.MULTI_DESTINATION) {
alert("起終點(diǎn)不唯一");
}
});
//設(shè)置檢索失敗回調(diào)函數(shù)
drivingService.setError(function(data) {
alert(data);
});
//設(shè)置駕駛路線的起點(diǎn)和終點(diǎn)
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({
//設(shè)置地圖
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>
二、小程序?qū)崿F(xiàn)思路同樣的功能我們要放到小程序里實(shí)現(xiàn),自然要先看看小程序是否提供了相關(guān)的接口了呢。
上圖就是小程序提供的位置地圖相關(guān)api。我嘗試調(diào)用了openLocation接口。
var address = wx.getStorageSync('latlng');//數(shù)據(jù)庫存儲的位置
wx.openLocation({
latitude: address.lat,
longitude: address.lng,
name:"茶業(yè)精品店",
address:"河北省胡家莊興園路567號",
scale: 28
})
正如上圖所示出現(xiàn)了我想要的去這里按鈕,但是在蘋果手機(jī)(iphone 6 ios9.3.2)上是調(diào)不起該組件的。后面經(jīng)過一番查閱在社區(qū)里面找到了答案,蘋果上會默認(rèn)把參數(shù)當(dāng)成字符串解析,我們需要手動轉(zhuǎn)成Number類型。調(diào)整后代碼如下:
var address = wx.getStorageSync('latlng');//數(shù)據(jù)庫存儲的位置
wx.openLocation({
latitude: Number(address.lat),
longitude: Number(address.lng),
name:"茶業(yè)精品店",
address:"河北省胡家莊興園路567號",
scale: 28
})
我們可以點(diǎn)擊右下角調(diào)用手機(jī)自帶地圖或者導(dǎo)航軟件,進(jìn)行路線規(guī)劃。 三、需求升級我們想直接一次性點(diǎn)擊展現(xiàn)路線,在展現(xiàn)路線的同一頁頁面展現(xiàn)一些自定義的別的內(nèi)容,控制地圖的展現(xiàn)大小,或者要求不能讓用戶離開我們的小程序,那我們該怎么做呢?這個時候我們就需要借助小程序提供的map組件。
該組件的具體使用方法就不在這詳述了,還沒掌握的請參考@SoberLi小李君著的小程序入門教程,我在這里只介紹如何組成polyline參數(shù)并傳給map組件。百度路線規(guī)劃接口我這里采取的方式是小程序通過請求后端接口將起點(diǎn)和終點(diǎn)坐標(biāo)傳給后端,然后我在通過后端去和百度對接(方法不唯一)。
wx.request({
url: API+"/index.php?s=/Home/Address/wxaddress",//后端接口地址
data:{
"fromlat" : res.latitude,//起點(diǎn)緯度
"fromlng" : res.longitude,//起點(diǎn)經(jīng)度
"tolat" : address.lat,//終點(diǎn)緯度
"tolng" : address.lng//終點(diǎn)經(jīng)度
},
method: 'GET',
success: function(ress){}
});
以下是服務(wù)端php請求接口處理數(shù)據(jù),如果不懂php得可以直接跳過看返回的json數(shù)據(jù)。
public function wxaddress(){
$fromlat = $_GET['fromlat'];//接收起點(diǎn)緯度
$fromlng = $_GET['fromlng'];//接收起點(diǎn)經(jīng)度
$tolat = $_GET['tolat'];//接收終點(diǎn)緯度
$tolng = $_GET['tolng'];//接收終點(diǎn)經(jīng)度
$url = "http://api.map.baidu.com/direction/v2/transit?origin=$fromlat,$fromlng&destination=$tolat,$tolng&ak=l51Pp7gkTg8aqPNIgUh3UlClq8NBBeza";//接口地址
$datajson = $this -> curl( "" , $url,"GET");//發(fā)送請求并接收結(jié)果
$obj = json_decode($datajson,true);//將返回的json轉(zhuǎn)換成php能操作的對象;
if ( $obj && $obj['status'] ==0 ) {
apiResponse( "success" , "返回成功!" , $obj['result']['routes'][0] );//返回給小程序端。
}else{
apiResponse( "error" , "返回錯誤!" );
}
}
后端處理完成的返回?cái)?shù)據(jù),我后端只返回了一條路線,如果大家想在這個地圖上繪制多條路線,可以不做這個過濾。
{
"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路(火車站方向)經(jīng)過8站到經(jīng)十路段興西路站",
"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": "經(jīng)十路段興西路站",
"first_time": "05:30",
"last_time": "21:00"
}
}
}
]
]
}
// 以上steps數(shù)據(jù)只節(jié)選了一部分
以上數(shù)據(jù)的詳細(xì)解析我就不寫了,大家不明白的可以去百度地圖文檔查看,steps是該條路線的步驟集合類型是數(shù)組,經(jīng)過簡單分析我們需要拿到的是每一步里面的path路徑經(jīng)緯度集合,而微信文檔里面給出的格式是這樣的[{latitude: 0, longitude: 0}];所以我們需要循環(huán)遍歷取出里面的每一個path,具體js代碼實(shí)現(xiàn)如下:
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,關(guān)鍵點(diǎn)的經(jīng)緯度集合。
if(path){
var arr = path.split(";");//通過上面的json數(shù)據(jù),我們可以看到path存儲的關(guān)鍵點(diǎn)使用“;”隔開的,這里我們通過這一項(xiàng)把它轉(zhuǎn)換成數(shù)組進(jìn)行操作。
arr.map(function(point,index){
//point為每一個坐標(biāo)點(diǎn),格式為"116.94048601443,36.62979000594",逗號前面是longitude,逗號后面是latitude;
var pointarr = point.split(",");//我們再把每一個點(diǎn)轉(zhuǎn)成數(shù)組,以方便我們操作。
if(pointarr.length == 2){
//把我們?nèi)〉降拿恳粋€點(diǎn)以微信官方要求的數(shù)據(jù)結(jié)構(gòu)push到一個polyline數(shù)組里面去。
polyline.push({
longitude : pointarr[0],
latitude : pointarr[1]
});
}
});
}
})
//最后我們將polyline數(shù)組setData到微信組件里去。
that.setData({
"polyline":[{
"points" : polyline,
"color" : "#ff000088",
"width" : 5
}]
});
// wxml是這個樣子的
<map polyline="{{polyline}}" longitude="{{centerlng}}" latitude="{{centerlat}}" scale="8"></map>
當(dāng)你順利完成以上步驟時,那么恭喜你就可以看到這個效果了。喜歡的話點(diǎn)個贊,關(guān)注一下小編吧。
補(bǔ)充: 1.以上方法僅供參考,實(shí)現(xiàn)方法各式各樣。 2.小編開發(fā)過程中用的是百度地圖,后來發(fā)現(xiàn)騰訊地圖路線規(guī)劃更好使一點(diǎn)。(騰訊地圖direction API提供步行(walking),駕車(driving),公交(transit)三種出行方式的路線規(guī)劃服務(wù)。)騰訊支持jsonp跨域請求。(建議嘗試) |