小程序基於Map組件實現路線規劃
一、場景描述
這是一個連鎖加盟的企業,數據庫裏儲存了各經銷商的位置,要求系統具備可以讓用戶點擊位置規劃出從用戶所在位置到該經銷商的路線圖。在傳統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跨域請求。(建議嘗試)
3.如果發現小編哪裏寫的不好,歡迎指點。