Random Thoughts on Random Things by Tanomsak
Random header image... Refresh for more!

การหาเส้นทางแบบเปลี่ยนแปลงได้กับ Google Maps API

19 Nov 2010

ไม่ได้เขียนถึง Google Maps API นานมาก เผลอแป๊บเดียว ตอนนี้ Google ได้ออกเวอร์ชั่นใหม่แล้วเป็น Google Maps API V3 แล้วครับ โดยที่ใช้งานดีขึ้น เร็วขึ้น และมี function ต่างๆมากขึ้นเยอะเลยครับ

หลังจากโพสเรื่อง การหาเส้นทางโดย Google Maps API ไป มีคำถามเข้ามาเยอะแยะมากครับ แสดงว่าเริ่มมีคนสนใจเขียน Google Maps API กันเยอะขึ้นมาก น่าดีใจครับ วันนี้เลยจะมาเล่าเรื่อง function ใหม่ล่าสุดของการหาเส้นทางโดย Google Maps API ก็คือ Draggable Direction ครับ

ถ้าเคยลองค้นหาเส้นทางใน Google Maps จะเห็นว่าหลังจากเราหาเส้นทางแล้ว เราจะสามารถเลื่อนเส้นทางเพื่อเปลี่ยนแปลงการเดินทางให้ผ่านถนนบางเส้นที่ต้องการได้  สมัยก่อนตัว API ทำไม่ได้ครับ คือพอได้เส้นทางแล้วก็จบแบบว่าเป็นเส้นแข็งๆ แต่เมื่อกลางเดือนกันยายน Google เพิ่งเพิ่มการเปลี่ยนเส้นทางเข้ามาใน API

document จาก Google ครับ http://code.google.com/apis/maps/documentation/javascript/services.html#DraggableDirections

ก่อนอื่นลองดูตัวอย่างว่าเรากำลังจะทำอะไรกันครับ Draggable Direction Example (ลองใช้ mouse จับเส้นทางลาก เพื่อเปลี่ยนเส้นทางครับ)

ทีนี้ลองมาดูกันครับว่ามันทำงานยังไง

        function initialize() {
            var center = new google.maps.LatLng(13.732881766645967,100.48181533813477);
            var myOptions = {
                zoom: 12,
                center: center,
                scrollwheel: false,
                mapTypeControl: false,
                navigationControl: true,
                disableDefaultUI: true,
                streetViewControl: false,
                noClear: false,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            map = new google.maps.Map(document.getElementById("map"), myOptions);

            var rendererOptions = {
                draggable: true
            };
            var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);

            directionsDisplay.setMap(map);
            directionsDisplay.setPanel(document.getElementById("route"));

            var directionsService = new google.maps.DirectionsService();

            var request = {
                origin: "14.068, 100.6009",
                destination: "13.8152, 100.5606",
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };
            directionsService.route(request, function(response, status) {
                if (status == google.maps.DirectionsStatus.OK) {
                    directionsDisplay.setDirections(response);
                }
            });
        }

ส่วนต้นๆของ function initialize จนถึงบรรทัด 14 เป็นการสร้างแผนที่ธรรมดา ตามวิธีของ Google Maps API V3 ครับ มาเริ่มน่าสนใจตั้งแต่บรรทัดที่ 16 ลงมา

ก่อนอื่นมาทำความเข้าใจกันก่อนครับ ว่าใน Google Maps API V3 เนี้ย การหาเส้นทางจะใช้ API หลักๆอยู่ 2 ตัวคือ

  1. google.maps.DirectionsService เอาไว้ request ให้ Google หาเส้นทางให้ โดยเราจะส่งค่า จุดเริ่มต้น จุดสิ้นสุด และวิธีการเดินทางว่าจะเอาเส้นทางแบบขับรถ หรือเดินเท้า ไปให้ Google และ Google ก็จะส่งผลลัพธ์กลับมาให้ครับ
  2. google.maps.DirectionsRenderer เอาไว้แสดงผลลัพธ์ที่ Google ส่งกลับมาให้เราครับ

โดยในบรรทัดที่ 16-22 เป็นการ define DirectionsRenderer เพื่อเอาไว้แสดงผลครับ

โดยเรากำหนดให้เส้นทางที่จะแสดงสามารถจัดเลื่อนได้ โดยการกำหนด parameter draggable : true ในตอนสร้าง DirectionsRenderer

จากนั้นในบรรทัดที่ 21 เรากำหนดให้ ตัวแสดงผลของที่ แสดงเส้นทางในแผนที่ (ตัวแปล map) ที่เราสร้างแผนที่ไว้ก่อนหน้าแล้ว

บรรทัดที่  22 เป็นการกำหนดให้แสดงคำอธิบายเส้นทาง ประมาณว่า “ตรงไป 1 กม. แล้วเลี่้ยวขวา” ใน markup ที่ที id = “route” ซึ่งเรากำหนด DIV ที่มี id = “route” เอาไว้แล้ว

แค่นี้ตัวแสดงผลของเราก็เรียบร้อย เหลือแค่การ request เส้นทางเท่านั้นเองครับ

ในบรรทัดที่ 24 เราก็สร้าง directionsService ขึ้นมาเพื่อเอาไว้ขอเส้นทาง

และเราขอเส้นทางกับ Google โดยใช้ method directionsService.route ครับ โดยรูปแบบการเรียกใช้งานคือ
directionsService.route(request:DirectionsRequest, callback:function(DirectionsResult,DirectionsStatus)))

parameter ตัวแรก DirectionRequest ก็คือพวกระบุจุดเริ่มต้น จุดหมายปลายทาง วิธีการเดินทาง จะให้หลบทางด่วนไหม อะไรประมาณนี้ครับ ใครอยากดูทั้งหมดลองดูที่ (DirectionsRequest)

parameter ตัวที่สอง คือ callback function ที่จะทำงานหลังได้ผลลัพธ์จาก Google ครับ

ในตัวอย่างเราระบุจุดเริ่มต้น จุดหมายปลายทาง และวิธีการเดินทางดังนี้ครับ

var request = {
    origin: "14.068, 100.6009",
    destination: "13.8152, 100.5606",
    travelMode: google.maps.DirectionsTravelMode.DRIVING
};

และบรรทัดที่ 31 ก็ส่ง object request เป็น parameter แรกของ method route และกำหนดให้ callback function แสดงผลลัพธ์ด้วย method directionsDisplay.setDirections(response); ในบรรทัดที่ 33 ครับ

แต่ถ้า Google ไม่สามารถหาเส้นทางได้ status จะไม่เท่ากับ google.maps.DirectionsStatus.OK เราก็จะไม่แสดงผลลัพธ์ครับ

แค่นี้ก็เป็นอันเสร็จครับ เส้นทางที่เราสร้างขึ้นก็จะสามารถจับเลื่อนได้ และหลังจากเปลี่ยนเส้นทางแล้ว Google จะแสดงเส้นทางใหม่พร้อม update คำอธิบายการเดินทางให้เองเลยครับ เห็นไหมครับ ว่า Google Maps API V3 เนี้ยเจ๋งจริงๆ

ถ้ามีคำถามตรงไหน เชิญใน Comment ได้เลยครับ :)

  • Pingback: การหาเส้นทางโดย Google Maps API (GDirections) — tanomsak.com

  • เมษา

    ขอบคุณมากค่ะ
    เข้าใจง่ายทุกเรื่องเกียวกับ google api เลยค่ะ

    มีวิธีใส่ windows info ไหมค่ะ ให้แต่ละหมุด กรณีมีหลายๆหมุดอะค่ะ
    (เป็นเว้บก็ได้ค่ะ)

  • tanomsak

    โดยปกติจะมี infoWindow อยู่แล้วครับ แต่ค่า default จะเป็น address ของจุดนั้นๆครับ ผมเห็นใน document ของ Google มี parameters ให้ใส่ infoWindow ด้วยครับ ลองดูที่

    http://code.google.com/apis/maps/documentation/javascript/reference.html#DirectionsRendererOptions

    แต่ผมไม่เคยใช้ครับ เลยแนะนำไม่ได้

    แต่ถ้าต้องการเปลี่ยนข้อความที่แสดง สามารถทำได้โดย overwrite ค่า address นั้นๆก่อน setDirections ครับ เช่น

    directionsService.route(request, function(response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
    response.routes[0].legs[1].end_address=”End”;
    response.routes[0].legs[1].start_address=”Middle”;
    response.routes[0].legs[0].start_address=”Start”;

    directionsDisplay.setDirections(response);
    }
    });

  • Rain

    สวัสดีคะ… หนูมีคำถามคะ ^_^
    หนูต้องการให้เวลาที่เราคลิ๊กที่ step ของเส้นทางแต่ละ step ที่ map getdirection มา
    (จากตัวอย่างของพี่เวลาคลิ๊กมันจะขึ้น infowindow เป็นรายละเอียดเหมือนกับที่แสดงแต่ละ step ใช่มั้ยคะ)
    หนูสามารถทำให้ใน infowindow ที่คลิ๊กขึ้นเป็น lat,long ที่จุดนั้นได้ด้วยมั้ยคะ
    แล้วก็หนูอยากให้ map คืนค่าเป็น html เช่น getSummaryHtml() ด้วยอ่ะคะ
    พี่พอจะมีตัวอย่างหรือข้อมูลให้หนูศึกษามั้ยคะ

    ขอบคุณมาก ๆ ๆ ๆ นะคะ :D

  • Jandara_man

    พี่ึีัครับ คือผมศึกษาเกี่ยวกับ API Map ครับ เพื่อเอาไปทำโปรเจคจบ เรื่องเกี่ยวกับค้นหาจุดจอดรถตู้(วินรถตู้) ที่ไกล้กับที่อยู่ทึ่สุด
    ตัวอย่างครับ ผมอยู่บางโพ แต่จะไป มหิดล(ศาลายา) โปรแกรมก็จะบอกว่า วินที่ไกล้ที่สุดก็คือ ที่พาต้าโดยใช้ API เป็นตัวบอกว่าการเดินทางไปวินไหนไกล้ที่สุดอ่ะครับ …

    พี่พอเข้าใจไหมครับ ขอโทษน่ะครับที่รบกวน และขอบคุณสำหรับคำตอบ(ตอนนี้กลัวทำโปรเจคไม่จบ TT) ขอบคุณครับ

  • MonkeyZ

    ผมสอบถามหน่อยครับ ตัว direction เย เราสามารถระบุ จุด start และ จุด end หลายๆ ตัวพร้อมกันได้มั้ยครับ
    เหมือนการทำ traffic หน่ะครับ ผมเข้าใจว่าตอนนี้มันสร้าง route ได้แค่เส้นทางเดียว
    รบกวนทีครับ

  • สมคิด

    ดีมากเลยครับ มีวิธี getเอาค่าLatLng เมื่อเราลากเสร็จแล้วเราอยากจะได้ค่าLatLng นะครับต้องเขียนอะไรเพิ่มตรงไหนครับ โดยเอาค่าเก็บไว้ในตัวแปรนะครับต้องทำไงครับ ช่วยที่นะครับ ขอบคุณมากเลยครับ

  • Phanida_gump

    function ของ google map ต้องส่งค่า latitude longitude ไปให้ แล้วเราจะเอาค่าพวกนั้นมาจากไหนคะ

  • Puytu

    อยากรู้เรื่อง การใช้ Buffer zone ใน Google Map พอจะอธิบายได้ไหม ครับ

  • B_wit_tawat

    สวัสดีคับ  คือทำโปรเจกจบอยู่   ต้องการที่    หาระยะทาง    จาก  google  map  โดยมีการกรอก  ข้อมูล ต้นทาง-ปลายทาง   จากผู้ใช้      จะต้องเริ่มต้นยังไงคับ  ทำอะไรบ้างคับ

  • B_wit_tawat

    โค้ดที่ให้ตัวอย่างมา  ทำไมมันรันแล้วไม่ขึ้นอะไรเลยคับ  หรือว่าต้องมีอะไรเพิ่มเติมคับ
      ขอบคุน ครับ

  • Tanasarn

    ขอบคุณมากครับ 

  • Tanasarn

    ขอถามหน่อยนะครับ  
     คือว่าถ้าต้องการคำนวณระยะทางรวมจากจุด A  ไปจุด B และ  จุด  A  กับจุด B  ใส่เป็น คำค้นหา  เช่น  A  = “กรุงเทพมหานคร”  ,  B = “อุบลราชธานี”  เราต้องทำงัยบ้างครับ

  • Tanasarn

    ได้แล้ว

  • Meunchamroen

    คือผมทำdirectionใน v2ได้ แต่พอใน v3 แล้วงง พอจะแนะนำได้ไหมอะครับ

  • Eng52

    map = new google.maps.Map(document.getElementById(“content”), myOptions);                var rendererOptions = {                    draggable: true                };                var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);                directionsDisplay.setMap(map);                directionsDisplay.setPanel(document.getElementById(“route”));
                    var directionsService = new google.maps.DirectionsService();
                    var request = {                    origin: “14.916369978834297,105.06141901016227″,                    destination: latANDlng,                    travelMode: google.maps.DirectionsTravelMode.WALKING//DRIVING//BICYCLING                };                directionsService.route(request, function(response, status) {                    if (status == google.maps.DirectionsStatus.OK) {                        directionsDisplay.setDirections(response);                    }                });

    ผมเขียนแบบนี้ครับ

  • potter

    อยากได้โค้ดค้นหาสถานที่ในรัศมี 10 กม. โดยคลิกแล้ววาดวงกลมรัศมี 10 กม และแสดงรายชื่อสถานที่ในรัศมี 10 กม จากdatabase

  • Gnothnapha

    รบกวนพี่ๆช่วยแก้ไขวิธีการปรับปรุง code  จาก Google map API v2 เป็น Google map API v.3
    ช่วยผมด้วยครับ
    ขอบคุณมากๆ ครับ

    ตัวอย่างโค้ด
    1.index.html

      
        
        map edl
        
        
        
        //<![CDATA[
        var circle = null;
        var circle2 = null;
        var map;
        var geocoder;

        var iconBlue = new GIcon();
        iconBlue.image = 'http://newsirius13.thport.com/picture/c004.png';
        iconBlue.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
        iconBlue.iconSize = new GSize(20, 22);
        iconBlue.shadowSize = new GSize(1, 1);
        iconBlue.iconAnchor = new GPoint(12, ;
        iconBlue.infoWindowAnchor = new GPoint(5, 1);

        var icongreen = new GIcon();
        icongreen.image = 'http://newsirius13.thport.com/picture/c003.png';
        icongreen.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
        icongreen.iconSize = new GSize(20, 22);
        icongreen.shadowSize = new GSize(1, 1);
        icongreen.iconAnchor = new GPoint(12, ;
        icongreen.infoWindowAnchor = new GPoint(5, 1);

        var customIcons = [];
        customIcons["ปิด"] = iconBlue;
        customIcons["เปิด"] = icongreen;

        function load() {
          if (GBrowserIsCompatible()) {
       map = new GMap2(document.getElementById("map_canvas"));
       geocoder = new GClientGeocoder();
       map.addMapType(G_PHYSICAL_MAP);
       map.addControl(new GLargeMapControl());
       map.addControl(new GMapTypeControl());
       map.setCenter(new GLatLng(17.963405,102.611468), 11);
       
          }
       }

       function searchLocationsNear() {
       var asearch = document.getElementById('asearch').value;
       var fsearch = document.getElementById('fsearch').value;
         var searchUrl = "../map/ex_11/ex_11/search.php?fsearch=" + fsearch + "&asearch=" + asearch ;
         GDownloadUrl(searchUrl, function(data) {
           var xml = GXml.parse(data);
           var markers = xml.documentElement.getElementsByTagName('marker');

           var sidebar3 = document.getElementById('sidebar3');
           sidebar3.innerHTML = '';
           if (markers.length == 0) {
             sidebar3.innerHTML = 'nodata';
             map.setCenter(new GLatLng(17.963405,102.611468), 11);
             return;
           }

           var bounds = new GLatLngBounds();
           for (var i = 0; i < markers.length; i++) {
            /*   var fid = markers.getAttribute("id");*/            var polemunber_m = markers.getAttribute("polemunber_m");            var pointtype = markers.getAttribute("pointtype");           /* var fcollection = markers.getAttribute("fcollection");*/            var poletype = markers.getAttribute("poletype");            var district_name = markers.getAttribute("district_name");       /*     var type = markers.getAttribute("type");*/            var point = new GLatLng(parseFloat(markers.getAttribute("lat")),                                    parseFloat(markers.getAttribute("lng")));            var marker = createMarker(point, poletype, district_name, polemunber_m, pointtype);            map.addOverlay(marker);         var sidebarEntry = createSidebarEntry(marker, polemunber_m, district_name);         sidebar3.appendChild(sidebarEntry);         bounds.extend(point);       }       map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));     }); }  function createMarker(point, poletype, district_name, polemunber_m, pointtype) {      var marker = new GMarker(point, customIcons[poletype]);  
       var html = "”+”id:  ”+
    polemunber_m +”"+ “name:   ” + poletype
    +”"+”address:  ”+district_name +”"+”lastname:
     ”+pointtype+”";       GEvent.addListener(marker, ‘click’, function() {       marker.openInfoWindowHtml(html);         });         return marker;    }function createSidebarEntry(marker, polemunber_m, district_name) {  var div = document.createElement(‘div’);  var
    html = ““+”id:  ” + polemunber_m + “
    “+”id:  ” + district_name + ”
    —————————— ” ;  div.innerHTML = html;  div.style.cursor = ‘pointer’;  div.style.marginBottom = ’5px’;  GEvent.addDomListener(div, ‘click’, function() {    GEvent.trigger(marker, ‘click’);  });  GEvent.addDomListener(div, ‘mouseover’, function() {    div.style.backgroundColor = ‘#eee’;  });  GEvent.addDomListener(div, ‘mouseout’, function() {    div.style.backgroundColor = ‘#fff’;  });  return div;}    //]]>                    
                            ຈາກລາຍການ:                                    id            lastname            address                                                           —–2. search.php?createElement(“markers”);$parnode = $dom->appendChild($node);// Opens a connection to a mySQL server$connection=mysql_connect ($hostname, $username, $password);mysql_query(“SET NAMES UTF8″,$connection); if (!$connection) {  die(“Not connected : ” . mysql_error());}// Set the active mySQL database$db_selected = mysql_select_db($database, $connection);if (!$db_selected) {  die (“Can’t use db : ” . mysql_error());}$query = “select * FROM    `dataedl`.`poleedl`    INNER JOIN `dataedl`.`district`         ON (`poleedl`.`district_id` = `district`.`district_id`) where $fsearch like ‘%$asearch%’ “;$result = mysql_query($query);if (!$result) {  die(“Invalid query: ” . mysql_error());}header(“Content-type: text/xml”);// Iterate through the rows, adding XML nodes for eachwhile ($row = @mysql_fetch_assoc($result)){  $node = $dom->createElement(“marker”);  $newnode = $parnode->appendChild($node);  $newnode->setAttribute(“polemunber_m”, $row['polemunber_m']);  $newnode->setAttribute(“lat”, $row['latitude']);  $newnode->setAttribute(“lng”, $row['longitude']);  $newnode->setAttribute(“poletype”, $row['poletype']);  $newnode->setAttribute(“pointtype”, $row['pointtype']);  $newnode->setAttribute(“district_name”, $row['district_name']);}echo $dom->saveXML();?>

  • Dop705

    ตอนนี้กำลังทำอยู่พอดีเลยครับมีคำถามอยู่นิดหน่อยคืออยากทราบว่า ในส่วนของ div id = “route” จะมีการแสดงเส้นทางให้เลือกอยู่บ้างทีก็สองเส้นทางบาทีก็สามเส้นทาง คืออยากทราบว่าเราสามารถแทรก code เข้าไปเพื่อให้ส่งขอมูลเส้นทางในส่วนนี้ออกมาได้ไหมครับคือต้องการส่งออกมาเพื่อเก็บเป็น log ข้อมูลน่ะครับ เช่น เรากำหนดจุด a ไป b มีให้เลือกสามเส้นทางคือ เส้นทางที่ 1,2,3 คือต้องการข้อมูลเส้นทางที่1,2,3อะครับเพื่อเอามาเก็บเป็นข้อมูลอ่ะครับต้องแทรก code เข้าไปตรงไหน ถึงจะได้ข้อมูลดังกล่าวอ่ะครับ ช่วยหน่อยน่ะครับPlz….

  • caramello

    ทำไมเปิดที่หน้าตัวอย่าง ใน ie มันมีerror ด้วยอะครับ