wiki:oid/WorkLog/08-09-22

2008-09-22

學習如何匯入 KML

  • 根據Google Map API 官方部落格的範例,要將 KML 加入 Google Map 圖層只要簡單的兩行,因此我們把國榮提供的 KML 檔案全部 Load 到圖層上,請看第四個成果
    var gx = new GGeoXml("http://trac.nchc.org.tw/OR1-0866.kml");
    map.addOverlay(gx);
    
    • .html

      old new  
      1616       map.addControl(new GLargeMapControl());               // 加入左上角比例尺規控制列
      1717       map.addControl(new GScaleControl());                  // 加入左下角比例尺狀態列
      1818       map.addControl(new GMapTypeControl());                // 加入右上角"地圖","衛星","混合地圖"按鈕
      19        map.setCenter(new GLatLng(23.8,121), 7);              // 設定預設經緯度北緯 23.8, 東經 121, 預設比例尺 100 公里(7)
       19       map.setCenter(new GLatLng(23.8,121), 6);              // 設定預設經緯度北緯 23.8, 東經 121, 預設比例尺 200 公里(6)
      2020       map.setMapType(G_SATELLITE_MAP);                      // 設定預設底圖為"衛星"
      2121      }
      2222      var request = GXmlHttp.create();                        // 產生一個非同步的 AJAX XMLHttp 物件
       
      4141       }
      4242      }
      4343      request.send(null);                                      // 送出 XMLHttp 物件的要求
       44
       45      // 產生 GGeoXml 物件來讀取 KML 檔案並貼上 Google Map 圖層
       46      // - 參考 http://googlemapsapi.blogspot.com/2007/03/kml-and-georss-support-added-to-google.html
       47      // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GGeoXml
       48      // - GGeoXml(urlOfXml) 必須輸入標準網址,不能輸入相對位址
       49      var gx = new GGeoXml("http://trac.nchc.org.tw/OR1-0866.kml");
       50      map.addOverlay(gx);
       51      gx = new GGeoXml("http://trac.nchc.org.tw/OR1-0868.kml");
       52      map.addOverlay(gx);
       53      gx = new GGeoXml("http://trac.nchc.org.tw/OR2-1547.kml");
       54      map.addOverlay(gx);
       55      gx = new GGeoXml("http://trac.nchc.org.tw/OR3-1297.kml");
       56      map.addOverlay(gx);
      4457    }
      4558    //]]>
      4659    </script>

學習自訂按鈕

  • Q: Google Map 如何使用自己定義的按鈕??
  • 解析 custom control 原始碼
  • 從這一個範例,我們可以學習到 JavaScript 的多型繼承該怎麼作!!
        // 首先宣告一個函數 TextualZoomControl() 這個應該就是類別的建構子(Constructor)
        function TextualZoomControl() {
        }
        // 宣告 TextualZoomControl 的原型(prototype) 是 GControl (型態是 Interface)
        TextualZoomControl.prototype = new GControl();
    
        // 重新實作 GControl 的 initialize(map) 回傳 Node (型態為 DOM 的 DIV 元件)
        TextualZoomControl.prototype.initialize = function(map) {
          // 產生最上層的 DIV
          var container = document.createElement("div");
          // 產生第二層的 DIV (按鈕 Zoom In)
          var zoomInDiv = document.createElement("div");
          // 設定 zoomInDiv 為自訂的格式
          this.setButtonStyle_(zoomInDiv);
          // 把 zoomInDiv 加進 container
          container.appendChild(zoomInDiv);
          // 在 zoomInDiv 裡面寫文字 "Zoom In"
          zoomInDiv.appendChild(document.createTextNode("Zoom In"));
          // 替 zoomInDiv 註冊 onclick 事件處理等於 map.zoomIn()
          GEvent.addDomListener(zoomInDiv, "click", function() {
            map.zoomIn();
          });
          // 產生第二層的 DIV (按鈕 Zoom Out)
          var zoomOutDiv = document.createElement("div");
          // 設定 zoomInDiv 為自訂的格式
          this.setButtonStyle_(zoomOutDiv);
          // 把 zoomInDiv 加進 container
          container.appendChild(zoomOutDiv);
          // 在 zoomInDiv 裡面寫文字 "Zoom In"
          zoomOutDiv.appendChild(document.createTextNode("Zoom Out"));
          // 替 zoomInDiv 註冊 onclick 事件處理等於 map.zoomIn()
          GEvent.addDomListener(zoomOutDiv, "click", function() {
            map.zoomOut();
          });
          // 把 container 加進 google map 預設的 container (DIV) 裡面
          map.getContainer().appendChild(container);
          return container;
        }
    
        // 重新實作 GControl 的 getDefaultPosition() 回傳 GControlPosition 型態的變數
        TextualZoomControl.prototype.getDefaultPosition = function() {
          return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7));
        }
    
        // 自訂函數 setButtonStyle_(button)
        TextualZoomControl.prototype.setButtonStyle_ = function(button) {
          button.style.textDecoration = "underline";
          button.style.color = "#0000cc";
          button.style.backgroundColor = "white";
          button.style.font = "small Arial";
          button.style.border = "1px solid black";
          button.style.padding = "2px";
          button.style.marginBottom = "3px";
          button.style.textAlign = "center";
          button.style.width = "6em";
          button.style.cursor = "pointer";
        }
    
        // 這個是 onload 時載入 google map 的處理函式
        function initialize() {
          if (GBrowserIsCompatible()) {
            var map = new GMap2(document.getElementById("map_canvas"));
            map.setCenter(new GLatLng(37.441944, -122.141944), 13);
            // 把自訂的按鈕 TextualZoomControl 加到左上角
            map.addControl(new TextualZoomControl());
          }
        }
    
  • 從上述範例程式碼可以學習到如何使用 !Javascript 產生 DOM 並定義對應的 Google Map 行為。
    • [感想] 我想應該也可以自己先寫好 DIV 並定義行為函數,應該也可以產生一樣的效果。

學習自訂背景圖層

  • Q: Google Map 如何使用自己定義的背景圖層??
  • 解析 Polar Mars Example 原始碼
        <script src="http://alderaan.arc.nasa.gov/maps/nasamaps.js" type="text/javascript"></script>
        // 底下有一些名稱為 NASA_MARS 開頭的變數是定義在 nasamaps.js 中
    
    ..  ..
        if (GBrowserIsCompatible()) {
          // 產生 GMap2 的 Google Map 底圖物件,並宣告 mapTypes 屬性包括六種 GMapType
          // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GMap2
          // GMap2(container, opts?) - container 是 DOM 的 DIV 元件, opts 是型態為 GMapOptions 的物件
          // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GMapOptions
          // GMapOptions 具備 mapTypes 屬性,其型態為 Array of GMapType (GMapType 的陣列)
          // 這裡定義的 NASA_MARS 開頭的變數是定義在 nasamaps.js 中
          map = new GMap2( document.getElementById("map"), {mapTypes:[NASA_MARS_VISIBLE_MAP, NASA_MARS_VISIBLE_MAP_NPOLAR, NASA_MARS_VISIBLE_MAP_SPOLAR, NASA_MARS_ELEVATION_MAP, NASA_MARS_ELEVATION_MAP_NPOLAR, NASA_MARS_ELEVATION_MAP_SPOLAR]});
        
          map.addControl(new GLargeMapControl());               // 加入左上角比例尺規控制列
          // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GHierarchicalMapTypeControl
          // addRelationship(parentType,  childType,  childText?,  isDefault?)
          // - parentType 跟 childType 都是 GMapType 物件
          mtc = new GHierarchicalMapTypeControl();              // 產生自訂階層式控制列
          mtc.addRelationship(NASA_MARS_VISIBLE_MAP,NASA_MARS_VISIBLE_MAP_NPOLAR);     // 把 North Polar 加到 Visible 下
          mtc.addRelationship(NASA_MARS_VISIBLE_MAP,NASA_MARS_VISIBLE_MAP_SPOLAR);     // 把 South Polar 加到 Visible 下
          mtc.addRelationship(NASA_MARS_ELEVATION_MAP,NASA_MARS_ELEVATION_MAP_NPOLAR); // 把 North Polar 加到 Elevation 下
          mtc.addRelationship(NASA_MARS_ELEVATION_MAP,NASA_MARS_ELEVATION_MAP_SPOLAR); // 把 North Polar 加到 Elevation 下
          map.addControl(mtc);                                  // 把自訂階層式控制列加入右上角
          map.setCenter( new GLatLng(0,0), 2 );                 // 定義地圖中心
    
          // 底下這一段很有趣,NASA 刻意要把右下角"使用條款"前的授權加入 NASA/USGS 的字眼
          // 取得第二個 Div (陣列[0]才是第一個, 陣列[1]是第二個) (詳見圖片)
          map.termsDiv_ = map.getContainer().childNodes[1];
          // 產生一個新的 <SPAN> 的 DOM 元件
          map.copyrightSpan_ = document.createElement("span");
          // 把先的 <SPAN> 元件插入到第二個 DIV 的第一個元件前面
          map.termsDiv_.insertBefore(map.copyrightSpan_,map.termsDiv_.firstChild);
          // 自訂的 <SPAN> 內容設定為 NASA/UGGS 跟相關聯結
          map.copyrightSpan_.innerHTML = "<a href=\"http://ti.arc.nasa.gov/projects/planetary/\">NASA/USGS</a> - "; 
        }
    
  • 上面提到處理 DOM 的 JavaScript,可以用 Firefox 的 DOM Inspector 去看,就可以理解在寫什麼了。

  • 繼續解析 nasamaps.js
    ..  ..
    
    function TMSBaseLayer( baseurl, levels ) {
      // 產生一個 GTileLayer 物件
      // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GTileLayer
      // GTileLayer(copyrights,  minResolution,  maxResolution,  options?)
      // - copyrights = 授權字串, minResolution: 最小比例尺數字, maxResolution: 最大比例尺數字
      var layer = new GTileLayer(null, 0, levels);
      // GTileLayer.isPng() 是抽象函數(Abstract), 必須重新定義
    
      // - 原型為 isPng() 回傳 Boolean
      layer.isPng = function() { return false };
      // GTileLayer.getTileUrl 是抽象函數(Abstract), 必須重新定義
      // - 原型為 getTileUrl(tile,  zoom) 回傳 String, 其中 tile 是 GPoint 物件(內含<x,y>座標), zoom 是比例尺的數字
      // 從底下的實作,我們不難發現用 GTileLayer 達成使用自己的背景圖替代 Google Map 預設背景圖的目標
      // ToDo: 接下來就是要找出怎麼產生符合 GTileLayer 不同比例尺的背景圖 jpg 檔案
      layer.getTileUrl = function(tile, zoom) {
        var y = Math.pow(2, zoom)-tile.y-1;
        var url = baseurl + zoom + "/" + tile.x + "/" + y + ".jpg";
        return url;
      };
      // 回傳 GTileLayer 物件
      return layer;
    }
    
    // 產生不同的 GMapType 物件
    // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GMapType
    // GMapType(layers,  projection,  name,  opts?)
    // - layers 型態為 GTileLayer
    // - projection 型態為 GProjection ,這裡的 GMercatorProjection 是 GProjection 的實作(implementation)
    // - name 型態為字串(String) 也就是要顯示在畫面上自訂的按鈕名稱
    var NASA_MOON_VISIBLE_MAP = new GMapType( [TMSBaseLayer("http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/",9)],
    // - 參考 http://code.google.com/apis/maps/documentation/reference.html#GMercatorProjection
    // GMercatorProjection(zoomlevels): 使用 mercator projection 座標系
    // - zoomlevels 型態為數字, 代表有幾種比例尺, 像這裡的比例尺是 0-9 總共 10 種
                new GMercatorProjection(10), "Visible" );
    
  • 繼續解析 nasamaps.js (PART 2)
  • 從這一個範例,我們可以學習到 JavaScript 的多型繼承該怎麼作!!
    // 首先定義自訂投影座標函數 PolarStereographicProjection 有兩個參數 zoomelevels 跟 type
    // 其中 zoomlevels 跟 GMercatorProjection 一樣,代表分幾種比例尺
    function PolarStereographicProjection( zoomlevels, type ) {
      var me = this;
      me.zoomlevels = zoomlevels;
      me.zvector = type;
    }
    
    // 宣告 PolarStereographicProjection 實作 interface GProjection 回傳 GPoint
    PolarStereographicProjection.prototype = new GProjection();
    
    // 重新實作 interface GProjection 的 fromLatLngToPixel(latlng,  zoom)
    PolarStereographicProjection.prototype.fromLatLngToPixel = function(latlng, zoom) {
      var lat = Math.PI/180 * latlng.lat();
      var lon = Math.PI/180 * latlng.lng();
      var s1 = Math.cos(lat)/(1.0 + this.zvector * Math.sin(lat));
      var s2 = 256 / 2 * Math.pow(2,zoom);
      var x = ( Math.sin(lon) * s1 + 1 ) * s2;
      var y = ( this.zvector * Math.cos(lon) * s1 + 1 ) * s2;
      return new GPoint(x,y);
    };
    
    // 重新實作 interface GProjection 的 fromPixelToLatLng(pixel,  zoom,  unbounded?) 回傳 GLatLng
    PolarStereographicProjection.prototype.fromPixelToLatLng = function(pixel, zoom, unbounded) {
      var s2 = 256 / 2 * Math.pow(2,zoom);
      var x = pixel.x / s2 - 1;
      var y = pixel.y / s2 - 1;
      if ( x == 0 && y == 0 ) return new GLatLng(90,0);
      var z = this.zvector * Math.min( 2.0 / ( x*x + y*y + 1 ) - 1.0, 1.0 );
      var lon = 180/Math.PI * Math.atan2( x, this.zvector * y );
      var lat = 180/Math.PI * Math.asin( z );
      return new GLatLng(lat,lon);
    };
    
    // 重新實作 interface GProjection 的 tileCheckRange(tile,  zoom,  tilesize) 回傳 Boolean
    PolarStereographicProjection.prototype.tileCheckRange = function(tile, zoom, tilesize) {
      if( zoom > this.zoomlevels ) return false;
      else return true;
    };
    
    // 重新實作 interface GProjection 的 getWrapWidth(zoom) 回傳 Number (比例尺的數字)
    PolarStereographicProjection.prototype.getWrapWidth = function(zoom) {
      // Is there a better cross-platform way to represent Infinity here?
      return 1E+100 * Math.pow(2,zoom);
    };
    
Last modified 16 years ago Last modified on Sep 22, 2008, 11:44:43 PM

Attachments (3)

Download all attachments as: .zip