2013年3月20日 星期三

【Google Maps】(二)資訊視窗infowindow與MarkerClusterer

若還未有初始化定位地圖與增加標記點的觀念,請先查看:【Google Maps】(一) 初始化地圖與透過地址轉換經緯度重新定位地圖位置

本篇文章要介紹的是如何在Google Maps各個標記點Marker建立資訊視窗infowindow,並且透過MarkerClusterer群聚多個標記點Marker。

預先看線上demo請點我

網路上查地圖位置資料,有時候可以看到某些地圖在搜尋結果的標記點Marker滑鼠點擊後,地圖上方會出現一個像對話泡泡框的區塊,在Google Maps中稱為資訊視窗,也就是infowindow,infowindow的主要使用方式如下:
 
   var infowindow = new google.maps.InfoWindow();  
   infowindow.setContent("設定資訊視窗內容");
   infowindow.open(mapObj,markerObj);

setContent 用來設定開啟的資訊視窗infowindow的內容。
open
  • 參數1:要顯示資訊視窗的map物件。
  • 參數2:開啟的資訊視窗所附加、關連的標記點Marker物件。
詳細infowindow介紹請點我,其他infowindow使用方式reference請點我




MarkerClusterer第一次知道是在客戶丟出需求範例時,我自己是將它解讀做:

在大範圍地圖中,群聚多個標記點Marker成為另ㄧ種形式的標記點(目前知道的形式長的像雷達圖),並且在新標記點中顯示包含的標記點個數。

如果需要查看更準確的說明,請看官網v1 reference中的How it works區塊請看文章最後補充更新。

MarkerClusterer主要使用方式如下:
 
var markerCluster = new MarkerClusterer(map, marker);

map 要建立MarkerClusterer的map物件。
marker 要被MarkerClusterer重新群聚成另ㄧ種標記點形式的標記點Marker物件。
官網使用範例請點我。其他MarkerClusterer使用方式reference請點我

關於demo範例:
  • 輸入框為欲查詢的地址資料清單。
  • 輸入框下方會依序呈現輸入框內的地址資料,並且點擊後右側地圖該地址定位點會出現資訊視窗infowindow。
  • 右側地圖預設為大範圍顯示,先以MarkerClusterer的雷達圖標記點顯示此大範圍中的標記點個數,點擊雷達圖標記點地圖會放大,若是點擊的是原本預設的標記點則會出現資訊視窗infowindow。
  • 可修改輸入框內的地址資料再按下「重新設定查詢資料」按鈕即可重置地址資料與地圖資料。

Html部分:
 
  
請輸入地址等資料,並且請以半形逗號「,」區隔每筆資料。

  • 下方為欲查詢的地址資料,若重新編輯上方的地址資料後可按下「重新設定查詢資料」按鈕後,可更新下方資料與右側地圖。
  • 下方資料與右側地圖中的圖示皆可點擊。

CSS部分:
 
  html { height: 100% }
  body { height: 100%; margin: 0px; padding: 0px }
  #map_canvas { height: 100% }

JS部分:
首先,先載入必要的檔案:
 




markerclusterer.js 取自http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/src/markerclusterer.js,必須載入此js才可使用MarkerClusterer。



接著,本次demo詳細JS部分:
 
  var map;
  var MarkAry = [];    //要查詢的位址資料陣列
  var marker = [];     //要查詢的位址資料陣列,對應的標記Marker資訊
  var infowindow = new google.maps.InfoWindow();  
  var geocoder = new google.maps.Geocoder();
   
$(document).ready(function() { 
    SetData(initialize);//初次載入頁面讀取預設地址資料供地圖使用
 
    $("#reSetData").click(function(){
        SetData(initialize);//重新依據textarea內地址資料供地圖使用
    });
});
  
function initialize(MarkAry) 
{
   //console.log(MarkAry);
   marker = [];//重設欲查詢的地址資料時需確認marker為空
 
   var latlng = new google.maps.LatLng(23.973875,120.982024); //台灣緯度Latitude、經度Longitude:23.973875,120.982024
   var mapOptions = {
     zoom: 5,
     center: latlng,
     mapTypeId: google.maps.MapTypeId.ROADMAP
   };
 
   map = new google.maps.Map(document.getElementById("map_canvas"),mapOptions);
 
   //顯示MarkAry中地點標記 
   var DataHtml = "
    "; for ( var index in MarkAry ) { //設定各查詢位址的標記Marker marker[index] = new google.maps.Marker({ position: new google.maps.LatLng(MarkAry[index][1],MarkAry[index][2]), title:MarkAry[index][0], map:map //要顯示標記的地圖 }); //設定 各標記點Marker的click事件 google.maps.event.addListener(marker[index], 'click', function() { ShowInfo(map , this); }); //設定 左方資料列表與其資料列click事件 onclickJs = "ShowInfo(map , marker[" + index + "] )"; DataHtml += "
  • " + MarkAry[index][0] + "
  • "; } //設定當user縮放地圖時,若存在資訊視窗則關閉資訊視窗 google.maps.event.addListener(map, 'zoom_changed', function() { if (infowindow){ infowindow.close(); } }); DataHtml += "
"; $("#DataList").html(DataHtml); var markerCluster = new MarkerClusterer(map, marker); } function SetData(callback) { MarkAry = [];//重設欲查詢的地址資料時需確認MarkAry為空 var strData = ($.trim($("#searchData").val())).replace("\n",""); var aryData = strData.split(","); var lengthData = aryData.length; //地址個數 var i = 0; $.each(aryData,function(key,value){//console.log(key);console.log(value); geocoder.geocode( { 'address':value },function (results,status) { i++; if(status==google.maps.GeocoderStatus.OK) { var obj = results[0].geometry.location; var thisData = [value,obj.lat(),obj.lng()]; //MarkAry.push(thisData); //直接使用push似乎會由於非同步回傳結果時間的不同,導致順序與地址輸入框內不同 MarkAry[key] = thisData; //將push方式改為直接設定陣列的index再去塞值,如此MarkAry的順序跟地址輸入框內才相同 } if ( i==lengthData ){ callback(MarkAry); } } ); }); } function ShowInfo(mapObj , markerObj) {//開啟資訊視窗 if (infowindow){ infowindow.close();} infowindow.setContent(InfoContent(markerObj)); infowindow.open(mapObj,markerObj); } function InfoContent(markerObj) {//設定資訊視窗內容要呈現什麼 html = "
縣市:" + markerObj.title + "
"; html += "
緯度:" + markerObj.getPosition().lat() + "
"; html += "
經度:" + markerObj.getPosition().lng() + "
"; return html; }

【2017/9/16更新】


如果您喜歡我的分享、或是我的文章對您有幫助的話,希望能到我的粉絲專頁點個讚追蹤我唷~~

寫程式、技術分享文章很辛苦,寫一篇要花非常久的時間,希望您能幫我點一下頁面上的廣告給我支持跟肯定,讓我更有動力寫這類文章唷~

4 則留言:

  1. 你的解說真是很棒的資訊與知識,可是網誌配色紅色看得眼睛好不舒服QQ不過還是很感謝您的分享!

    回覆刪除
    回覆
    1. 謝謝你的留言:)

      顏色...我會找時間調整看看>"<

      刪除
  2. 你的文章很棒:)
    但我想嘗試更換cluster的圖檔
    但怎麼試都無法更換 想請教您是否有嘗試過

    回覆刪除
    回覆
    1. Hi~您好,謝謝你喜歡我的文章~
      我爬了一下官方文件,目前測出可成功更換cluster圖檔程式碼如下:

      //變更Cluster icon圖
      var styles=markerCluster.getStyles();
      //console.log(markerCluster.getStyles());
      $(styles).each(function(){
      var obj =($(this))[0];
      obj.url = "m2.png";//直接設定要替換的圖檔url位置
      });

      上述方式源自v1文件:http://goo.gl/CkptP
      文件中顯示style須為陣列,國外的範例也是依序設定陣列中的url為解決方式,原本我不太了解,為何是陣列,但我發現v3 (http://goo.gl/bV6Ur)當中getStyles方法,執行後的陣列數量,似乎好像是Cluster的數量!?
      (我不是很確定 推測..)
      所以最後是以上述這段程式碼來完成這個需求。

      P.S 最一開始,我以為而且我希望是會有一個方法或屬性可以直接設定將所有的icon換掉,但查了我文中附的兩個版本文件似乎沒有 (v3中的setStyles方法我想原理跟上述是一樣的),後來在這個地方:http://goo.gl/BNir6 看到他直接有一個url properties可以設定!!

      不過,因為他是 「MarkerClustererPlus」 for Google Maps V3,多了個Plus,似乎有點不太一樣,我沒仔細去研究是否可以跟原本的「MarkerClusterer」搭配使用,如果需要您可以研究看看囉~ ^_^

      刪除

writing for work~writing for life~