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

แสดงหมุดจาก database ใน Google Maps ด้วย AJAX

21 Dec 2008

ความเดิมจากตอนที่แล้ว เราพูดถึงวิธีิการแสดงหมุดจาก database บนแผนที่ Google Maps ไปแล้ว แต่ติดตรงที่ว่าเวลามีหมุดเยอะๆจะแสดงหน้าเวปช้า และเปลือง memory คราวนี้ผมจะพูดถึงการใช้วิธีการแสดงหมุดจาก database เฉพาะส่วนที่มองเห็นในหน้าต่างแผนที่โดยการใช้ AJAX ครับ

ส่วน table database และ ข้อมูลใน database ก็ใช้ของคราวที่แล้วครับ (ดูได้ที่ Tutorial แบบบ้านๆ ตอนที่ 2 – แสดงหมุดจาก database ใน Google Maps)

สิ่งที่ต้องเตรียมก่อนเริ่ม

  1. ผมใช้ Prototype Javascript Framework สำหรับทำ AJAX เพราะมันติดมากับ Rails เลยชินครับ ถ้าใครถนัดตัวอื่นก็ตามสะดวก
  2. แนะนำ Firefox + Firebug สำหรับการ Debug ครับ สุดยอดมากๆ

หลักกาำรทำงาน

  1. ทุกครั้งที่มีกา่รเลื่อนแผนที่ หรือซูมเข้า/ซูมออก script จะขอข้อมูลจาก server และนำไปแสดงจุดพิกัดใหม่ในแผนที่
  2. ใช้พิกัดของแผนที่ ที่กำลังแสดงผล (x1,y1,x2,y2 ตรงมุมกรอบของแผนที่) เป็นตัวแปลในการเลือกข้อมูลพิกัดจาก database

อ้อ วิธีการที่จะเขียนถึง ส่วนใหญ่นำมาจากหนังสือ “Beginning Google Maps Applications with Rails and Ajax” นะครับ ลองไปหาอ่านดูกัน แนะนำๆ

ส่วนที่ 1 เรียกใช้ prototype.js โดยการเพิ่มบรรทัดต่อไปนี้ ในส่วน head

<script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js" type="text/javascript"></script>

ส่วนที่ 2 แก้ไขส่วน Javascript โดยเพิ่ม function สำหรับแสดงหมุด และ แก้ไข function load() ดังนี้ครับ

var displayingMarkers = [];
var displayingMarkersNum = 0;
var deletingMarkers = [];
var deletingMarkersNum = 0;

function clearMarkers() {

for (var i = 0 ; i < deletingMarkersNum ; i++) {
map.removeOverlay(deletingMarkers[i]);
}

}

function updateMarkers() {
//เตรียม parameters พิกัดของแผนที่ที่กำลังแสดง เพื่อ query หมุดจาก database
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var mapBoundary = 'ne=' + northEast.toUrlValue() + '&amp;amp;amp;sw=' + southWest.toUrlValue();
var myAjax = new Ajax.Request( '/get_marker', {
method: 'get',
parameters: mapBoundary,
onComplete: function(request){
// function นี้จะทำงานหลังจากได้รับค่า response จาก server
// ทำการเก็บค่า response จาก server เข้าตัวแปล markers
markers = eval( "(" + request.responseText + ")" );

// copy markers ที่กำลังแสดงอยู่เก็บไว้ เดี๋ยวเราจะลบหมุดพวกนี้ออก หลังจากเพิ่มหมุดชุดใหม่ในแผนที่แล้ว
deletingMarkers = displayingMarkers.clone();
deletingMarkersNum = displayingMarkersNum;
displayingMarkersNum = 0;
displayingMarkers.clear();

for (var i = 0 ; i < markers.length ; i++) {
var marker = markers[i]
var lat = marker.lat;
var lng = marker.lng;

//check for lat and lng so MSIE does not error on parseFloat of a null value
if (lat &amp;amp;amp;&amp;amp;amp; lng &amp;amp;amp;&amp;amp;amp; lat != 0 &amp;amp;amp;&amp;amp;amp; lng != 0) {
var latlng = new GLatLng(lat,lng)

var marker = new GMarker(latlng);

displayingMarkers[displayingMarkersNum] = marker;
displayingMarkersNum++;

map.addOverlay(marker);

} // end of if lat and lng
} // end of for loop

clearMarkers();

} // end of anonymous onComplete function

}); // end of the new Ajax.Request() call

}

function load() {
if (GBrowserIsCompatible()) {
displayingLandmarkNum = 0;
displayingLandmark.clear();
deletingLandmarkNum = 0;
deletingLandmark.clear();

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

updateMarkers();
GEvent.addListener(map,'zoomend',function() {
updateMarkers();
});

GEvent.addListener(map,'moveend',function() {
updateMarkers();
});
}
}

ส่วนที่ 3 เพิ่ม action ฝั่ง server ให้รับ AJAX request และ return ค่าพิกัด

def get_marker
ne = params[:ne].split(',').collect{|e|e.to_f}
sw = params[:sw].split(',').collect{|e|e.to_f}

# if the NE longitude is less than the SW longitude,
# it means we are split over the meridian.

if ne[1] > sw[1]
conditions = '((lng > ? AND lng < ?) AND (lat <= ? AND lat >= ?))'
else
conditions = '((lng >= ? OR lng < ?) AND (lat <= ? AND lat >= ?))'
end
markers = Marker.find :all, :select => 'id, lat, lng', :conditions => [conditions,sw[1],ne[1],ne[0],sw[0]]

render :text=>markers.collect{|c|c.attributes}.to_json
end

TIPS:

ลองสังเกตุหน้าต่าง console ของ Firebug เวลาเลื่อนแผนที่ดูครับ จะเห็นการสื่อสารระหว่าง browser กับ server เพิ่มขอข้อมูลพิกัดทุกครั้งที่มีการเลื่อนแผนที่

  • Pingback: Tutorial แบบบ้านๆ ตอนที่ 1 - Basic Google Maps API — tanomsak.com

  • นัด

    ชอบมากคับ รอติดตามส่วนอื่นๆ อยู่คับ

  • ab

    ไม่มี ตัว อย่าง หรือ ครับ

  • tanomsak

    ยังไม่ได้ทำตัวอย่างเฉพาะสำหรับเรื่องนี้น่ะครับ ลองดูตัวอย่างที่ใช้งานจริงที่ http://www.ddproperty.com/ นะครับ สังเกตุพวก สถานที่ต่างๆในแผนที่

    ตอนนี้กำลังหาเวลาเขียนตอนต่อไปอยู่ครับ ยุ่งอยู่กับเรื่องอื่นเลย ดองเรื่อง google maps ยาวเลย

  • kukuri

    คือว่า หาข้อมูลเกี่ยวกับพวกนี้แล้วมาเจออ่ะคะ แล้วอยากทราบเกี่ยวกับว่า ถ้า หาก เราดึงพิกัดจาก database มาแสดงบน แผนที่ และก็ทำเป็นpolygon อ่ะคะ แบบว่า พิกัด ของมุมที่ดินหนึ่งผืน และแต่ละผืนอาจจะมี สี่มุม ห้ามุม หรือ หกมุม อะไรพวกนั้นอ่ะคะ จะส่งค่ายังไงอ่ะคะ

  • lab

    รอหัวข้อต่อๆ ไปอยู่คับ
    ติดตามมาพอสมควรแล้ว จะอับเดทมะไหร่คับ T_T

  • Khan

    คืออยากดูว่ามีไฟล์ไหนมั้งอ่าคะ

    เพราะไม่รู้จะเอาไปแปะตรงไหน

    ใครรู้ช่วยทีคะ ไม่ค่อยรู้เรื่องคอมคะ

  • http://www.ideezign.com dynaz

    สุดยอด จิง ๆ คับ…

  • อุดมพงษ์ ค้าของ

    เค้าว่ากันนะ…การปักหมุดบน Google เกิน “หนึ่งพันจุด” จะทำให้มีการแสดงผลออกมาหน้าเว็บช้ามากจิงรึป่าวคับท่านผู้ชม ช่วยตอบด้วยคับ เห็นเค้าว่าเกินพันจุด Google ทำให้ช้าเพื่อเก็บตังจิงป่าวครับพี่น้อง???

  • tanomsak

    ผมว่าจริงครับ ไม่ต้องถึงพันจุดหรอกครับ เป็นร้อยก็ช้าแล้วครับ browser จะกิน RAM อย่างดุเดือดเลย :) ไม่คงไม่ใช่เพราะ Google จะเก็บตังหรอกครับ

  • อุดมพงษ์ ค้าของ

    ถ้าไม่ยากเจอปัญหาการช้า หรือ กินแรม มีวิธีแนะนำมํยคับ ว่าจะใช้วิธีไหนในการพร๊อตจุดครั้งละเป็นพันจุด รบกวนพี่น้องที่รู้ช่วยตอบหน่อยนะคับ ไม่รู้จะทำยังไงปวดหมองมากเลย

  • tanomsak

    คงทำทำแบบ Ajax ครับ คือเอามาแสดงเฉพาำะส่วนที่เรามองเห็นในแผนที่ แล้วก็ เรียกจุึดใหม่ๆมาแสดงเวลาขยับแผนที่ครับ

  • อุดมพงษ์ ค้าของ

    ขอบคุณครับท่าน(tanomsak) ขอให้เจริญในหน้าที่และการงานครับ

  • blossom

    อ่านแล้วมึนๆ ดีจังค่ะ มีแบบเป็น php มั้ยคะ

  • nuijang

    ขอบคุณมากครับที่เขียนบทความดีๆ มาให้อ่าน มีประโยชน์มากครับ

  • Smapa N

    อยากให้ลองเสนอราคาดูหน่อยครับ
    สวัสดีครับ
    อยากให้ลองเสนอราคาดูหน่อยครับ

    ตามรายละเอียดนี้ครับ
    http://www.thaiseoboard.com/index.php/topic,129…

    โดยหน้าค้นหาทางซ้ายขอปรับให้ look&feel คล้ายๆกับ
    http://www.allapartment.in.th/%E0%B8%AD%E0%B8%9…

    เวลากดแล้วอัพเดตได้ทันทีครับ แค่การนำเสนอให้ออกมาที่แผนที่แทนครับ

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

    ผมมี script ที่ใช้งานได้แล้วระดับนึงครับ คือคนเก่าเค้าเขียนไว้ครับ + เอา script มาโม คือ
    http://map.apartment.in.th/map.php

    ที่ยังขาดคือ เอาข้อมูลมาแสดงครับ ถ้าต้องการเข้าไปดู code ก็ยินดีนะครับ

    ขอให้เสนอราคามาครับ และขอชื่อ ติดต่อด้วยนะครับ

    ขอบคุณครับ

    นพ 083-757-1515

  • tanomsak

    สวัสดีครับคุณนพ ยินดีที่รู้จักครับ

    ขอบคุณที่สนใจอยากให้ผมทำงานนะครับ แต่ปกติผมไม่ได้รับงานพัฒนาเวปน่ะครับ

    เอาเป็นยินดีให้คำปรึกษาฟรีตามความสามารถของผมดีกว่าครับ

  • Ba_nana55

    ขอบคุณมากเลยคะสำหรับความรู้ดี

    ว่าแต่ยังงงตรง ส่วนที่ 3 ของฝั่ง server เอ่อ… ไม่ถนัดภาษาที่คุณเขียนด้วยซี

    ถ้าช่วยอธิบายเพิ่ม จะขอบคุณมากเลยค่ะ ^____^

  • tanomsak

    ส่วนที่ 3 เป็นการ query ค่า จาก database โดยเอาค่า lat, lng ที่ส่งมาจาก client มาสร้าง เงื่อนไขการ query ครับ

    โดย lat lng ที่ได้มาจะเป็นจุด 2 จุด คือ มุมบนขวา และ ล่างซ้ายของแผนที่ ครับ ตัวอย่าง parameters จาก client เป็นประมาณนี้ครับ

    ?ne=13.886578,100.596485&sw=13.819578,100.437183&zoomlevel=13

    ทีนี้ที่ต้องทำทาง server ก็คือ เอา lat, lng ที่ได้มา มา query หาจุดในกล่อง 4 เหลี่ยมที่ว่า และส่งกลับไปยัง client ครับ

  • Pakazz

    ขอสอบถามนิดนึงครับ พอดีไม่รู้จะติดต่อจากช่องทางไหน

    ไม่ทราบว่า google map มีความสามารถในการแสดงค่าพิกัด LatLng เหมือน google earth ไหมครับ
    แบบเวลา เม้าส์ เลื่อนไปทางไหนก้อจะบอกพิกัด ณ ตำแหน่งนั้นๆๆอะครับ

  • tanomsak

    มีครับ ต้องไปเปิดใช้งานตรงก่อนเป็น function ใน Lab ครับ จะเห็นขวดน้ำยาสีเขียวๆ และก็คำว่า New ตรงขวามือบนครับ

    กดเข้าไปแล้วหา ชื่อว่า LatLng Tooltip ครับ

  • Ba_nana55

    ขอบคุณค่ะ

    ขอรบกวนอีกรอบค่ะ

    อยากทราบว่าฝั่ง ๆ server รีเทิร์นค่ามาทางฝั่ง client ในรุปแบบไหนค่ะ เปน อาร์เรย์ หรือว่าเปนแพตเทิร์นไหนอ่ะค่ะ

    ขอบคุณค่ะ

  • tanomsak

    ที่ผมทำผม return มาเป็นรูปแบบ Array ครับ โดยเป็น Array ของ JSON text แบบนี้ครับ

    [{"lng": 100.491566, "lat": 13.733916},{"lng": 100.591566, "lat": 14.733916},{"lng": 100.42566, "lat": 13.833916},]

    พอเรา markers = eval( “(” + request.responseText + “)” );

    ก็จะได้ object ที่เป็น Array ออกมาและเข้าถึง lat, lng ของแต่ละจุดได้ด้วย dot แบบนี้ครับ

    markers[0].lat จะได้ค่า ==> 13.733916
    markers[0].lng จะได้ค่า ==> 100.491566

  • Ba_nana55

    ขอบคุณมากๆเรยค่ะ ^___^

  • Airzio

    พี่มีเมลป่ะครับรบกวนขอหน่อยครับอยากปรึกษาตอนนี้ติดขัดมากทำต่อไม่ได้เลย คือผมได้code คิวรี่จุดจาก database แต่ มันอยู่คนละไฟล์กันมี2ไฟล์อ่ะครับ ผมอยากให้มันคิวรี่ตามเงื่อนไข อ่ะครับ ติดขัดมาก Y_Y เมลล์ผมนะครับถ้าเกิดไม่สดวกแอดมา airzio@hotmail.com

  • tanomsak

    มีคำถามว่าไงครับ ถามมาได้เลยครับ หรือว่าจะส่งมาที่หน้า http://www.tanomsak.com/index.php/contact ก็ได้ครับ

  • Chaluempon

    อยากได้ตัวอย่างที่เป็น Google API V.3 โดยใช้ php+ajax หน่อยครับ ^_^ ขอบคุณครับผม