天天看點

Google Maps API V3 之繪圖庫

繪圖庫

本文檔中的概念僅适用于 

google.maps.drawing

 庫中提供的地圖項。預設情況下,系統在加載 Maps JavaScript API 時不會加載該庫,您必須使用 

libraries

 引導程式參數進行明确指定。 

http://maps.googleapis.com/maps/api/js?sensor=false&libraries=drawing

DrawingManager

 類提供了一個圖形界面,以供使用者在地圖上繪制多邊形、矩形、折線、圓形和标記。

DrawingManager

 對象以如下方式建立:

var drawingManager = new google.maps.drawing.DrawingManager();
drawingManager.setMap(map);      

DrawingManager 選項

DrawingManager

 構造函數采用一組選項,以定義要顯示的控件集、控件的位置以及初始繪圖狀态。

  • DrawingManager

     的 

    drawingMode

     屬性用于定義 DrawingManager 的初始繪圖狀态。該屬性接受 

    google.maps.drawing.OverlayType

     常量,且預設為 

    null

    (在此情況下啟動 DrawingManager 時,光标會處于非繪圖模式)。
  • DrawingManager

     的 

    drawingControl

     屬性用于定義地圖上的繪圖工具選擇界面的可見性。該屬性接受布爾值。
  • 您還可以使用 

    DrawingManager

     的 

    drawingControlOptions

     屬性,定義控件的位置以及控件中應表示的疊加層的類型。
    • position

       用于定義繪圖控件在地圖上的位置,且接受 

      google.maps.ControlPosition

       常量。
    • drawingModes

       是一組 

      google.maps.drawing.OverlayType

       常量,且用于定義繪圖控件形狀選擇器中包含的疊加層類型。系統将始終顯示手形圖示,以便使用者無需繪圖即可與地圖進行互動。
  • 您可為每種疊加層類型都指定一組預設屬性,以便定義首次建立相應疊加層時所采用的外觀。這些屬性可在疊加層的 

    {overlay}Options

     屬性(其中 

    {overlay}

     表示疊加層的類型)中進行定義。例如,圓形的填充屬性、筆觸屬性、zIndex 和可點選性可使用 

    circleOptions

     屬性進行定義。如果已傳遞任何大小、位置或地圖值,則系統會忽略這些預設屬性。
var drawingManager = new google.maps.drawing.DrawingManager({
  drawingMode: google.maps.drawing.OverlayType.MARKER,
  drawingControl: true,
  drawingControlOptions: {
    position: google.maps.ControlPosition.TOP_CENTER,
    drawingModes: [google.maps.drawing.OverlayType.MARKER, google.maps.drawing.OverlayType.CIRCLE]
  },
  markerOptions: {
    icon: new google.maps.MarkerImage('http://www.example.com/icon.png')
  },
  circleOptions: {
    fillColor: '#ffff00',
    fillOpacity: 1,
    strokeWeight: 5,
    clickable: false,
    zIndex: 1,
    editable: true
  }
});
drawingManager.setMap(map);
           

更新繪圖工具控件

建立 

DrawingManager

 對象後,您可調用 

setOptions()

 并傳遞新的值,以進行更新。

drawingManager.setOptions({
  drawingControlOptions: {
    position: google.maps.ControlPosition.BOTTOM_LEFT,
    drawingModes: [google.maps.drawing.OverlayType.MARKER]
  }
});
           

使用以下方法即可隐藏或顯示繪圖工具控件:

// To hide:
drawingManager.setOptions({
  drawingControl: false
});

// To show:
drawingManager.setOptions({
  drawingControl: true
});
           

要從 

map

 對象删除繪圖工具控件,請使用以下方法:

隐藏繪圖控件會導緻繪圖工具控件無法顯示,不過 

DrawingManager

 類的所有功能仍然可用。這樣即可實作您自己的控件(如有必要)。從 

map

 對象删除 

DrawingManager

 會導緻所有繪圖功能停用;要恢複繪圖地圖項,請務必使用 

drawingManager.setMap(map)

 将 

DrawingManager

 對象重新附加到地圖,或者構造新的該對象。

繪圖事件

建立形狀疊加層後,會觸發以下兩個事件:

  • {overlay}complete

     事件(其中 

    {overlay}

     代表疊加層類型,例如 

    circlecomplete

    polygoncomplete

     等)。對相應疊加層的引用會作為參數進行傳遞。
  • overlaycomplete

     事件。包含 

    OverlayType

     和對相應疊加層的引用的對象常量會作為參數進行傳遞。
google.maps.event.addListener(drawingManager, 'circlecomplete', function(circle) {
  var radius = circle.getRadius();
});

google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event) {
  if (event.type == google.maps.drawing.OverlayType.CIRCLE) {
    var radius = event.overlay.getRadius();
  }
});
           

資訊視窗

InfoWindow

 用于在地圖上方以浮動視窗的形式顯示内容。資訊視窗有點像漫畫書上的文字氣泡框,它有一個内容區域和一條錐形引線,引線的頭位于地圖的指定位置上。點選 Google 地圖上的商戶标記後,您就可以看到活動的資訊視窗了。

InfoWindow

 構造函數采用 

InfoWindow options 

對象,以指定一組關于資訊視窗的顯示方式的初始參數。建立完畢後,所生成的資訊視窗不會添加到地圖上。要顯示該資訊視窗,您需要對 

InfoWindow

 調用 

open()

 方法,并向其傳遞要在其上打開資訊視窗的 

Map

,以及用于錨定該資訊視窗的 

Marker

(可選)。(如果未提供任何标記,則會在該資訊視窗的 

position

 屬性處将其打開。)

InfoWindow options

 對象是一個包含以下字段的對象常量:

  • content

    ,其中包含要在資訊視窗打開後顯示在其中的文本字元串或 DOM 節點。
  • pixelOffset

    ,其中包含從資訊視窗的尖端到其錨定位置的偏移量。實際上,您無需修改此字段。
  • position

    ,其中包含此資訊視窗錨定位置處的 

    LatLng

    。請注意,在标記上打開資訊視窗後,系統會自動使用一個新位置更新該值。
  • maxWidth

    ,用于指定資訊視窗的最大寬度(以像素為機關)。預設情況下,資訊視窗會根據其内容進行擴充,并且如果是為填充地圖而進行擴充的,則其文本會自動換行。如果您實作了 

    maxWidth

    ,那麼資訊視窗将會自動換行以強制适應像素寬度。如果螢幕的實際使用面積允許的話,那麼資訊視窗在達到最大寬度後仍然可以垂直擴充。

InfoWindow

 的内容可以是文本字元串、HTML 代碼段,也可以就是 DOM 元素。要設定此内容,請在 

InfoWindow options

 構造函數中傳遞該内容,或者對資訊視窗顯式調用

setContent()

。要顯式調整内容的大小,您可以使用 

<div>

 進行調整,或者啟用滾動功能(如果您希望的話)。請注意,如果您沒有啟用滾動功能,且内容的大小又超出了資訊視窗的可用空間,那麼内容可能會從資訊視窗中“溢”出。

您可以将 

InfoWindow

 附加到 

Marker

 對象(在此情況下,資訊視窗的位置取決于标記的位置)上,或者地圖上所指定的 

LatLng

 位置。如果您一次隻想顯示一個資訊視窗(正如 Google 地圖上的相應行為),隻需建立一個資訊視窗,然後在地圖事件(例如使用者點選)完畢後将其重新配置設定到不同的位置或标記即可。不過與 Google Maps API V2 中的相應行為不同,如果您選擇執行以上操作,那麼地圖可能會立即顯示多個 

InfoWindow

 對象。

要更改某個資訊視窗的位置,您可以對該資訊視窗調用 

setPosition()

 以顯式更改其位置,或者使用 

InfoWindow.open()

 方法将其附加到新标記。請注意,如果您在沒有傳遞标記的情況下調用了 

open()

,那麼 

InfoWindow

 将會使用建構完畢後通過 

InfoWindow options

 對象所指定的位置。

以下代碼顯示了澳洲中心位置的标記。點選該标記可顯示資訊視窗。

var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var mapOptions = {
  zoom: 4,
  center: myLatlng,
  mapTypeId: google.maps.MapTypeId.ROADMAP
}

var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

var contentString = '<div id="content">'+
    '<div id="siteNotice">'+
    '</div>'+
    '<h2 id="firstHeading" class="firstHeading">Uluru</h2>'+
    '<div id="bodyContent">'+
    '<p><b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large ' +
    'sandstone rock formation in the southern part of the '+
    'Northern Territory, central Australia. It lies 335 km (208 mi) '+
    'south west of the nearest large town, Alice Springs; 450 km '+
    '(280 mi) by road. Kata Tjuta and Uluru are the two major '+
    'features of the Uluru - Kata Tjuta National Park. Uluru is '+
    'sacred to the Pitjantjatjara and Yankunytjatjara, the '+
    'Aboriginal people of the area. It has many springs, waterholes, '+
    'rock caves and ancient paintings. Uluru is listed as a World '+
    'Heritage Site.</p>'+
    '<p>Attribution: Uluru, <a href="http://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194" target="_blank" rel="external nofollow" >'+
    'http://en.wikipedia.org/w/index.php?title=Uluru</a> (last visited June 22, 2009).</p>'+
    '</div>'+
    '</div>';

var infowindow = new google.maps.InfoWindow({
    content: contentString
});

var marker = new google.maps.Marker({
    position: myLatlng,
    map: map,
    title:"Uluru (Ayers Rock)"
});

google.maps.event.addListener(marker, 'click', function() {
  infowindow.open(map,marker);
});
           

地面疊加層

多邊形在表示不規則的區域時很有用,但不能顯示圖檔。要在地圖上放置一張圖檔,請使用 

GroundOverlay

 對象。

 GroundOverlay

 的構造函數指定圖檔的網址和

LatLngBounds

 作為參數。圖檔将在地圖上的給定邊界内呈現,并與地圖的投影一緻。

以下示例将紐澤西州紐瓦克的一幅老地圖作為疊加層放在地圖上:

var newark = new google.maps.LatLng(40.740, -74.18);
var imageBounds = new google.maps.LatLngBounds(
    new google.maps.LatLng(40.716216,-74.213393),
    new google.maps.LatLng(40.765641,-74.139235));

var mapOptions = {
  zoom: 13,
  center: newark,
  mapTypeId: google.maps.MapTypeId.ROADMAP
}

var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

var oldmap = new google.maps.GroundOverlay(
    "http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg",
    imageBounds);
oldmap.setMap(map);
           

自定義疊加層

Google Maps API V3 提供了用于建立自定義疊加層的 

OverlayView

 類。

OverlayView

 是一個基類,可為您提供在建立疊加層時必須實作的若幹方法。該類還提供了一些方法,用于實作螢幕坐标和地圖位置之間的轉換。

要建立自定義疊加層,請執行以下操作:

  • 将自定義對象的 

    prototype

     設定為 

    google.maps.OverlayView()

     的新執行個體。這可以有效地實作疊加層類的“子類化”。
  • 為自定義疊加層建立構造函數,并将該構造函數中的所有初始化參數都設定為自定義屬性。
  • 在原型中實作 

    onAdd()

     方法,以将疊加層附加到地圖。在地圖準備好附加疊加層後,系統将會調用 

    OverlayView.onAdd()

  • 在原型中實作 

    draw()

     方法,以處理對象的視覺顯示。同樣,在對象首次顯示後,系統将會調用 

    OverlayView.draw()

  • 您還應實作 

    onRemove()

     方法,以清理疊加層中添加的所有元素。

我們将會在以下各部分中逐漸介紹這些操作。

疊加層的子類化

我們将會使用 

OverlayView

 建立簡單的圖檔疊加層(類似于 V2 API 中的 

GGroundOverlay

)。我們将建立一個 

USGSOverlay

 對象,其中包含了相關區域的 USGS 圖檔以及該圖檔的邊界。

var overlay;

function initialize() {
  var myLatLng = new google.maps.LatLng(62.323907, -150.109291);
  var mapOptions = {
    zoom: 11,
    center: myLatLng,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  };

  var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

  var swBound = new google.maps.LatLng(62.281819, -150.287132);
  var neBound = new google.maps.LatLng(62.400471, -150.005608);
  var bounds = new google.maps.LatLngBounds(swBound, neBound);

  // Photograph courtesy of the U.S. Geological Survey
  var srcImage = 'images/talkeetna.png';
  overlay = new USGSOverlay(bounds, srcImage, map);
}
           

接下來,我們将建立一個該類的構造函數,并将已傳遞的參數初始化為新對象的屬性。此外,我們還需要顯式地将 

OverlayView

 中的 

USGSOverlay

 子類化。為此,我們會将新類的 

prototype

 設為相應父類的一個執行個體。(由于我們不希望修改父類,是以将此處的原型設為了執行個體,而非該父類。)

function USGSOverlay(bounds, image, map) {

  // Now initialize all properties.
  this.bounds_ = bounds;
  this.image_ = image;
  this.map_ = map;

  // We define a property to hold the image's
  // div. We'll actually create this div
  // upon receipt of the add() method so we'll
  // leave it null for now.
  this.div_ = null;

  // Explicitly call setMap() on this overlay
  this.setMap(map);
}

USGSOverlay.prototype = new google.maps.OverlayView();
           

目前,我們還無法在疊加層的構造函數中将此疊加層附加到地圖上。具體而言,我們需要確定所有的地圖窗格(用于指定對象在地圖上的顯示順序)都可用。API 提供了一種幫助程式方法,可以非常友善地表明是否執行了上述操作。我們将會在下一部分中介紹如何處理該方法。

初始化疊加層

當疊加層完成首次示例化并處于準備顯示狀态時,我們需要通過浏覽器的 DOM 将其附加到地圖。API 會顯示相關資訊以表明:系統已認證調用疊加層的 

onAdd()

 方法将其添加到地圖。在處理此方法時,我們會建立一個用于存儲圖檔的 

<div>

,然後添加一個 

<img>

 元素并将其附加到 

<div>

,最後将疊加層附加到地圖的一個“窗格”(即 DOM 樹中的節點)。

一組 

MapPanes

 類型的窗格用于指定不同的層在地圖上的堆疊順序。您可以使用以下窗格,并按以下枚舉順序(由下至上,第一個窗格在最下面)堆疊這些窗格:

  • MapPanes.mapPane

  • MapPanes.overlayLayer

  • MapPanes.overlayShadow

  • MapPanes.overlayImage

  • MapPanes.floatShadow

  • MapPanes.overlayMouseTarget

  • MapPanes.floatPane

由于我們的圖檔為“地面疊加層”,是以将會使用 

overlayLayer

 地圖窗格。建立該窗格後,我們将以子對象的形式向其附加對象。

USGSOverlay.prototype.onAdd = function() {

  // Note: an overlay's receipt of onAdd() indicates that
  // the map's panes are now available for attaching
  // the overlay to the map via the DOM.

  // Create the DIV and set some basic attributes.
  var div = document.createElement('div');
  div.style.border = "none";
  div.style.borderWidth = "0px";
  div.style.position = "absolute";

  // Create an IMG element and attach it to the DIV.
  var img = document.createElement("img");
  img.src = this.image_;
  img.style.width = "100%";
  img.style.height = "100%";
  div.appendChild(img);

  // Set the overlay's div_ property to this DIV
  this.div_ = div;

  // We add an overlay to a map via one of the map's panes.
  // We'll add this overlay to the overlayImage pane.
  var panes = this.getPanes();
  panes.overlayLayer.appendChild(div);
}
           

繪制疊加層

請注意,在上述操作中,我們實際上并未調用任何特殊的視覺顯示。每當需要在地圖上繪制疊加層時(包括首次添加疊加層時),API 都會對疊加層調用獨立的 

draw()

 方法。

是以,我們将會實作此 

draw()

 方法,然後使用 

getProjection()

 檢索疊加層的 

MapCanvasProjection

,并計算對象的右上角和左下角錨定點的準确坐标,進而重新調整 

<div>

 的大小;同時,此操作還可重新調整圖檔的大小,以使其與我們在疊加層的構造函數中所指定的範圍相比對。

USGSOverlay.prototype.draw = function() {

  // Size and position the overlay. We use a southwest and northeast
  // position of the overlay to peg it to the correct position and size.
  // We need to retrieve the projection from this overlay to do this.
  var overlayProjection = this.getProjection();

  // Retrieve the southwest and northeast coordinates of this overlay
  // in latlngs and convert them to pixels coordinates.
  // We'll use these coordinates to resize the DIV.
  var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
  var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());

  // Resize the image's DIV to fit the indicated dimensions.
  var div = this.div_;
  div.style.left = sw.x + 'px';
  div.style.top = ne.y + 'px';
  div.style.width = (ne.x - sw.x) + 'px';
  div.style.height = (sw.y - ne.y) + 'px';
}
           

删除疊加層

我們還會添加 

onRemove()

 方法,以便從地圖徹底删除疊加層。如果之前将疊加層的 

map

 屬性設為了 

null

,那麼系統将會自動通過 API 調用此方法。

USGSOverlay.prototype.onRemove = function() {
  this.div_.parentNode.removeChild(this.div_);
  this.div_ = null;
}
           

隐藏和顯示疊加層

如果您想要隐藏或顯示(而不隻是建立或删除)疊加層,您可實作自己的 

hide()

 和 

show()

 方法,以調整疊加層的可見性。此外,您也可以将疊加層與地圖的 DOM 分離,不過此操作的成本略高。請注意,如果您随後将疊加層重新附加到了地圖的 DOM,那麼系統将會重新調用疊加層的 

onAdd()

 方法。

以下示例介紹了如何将 

hide()

 和 

show()

 方法添加到疊加層的原型,以切換容器 

<div>

 的可見性。此外,我們還添加了 

toogleDOM()

 方法,該方法可将疊加層附加到地圖,或将兩者分離開來。請注意,如果我們将可見性設為 

"hidden"

,那麼系統會通過 

toggleDOM()

 将地圖與 DOM 分離;如果我們稍後重新附加了地圖,那麼疊加層會再次顯示出來,這是因為我們利用疊加層的 

onAdd()

 方法重新建立了其中所包含的 

<div>

// Note that the visibility property must be a string enclosed in quotes
USGSOverlay.prototype.hide = function() {
  if (this.div_) {
    this.div_.style.visibility = "hidden";
  }
}

USGSOverlay.prototype.show = function() {
  if (this.div_) {
    this.div_.style.visibility = "visible";
  }
}

USGSOverlay.prototype.toggle = function() {
  if (this.div_) {
    if (this.div_.style.visibility == "hidden") {
      this.show();
    } else {
      this.hide();
    }
  }
}

USGSOverlay.prototype.toggleDOM = function() {
  if (this.getMap()) {
    this.setMap(null);
  } else {
    this.setMap(this.map_);
  }
}
           
// Now we add an input button to initiate the toggle method
// on the specific overlay
<div id ="toolbar" width="100%; height:20px;" style="text-align:center">
  <input type="button" value="Toggle Visibility" οnclick="overlay.toggle();"></input>
  <input type="button" value="Toggle DOM Attachment" οnclick="overlay.toggleDOM();"></input>
</div>
<div id="map_canvas" style="width: 100%; height: 95%;"></div>
           

繼續閱讀