2015年7月3日 星期五

如何使用Google Map API的導航(Directions)

作者常常想如果騎Youbike時,但又不知騎到哪一站時才能停車時,此時此刻如果可以查詢出附近的哪一個Youbike站有停車格是多麼令人感動的事啊! 雖然已經有不少APP已經有類似的功能了,但作者還是想自己動手做。

一、下戴Youbike的串接資料及官方的文件說明

請先下戴有關Youbikejson檔案

因為作者僅是示範教學,如果需要用到官方的即時資訊,是需要事先申請的,還請各位注意,記得把資料的串接改成GET模式

二、引用google Map v3的函式庫
<link href="Content/jquery.mobile-1.4.5.min.css" rel="stylesheet" />
<script src="scripts/jquery-2.1.4.min.js"></script>
<script src="scripts/jquery.mobile-1.4.5.js"></script> 
<script src="scripts/index.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=geometry"></script>

注意: 如果想要離線地圖的朋友們,可以考慮以下的網址 http://fanli7.net/a/JAVAbiancheng/JAVAzonghe/20120824/211085.html
但沒有提供導航的效果喔~

三、html網頁結構
<div data-role="page" id="yobikePage">
        <div data-role="header" data-theme="b">        </div>
        <div data-role="content" data-theme="b">
            <div id="map_canvas" style="left:0;top:0;width:100%;height:95%;position:absolute;"></div>
            <a href="#geolocation_destination" data-rel="close" id="geolocation_showDialog">Open dialog</a>          
        </div>
        <div data-role="footer" data-id="foo1" data-position="fixed" data-theme="b">
            <div data-role="navbar">
                <ul>
                    <li><a href="#yobikePage" class="ui-btn-active ui-state-persist"><img src="images/youBike.png" /></a></li>
                    <li><a href="#navigationPage"><img src="images/natigation.png" /></a></li>
                </ul>
            </div>
        </div>
<!-- 顯示點選的Youbike站的相關資訊(站名、住址、經緯度、現有腳踏車數、
允許停車空位數)  -->
        <div data-role="panel" data-position="right" data-display="overlay" id="geolocation_destination" data-theme="b">
            <div data-role="header">
                <center><span id="markerTitle"></span></center>
            </div>
            <div data-role="content">
                <h2><b>經緯度:</b></h2>
                <p><span id="markerLong"></span>&nbsp; / &nbsp; <span id="markerLat"></span></p>
                <h2><b>住址:</b></h2>
                <p>
                    <span id="markerAddr"></span>
                </p>
                <h2><b>距離位置</b></h2>
                <p><span id="markerDistance"></span>&nbsp;單位: (/)</p>
                <h2><b>場內車輛數</b></h2>
                <p><span id="markerSbi"></span>&nbsp;單位: ()</p>
                <h2><b>場內停車數</b></h2>
                <p><span id="markerBemp"></span>&nbsp;單位: ()</p>
                <a href="#pageone" id="btnDestination" data-rel="close" class="ui-btn ui-btn-inline ui-shadow ui-corner-all ui-btn-a ui-icon-delete ui-btn-icon-left">設定目的地</a>
            </div>
        </div>

    </div>

 <div data-role="page" id="navigationPage">
        <div data-role="header" data-theme="b">          
        </div>
        <div data-role="content">
            <ul data-role="listview" data-filter="true" id="youBikes"></ul>
        </div>
        <div data-role="footer" data-id="foo1" data-position="fixed" data-theme="b">
            <div data-role="navbar">
                <ul>
                    <li><a href="#yobikePage"><img src="images/youBike.png" /></a></li>
                    <li><a href="#navigationPage" class="ui-btn-active ui-state-persist"><img src="images/natigation.png" /></a></li>
                </ul>
            </div>
        </div>
    </div>
  
</body>
</html>

網頁的功能如下所示:
(1) 顯示所有Youbike的所有站名
(2) 在地圖上顯示所有Youbike的位置,YoubikeMarker可以設定終點站,
就能偵測『目前位置』自動導航到『設為終點』的Youbike
(3) 顯示點選的Youbike站的相關資訊(站名、住址、經緯度、現有腳踏車數、
允許停車空位數)

四、初始化google map的語法
var map;
var mapOptions = {
        zoom: 12, //預設地圖的比例大小
        center: new google.maps.LatLng(25.051150, 121.566002),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);

五、設定加入導航
var directionsService = new google.maps.DirectionsService();
//規畫路徑呈現選項
var rendererOptions = {
    suppressMarkers: true,
};
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
directionsDisplay.setMap(map);

六、取得目前的座標,並將Marker加在地圖上
var options = {
    enableHighAccuracy: true,
    timeout: 5000,
    maximumAge: 0
};
navigator.geolocation.getCurrentPosition(success, error, options);

function success(position) {   
    setCurrentLocation(position.coords.latitude, position.coords.longitude);
};
function error() {
    alert("取得經緯失敗");
};

function setCurrentLocation(lat, lon) {
    currentPosition = new google.maps.LatLng(lat, lon); //設目前位置的座標  
    map.setCenter(currentPosition); //以自已位置為地圖中心
    currentMarker = new google.maps.Marker({
        position: currentPosition,
        map: map,
        title: '目前位置',
        icon: "http://maps.google.com/mapfiles/ms/icons/purple-dot.png",
    });  //將目前位置的座標加入到地圖中

    //經過經緯度反查目前座標的住址
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({
        'latLng': currentPosition
    }, function (results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
            if (results) {
                startAddr = results[0].formatted_address;
                var contentString = '目前位置:' + results[0].formatted_address;
                var infowindow = new google.maps.InfoWindow({
                    content: contentString
                });
//點選目前位置座標,有文字方塊顯示目前的地址
                google.maps.event.addListener(currentMarker, 'click', function () {
                    infowindow.open(map, currentMarker);
                });
            }
        } else {
            alert("Reverse Geocoding failed because: " + status);
        }
    });
}

七、取得目前的座標,並將Marker加在地圖上
$.getJSON('scripts/youbike.json', function (data) {
        var youBikeData = data["retVal"];
//逐筆把youbike 的經緯度放在列表和地圖上
        $.each(youBikeData, function (i, v) {
            $('#youBikes').append('<li><a href="#"><h2>' + v["sna"] + '</h2><p>' + v["ar"] + '</p><span class="ui-li-count">' + v["sbi"] + '</span></a></li>').listview('refresh');
            var myLatlng = new google.maps.LatLng(v["lat"], v["lng"]); //youbike站名
            var intSbi = parseInt(v["sbi"]);//剩下腳踏車數量
            var color = "";
            if (intSbi == 0)
            {
                color = "red";
            }
            else if (intSbi > 0 && intSbi <= 5) {
                color = "yellow";
            } else {
                color = "green";
            }
            setMarket(color, { "title": v["sna"], "addr": v["ar"], "bemp": v["bemp"],"sbi":v["sbi"] }, myLatlng, map);
        });
    });

function setMarket(color, title, myLatlng, map) {
    var strMakerLink = "";
    switch (color) {
        case "red":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
            break;
        case "blue":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png';
            break;
        case "yellow":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png';
            break;
        case "purple":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/purple-dot.png';
            break;
        case "green":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/green-dot.png';
            break;
        default:
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
            break;
    }
    //建立地圖google座標
    var marker = new google.maps.Marker({
        position: myLatlng,
        title: title.title,
        icon: strMakerLink,
    })
    //google座標放進地圖
    marker.setMap(map);
    google.maps.event.addListener(marker, 'click', function () {
        var myLatLng = this.position;       
        $("#markerTitle").text(this.title);
        $("#markerLat").text(myLatLng.A);
        $("#markerLong").text(myLatLng.F);
        destinationPosition = myLatLng;
        destionAddr = title.addr;
        $("#markerAddr").text(destionAddr);
//估算『目前位置』和『終點』的距離
        var meters = google.maps.geometry.spherical.computeDistanceBetween(currentMarker.getPosition(), marker.getPosition());
        $("#markerDistance").text(meters);
        $("#markerSbi").text(title.sbi);
        $("#markerBemp").text(title.bemp);
        $("#geolocation_showDialog").click(); //點選座標後,跳出 panel 視窗
        return false;
    });
}

示範畫面:

    可以透過顏色展示目前Youbike的剩下腳踏車數(紅色:0/黃色:5台以內/:5台以上)

八、設定Youbke的站為終點站
//點選設定終點的按鈕
$("#btnDestination").click(function () {
     calcRoute(currentPosition, destinationPosition);
});

//從起點到終點的導航路徑
function calcRoute(startPoint, endPoint) {   
    var request = {
        origin: startPoint,   //可輸入住址名稱或Google座標
        destination: endPoint,
        travelMode: google.maps.TravelMode.DRIVING
    };
    directionsService.route(request, function (response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            directionsDisplay.setDirections(response);
        }
    });
}

示範:

































點選Youbikemarker後,出現panel 畫面,點選『設定為目的地』,就會從目前位置導航路徑到『設為目的地』的站   

全部的範例程式
var map; //地圖
var currentPosition; //取得目前的位置
var destinationPosition; //設定目的地
var directionsService;//導航
var startAddr; //起始點
var destionAddr; //結束點
var currentMarker;//取得起點座標

function setCurrentLocation(lat, lon) {
    currentPosition = new google.maps.LatLng(lat, lon);   
    map.setCenter(currentPosition);
    currentMarker = new google.maps.Marker({
        position: currentPosition,
        map: map,
        title: '目前位置',
        icon: "http://maps.google.com/mapfiles/ms/icons/purple-dot.png",
    });

    //經過經緯度反查住址
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({
        'latLng': currentPosition
    }, function (results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
            if (results) {
                startAddr = results[0].formatted_address;
                var contentString = '目前位置:' + results[0].formatted_address;
                var infowindow = new google.maps.InfoWindow({
                    content: contentString
                });

                google.maps.event.addListener(currentMarker, 'click', function () {
                    infowindow.open(map, currentMarker);
                });
            }
        } else {
            alert("Reverse Geocoding failed because: " + status);
        }
    });
}

function success(position) {   
    setCurrentLocation(position.coords.latitude, position.coords.longitude);
};

function error() {
    alert("取得經緯失敗");
};

function setMarket(color, title, myLatlng, map) {
    var strMakerLink = "";
    switch (color) {
        case "red":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
            break;
        case "blue":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png';
            break;
        case "yellow":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png';
            break;
        case "purple":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/purple-dot.png';
            break;
        case "green":
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/green-dot.png';
            break;
        default:
            strMakerLink = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
            break;
    }
    //建立地圖google座標
    var marker = new google.maps.Marker({
        position: myLatlng,
        title: title.title,
        icon: strMakerLink,
    })
    //google座標放進地圖
    marker.setMap(map);
    google.maps.event.addListener(marker, 'click', function () {
        var myLatLng = this.position;       
        $("#markerTitle").text(this.title);
        $("#markerLat").text(myLatLng.A);
        $("#markerLong").text(myLatLng.F);
        destinationPosition = myLatLng;
        destionAddr = title.addr;
        $("#markerAddr").text(destionAddr);
        var meters = google.maps.geometry.spherical.computeDistanceBetween(currentMarker.getPosition(), marker.getPosition());
        $("#markerDistance").text(meters);
        $("#markerSbi").text(title.sbi);
        $("#markerBemp").text(title.bemp);
        $("#geolocation_showDialog").click(); //點選座標後,跳出視窗
        return false;
    });
}

function setPath(map) {   
    directionsService = new google.maps.DirectionsService();
    //規畫路徑呈現選項
    var rendererOptions = {
        suppressMarkers: true,
    };
    directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
    directionsDisplay.setMap(map);
}

function calcRoute(startPoint, endPoint) {   
    var request = {
        origin: startPoint,
        destination: endPoint,
        travelMode: google.maps.TravelMode.DRIVING
    };
    directionsService.route(request, function (response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            directionsDisplay.setDirections(response);
        }
    });
}

$(document).ready(function () {
    var mapOptions = {
        zoom: 12,
        center: new google.maps.LatLng(25.051150, 121.566002),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
    var options = {
        enableHighAccuracy: true,
        timeout: 5000,
        maximumAge: 0
    };   
    setPath(map);
    navigator.geolocation.getCurrentPosition(success, error, options);
    $.getJSON('scripts/youbike.json', function (data) {
        //逐筆加入youbike
        var youBikeData = data["retVal"];
        $.each(youBikeData, function (i, v) {
            $('#youBikes').append('<li><a href="#"><h2>' + v["sna"] + '</h2><p>' + v["ar"] + '</p><span class="ui-li-count">' + v["sbi"] + '</span></a></li>').listview('refresh');
            var myLatlng = new google.maps.LatLng(v["lat"], v["lng"]); //youbike經緯度
            var intSbi = parseInt(v["sbi"]);//剩下腳踏車數量
            var color = "";
            if (intSbi == 0)
            {
                color = "red";
            }
            else if (intSbi > 0 && intSbi <= 5) {
                color = "yellow";
            } else {
                color = "green";
            }
//可以用JSON格式,將多重值傳遞的方式
            setMarket(color, { "title": v["sna"], "addr": v["ar"], "bemp": v["bemp"],"sbi":v["sbi"] }, myLatlng, map);
        });
    });

    $("#btnDestination").click(function () {
        calcRoute(currentPosition, destinationPosition);
    });
});

九、參考文獻

疑難雜症:

如果各位在phoneGap 中嵌入google Map 是否會遇到總是空白,無法正確地圖顯示,原來是jQueryMobile 的預設onLoad 的事件只是觸發在第一個Page上,所以放置地圖頁面要放在最上面。

沒有留言:

張貼留言