แสดงหมุดจาก database ใน Google Maps ด้วย AJAX
ความเดิมจากตอนที่แล้ว เราพูดถึงวิธีิการแสดงหมุดจาก database บนแผนที่ Google Maps ไปแล้ว แต่ติดตรงที่ว่าเวลามีหมุดเยอะๆจะแสดงหน้าเวปช้า และเปลือง memory คราวนี้ผมจะพูดถึงการใช้วิธีการแสดงหมุดจาก database เฉพาะส่วนที่มองเห็นในหน้าต่างแผนที่โดยการใช้ AJAX ครับ
ส่วน table database และ ข้อมูลใน database ก็ใช้ของคราวที่แล้วครับ (ดูได้ที่ Tutorial แบบบ้านๆ ตอนที่ 2 – แสดงหมุดจาก database ใน Google Maps)
สิ่งที่ต้องเตรียมก่อนเริ่ม
- ผมใช้ Prototype Javascript Framework สำหรับทำ AJAX เพราะมันติดมากับ Rails เลยชินครับ ถ้าใครถนัดตัวอื่นก็ตามสะดวก
- แนะนำ Firefox + Firebug สำหรับการ Debug ครับ สุดยอดมากๆ
หลักกาำรทำงาน
- ทุกครั้งที่มีกา่รเลื่อนแผนที่ หรือซูมเข้า/ซูมออก script จะขอข้อมูลจาก server และนำไปแสดงจุดพิกัดใหม่ในแผนที่
- ใช้พิกัดของแผนที่ ที่กำลังแสดงผล (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;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; lng &amp;amp;&amp;amp; lat != 0 &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 เพิ่มขอข้อมูลพิกัดทุกครั้งที่มีการเลื่อนแผนที่