2012年7月19日 星期四

小試牛刀:利用Google Map API 查地點經緯度

闊別接近兩年以上才重返IT界,即使工作已一星期以上還是渾渾乎心驚膽跳。因為上司待吾不薄,加上自己要求高,所以對於寫出來的網站總要十全十美。偏偏兩年的空窗期在IT界很要命,PHP已經換成第六代,Google API有新版本……自己本來會的技術都落伍,只好拼命買參考書狂吃下肚子自我增值。

最近應公司要求將Google Map置入網站中,其中的要求很簡單,就是讓用家輸入地址,然後直接顯示Google Map地圖定位。說起來很簡單,但後續問題不少。比方說為方便將來改寫為Mobile版,不能用iframe tag打混;需要輸入資料庫,所以要求經緯度……

花了一天時間在Google Map API的教學頁翻來閱去,終於成功解決BOSS要求,滿足感十分高。當然就功能及介面上十分陽春,但這些都是「外掛」,之後再慢慢加上去,大家都懂的吧。
無師自通的第一步,貴在於「抄」,直接用Google教學文件的範例參考後略作修改,取得基礎源碼。



<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> 
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false">
</script>
<script type="text/javascript">
 function initialize() {
    var myOptions = {
      zoom: 9,
      center: new google.maps.LatLng(-34.397, 150.644),
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      scaleControl: true
    }
    var map = new google.maps.Map($('#map_canvas').get(0), myOptions);
 }
window.onload = initialize;
</script>
</head>
<body>
 <div><p>Address:<input id="map_address" size="20" type="text" /><input id="map_set" type="submit" value="Show" /></p></div>
 <div id="map_canvas" style="width:600px; height:500px"></div>
</body>
</html>

以上源碼九成來自Google教學文件,改動的地方不多,特別要註明的是將中的onload事件取消,改為於<script>中以window.onload宣告,都是方便後續的工作安排。

思維邏輯,用家輸入地址,不需更新頁面,地圖會自動標記出來。如果不符,則再進行搜索。其中會利用API中的geocoder求取坐標(即lat及lng兩組參數),再以jQuery將value輸出至input上。這碰既是給用家作二重確認,亦是便利之後將數值傳送至MySQL。

<script type="text/javascript">
  var geocoder;
  var map;
 
  function initialize() {
    geocoder = new google.maps.Geocoder();
    var latlng = new google.maps.LatLng(0,0);
    var myOptions = {
      zoom: 13,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      scaleControl: true
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  }

  function codeAddress() {
 $("#lat").val("")
 $("#lng").val("")
    var address = document.getElementById("address").value;
    geocoder.geocode( {'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
  var lat=results[0].geometry.location.lat()
  var lat1 = lat
  $("#lat").val(lat1)
  var lng=results[0].geometry.location.lng()
  var lng1 = lng
  $("#lng").val(lng1)
        map.setCenter(results[0].geometry.location);
        var marker = new google.maps.Marker({
            map: map,
            position: results[0].geometry.location
        });
      } else {
        alert("Geocode was not successful for the following reason: " + status);
      }
    });
  }
 
  window.onload = initialize;
</script>
依Google說明,lat及lng輸入MySQL的型態是FLOAT( 10, 6 ) NOT NULL(原文:根據「Google 地圖」目前的縮放功能,小數點後應該只需要 6 位數的精準度。如果要讓我們的表格儲存空間保持在最小的限度,您可以指定 lat 和 lng 屬性的大小為 (10,6) 的浮點值。)取值雖然是小數點後很多位,輸入資料庫後會裁為小數點後六位,實際運作時從MySQL取值再定位,並無發生問題,可以依樣葫蘆。

對於比較簡單的頁面直接將MySQL的值以echo輸出至jQuery即可,但為了方便維護及日後的更新,需要變得聰明點,PHP將MySQL的值輸出至input的value,然後讓jQuery懂得抓input的value再投給Google定位輸出至地圖上。(所以wondow.onload如此重要,一定要全頁輸出,PHP執行完畢再取值)這樣子每次下載頁面只需要執行一次MySQL查詢,省時便利。
  var geocoder;
  var map;
  var marker;

  function initialize() {
 var lat0 = $("#lat").attr("value");
 var lng0 = $("#lng").attr("value");
    geocoder = new google.maps.Geocoder();
    var latlng = new google.maps.LatLng(lat0,lng0);
    var myOptions = {
      zoom: 13,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      scaleControl: true
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    var marker = new google.maps.Marker({
 position: new google.maps.LatLng(lat0,lng0),
 map: map
 })
  }
其實大致上完成,不過還有些不完全的地方。因為這個地圖定位是搭配MySQL資料庫,新增地點將座標輸入後可以讀出觀看或修改。此時我希望Edit Function抓取資料後會標記出地點,更改地址後亦會清除舊有的標記,重定向新的地點。根據Google Map API教學,再次加添幾句,便算完工。留個紀錄,方便自己也方便別人。


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript"
    src="https://maps.google.com/maps/api/js?sensor=false">
</script>
<script type="text/javascript">
  //宣告變數
  var geocoder;
  var map;
  var marker;

  function initialize() {
//從input欄位中抽取value
var lat0 = $("#lat").attr("value");
var lng0 = $("#lng").attr("value");
    geocoder = new google.maps.Geocoder();
    //利用變數自定義地圖中心點
    var latlng = new google.maps.LatLng(lat0,lng0);
    var myOptions = {
      zoom: 13,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      scaleControl: true
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(lat0,lng0)
})

  }

  function codeAddress() {
//清除地圖標記
if (marker) marker.setMap(null)
//清除input的value
$("#lat").val("")
$("#lng").val("")
//提取用戶填入的地址
    var address = document.getElementById("address").value;
    //以geocoder向Google Map提交查詢
    geocoder.geocode( {'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
//將geocoder回傳的資料中抽出座標的值,再填入input的欄位中
var lat = results[0].geometry.location.lat()
var lat1 = lat
$("#lat").val(lat1)
var lng = results[0].geometry.location.lng()
var lng1 = lng
$("#lng").val(lng1)
//重新輸出地圖資料
        map.setCenter(results[0].geometry.location);
        marker = new google.maps.Marker({
            map: map,
            position: results[0].geometry.location
        });
      } else {
//如果找不到地點時回傳的訊息
        alert("Geocode was not successful for the following reason: " + status);
      }
    });
  }

  //指定網頁中所有元素完全加載後執行
  window.onload = initialize;
</script>
</head>
<body>
  <div>
    <input id="address" type="textbox" value="66 Nathan Road">
    <input type="button" value="Geocode" onclick="codeAddress()">
    <input id="lat" /><input id="lng" />
  </div>
  <div id="map_canvas" style="width:600px; height:500px"></div>
</body>
</html>
實際結果如何?自己丟上Server試試。至於PHP的部份,大家自行解決吧,反正都是簡單的SQL指令。

範例完成品:

2 則留言:

  1. 請教一下
    如果我從mysql導入很多的點
    那麼在center這邊,他如何幫我自動計算中心點??

    回覆刪除
    回覆
    1. 這個暫時未有研究,因為目前本人只需要單點定位
      其實我都是在Google教學文件中慢慢學習的,可能那邊會有答案

      刪除