KML 與 GeoRSS 圖層

選取平台: Android iOS JavaScript

KmlLayer 會將 KML 和 GeoRSS 元素算繪成 Maps JavaScript API 圖塊疊加層。

總覽

Maps JavaScript API 支援顯示地理資訊的 KML 和 GeoRSS 資料格式。這些資料格式使用 KmlLayer 物件顯示在地圖上,該物件的建構函式接受可公開存取的 KML 或 GeoRSS 檔案網址。

注意:在 Maps JavaScript API 中產生 KML 疊加層的 KmlLayer 類別,會以 Google 代管的服務擷取和剖析 KML 檔案,並進行算繪。因此,只有當 KML 檔案代管在無需驗證即可公開存取的網址時,才能顯示這些檔案。

如果您需要存取私人檔案、精確控制快取,或是將瀏覽器可視區域做為查詢參數傳送至地理空間資料伺服器,建議使用資料層,而非 KmlLayer。這會引導使用者的瀏覽器直接向您的網路伺服器要求資源。

Maps JavaScript API 會將提供的地理 XML 資料轉換成 KML 表示法,並使用 Maps JavaScript API 圖塊疊加層顯示在地圖上。這個 KML 不僅外觀與 Maps JavaScript API 疊加層元素十分相似,兩者的某些行為也十分雷同。舉例來說,KML <Placemark> 與 GeoRSS point 元素都會算繪為標記,<LineString> 元素會算繪為折線,而 <Polygon> 元素則會算繪為多邊形。同樣地,<GroundOverlay> 元素在地圖上會算繪為矩形圖片。但請注意,這些物件不是 Maps JavaScript API MarkersPolylinesPolygonsGroundOverlays,而是會算繪為地圖上的單一物件。

設定 KmlLayer 物件的 map 屬性後,物件就會顯示在地圖上。您可以呼叫 setMap() 並傳遞 null,將該物件從地圖上移除。KmlLayer 物件會針對地圖的特定範圍自動擷取適合的地圖項目,藉此管理這些子元素的算繪作業。範圍會產生變化時,目前可視區域內的地圖項目會自動算繪。

KmlLayer 內的元件是隨需算繪,因此您可以運用圖層輕鬆管理數千個標記、折線及多邊形的算繪作業。請注意,雖然每個構成物件所提供的點擊事件會針對各物件本身傳回資料,但您無法直接存取這些構成物件。

KML 圖層選項

KmlLayer() 建構函式會視需要傳遞數個 KmlLayerOptions

  • map 指定要算繪 KmlLayerMap。在 setMap() 方法中將此值設定為 null,即可隱藏 KmlLayer
  • preserveViewport 指定顯示圖層時,不應根據 KmlLayer 的內容範圍調整地圖。根據預設,顯示 KmlLayer 時,地圖會縮放並調整位置以顯示圖層的完整內容。
  • suppressInfoWindows 表示 KmlLayer 內的可點選地圖項目不應觸發 InfoWindow 物件顯示。

此外,經過算繪後,KmlLayer 會包含不可變更的 metadata 屬性,該屬性的 KmlLayerMetadata 物件常值中內含圖層的名稱、說明、程式碼片段及作者。您可以使用 getMetadata() 方法檢查此資訊。算繪 KmlLayer 物件時需要與外部伺服器進行非同步通訊,因此建議您監聽 metadata_changed 事件,事件會表示已經填入屬性。

以下範例是根據指定的 GeoRSS 動態饋給來建構 KmlLayer

TypeScript

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: 49.496675, lng: -102.65625 },
    }
  );

  const georssLayer = new google.maps.KmlLayer({
    url:
      "http://api.flickr.com/services/feeds/geo/?g=322338@N20&lang=en-us&format=feed-georss",
  });
  georssLayer.setMap(map);
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: 49.496675, lng: -102.65625 },
  });
  const georssLayer = new google.maps.KmlLayer({
    url: "http://api.flickr.com/services/feeds/geo/?g=322338@N20&lang=en-us&format=feed-georss",
  });

  georssLayer.setMap(map);
}

window.initMap = initMap;

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

HTML

<html>
  <head>
    <title>GeoRSS Layers</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>

測試範例

以下範例是根據指定的 KML 動態饋給來建構 KmlLayer

TypeScript

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 11,
      center: { lat: 41.876, lng: -87.624 },
    }
  );

  const ctaLayer = new google.maps.KmlLayer({
    url: "https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml",
    map: map,
  });
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 11,
    center: { lat: 41.876, lng: -87.624 },
  });
  const ctaLayer = new google.maps.KmlLayer({
    url: "https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml",
    map: map,
  });
}

window.initMap = initMap;

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

HTML

<html>
  <head>
    <title>KML Layers</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>

測試範例

KML 地圖項目詳細資料

KML 可能包含大量地圖項目,因此您無法直接從 KmlLayer 物件存取地圖項目資料。不過,顯示地圖項目時,系統會進行算繪,使地圖項目看起來像是可點選的 Maps JavaScript API 疊加層。根據預設,點選個別地圖項目時,系統會顯示 <title>,其中包含與指定地圖項目相關的 KML <title><description> 資訊。此外,點選 KML 地圖項目會產生 KmlMouseEvent 並傳遞下列資訊:

  • position 表示錨定此 KML 地圖項目 InfoWindow 的經緯度座標。這個位置通常是多邊形、折線和地面疊加層的點選位置,但對標記而言,則是實際起點。
  • pixelOffset 表示從上方的 position 到錨定 InfoWindow「尾端」位置的偏移值。對多邊形物件而言,此偏移值通常是 0,0,但對標記而言,還必須包含標記的高度。
  • featureData 包含 KmlFeatureData 的 JSON 結構。

以下顯示範例 KmlFeatureData 物件:

{
  author: {
    email: "nobody@google.com",
    name: "Mr Nobody",
    uri: "http://example.com"
  },
  description: "description",
  id: "id",
  infoWindowHtml: "html",
  name: "name",
  snippet: "snippet"
}

以下範例顯示地圖項目經點選時,側邊 <div> 內的 KML 地圖項目 <Description> 文字:

TypeScript

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 12,
      center: { lat: 37.06, lng: -95.68 },
    }
  );

  const kmlLayer = new google.maps.KmlLayer({
    url: "https://raw.githubusercontent.com/googlearchive/kml-samples/gh-pages/kml/Placemark/placemark.kml",
    suppressInfoWindows: true,
    map: map,
  });

  kmlLayer.addListener("click", (kmlEvent) => {
    const text = kmlEvent.featureData.description;

    showInContentWindow(text);
  });

  function showInContentWindow(text: string) {
    const sidebar = document.getElementById("sidebar") as HTMLElement;

    sidebar.innerHTML = text;
  }
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 12,
    center: { lat: 37.06, lng: -95.68 },
  });
  const kmlLayer = new google.maps.KmlLayer({
    url: "https://raw.githubusercontent.com/googlearchive/kml-samples/gh-pages/kml/Placemark/placemark.kml",
    suppressInfoWindows: true,
    map: map,
  });

  kmlLayer.addListener("click", (kmlEvent) => {
    const text = kmlEvent.featureData.description;

    showInContentWindow(text);
  });

  function showInContentWindow(text) {
    const sidebar = document.getElementById("sidebar");

    sidebar.innerHTML = text;
  }
}

window.initMap = initMap;

CSS

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#container {
  height: 100%;
  display: flex;
}

#sidebar {
  flex-basis: 15rem;
  flex-grow: 1;
  padding: 1rem;
  max-width: 30rem;
  height: 100%;
  box-sizing: border-box;
  overflow: auto;
}

#map {
  flex-basis: 0;
  flex-grow: 4;
  height: 100%;
}

HTML

<html>
  <head>
    <title>KML Feature Details</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="container">
      <div id="map"></div>
      <div id="sidebar"></div>
    </div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>

測試範例

KML 算繪的大小和複雜度限制

Maps JavaScript API 會限制所載入 KML 檔案的大小和複雜度。以下摘要列出目前的限制:

注意:這些限制隨時可能有所變動。

可擷取檔案大小上限 (原始 KML、原始 GeoRSS 或壓縮過的 KMZ)
3 MB
未壓縮 KML 檔案大小上限
10 MB
KMZ 檔案中未壓縮圖片檔大小上限
每個檔案 500 KB
網路連結數量上限
10
整份文件的地圖項目總數上限
1,000
KML 圖層數量
單一 Google 地圖可顯示的 KML 圖層數量有上限。如果超過此上限,地圖上就不會顯示您的任何圖層,且網路瀏覽器的 JavaScript 控制台中會顯示錯誤訊息。這個上限取決於兩項因素,即已建立的 KmlLayer 類別數量,以及用於建立這些圖層的所有網址總長度。您建立的所有新 KmlLayer 都會佔圖層上限的一部分,而 KML 檔案載入來源的網址長度也會佔另一部分。因此,可新增的圖層數量會因應用程式而異。平均來說,您應該可以載入 10 到 20 個圖層,而不會達到上限。如果您仍達到上限,請使用網址縮短工具縮短 KML 網址。您也可以建立單一 KML 檔案,在其中納入指向個別 KML 網址的 NetworkLink

效能和快取注意事項

Google 的伺服器會暫時快取 KML 檔案,以降低伺服器的負載。這也會在使用者點選、平移和縮放地圖時,為 KML 檔案提供適當區隔以有效利用空間呈現方式,進而改善使用者體驗。

為獲得最佳成效,建議您:

  • 在 KML 中使用適當的 <expires> 標記。

    KmlLayer 決定如何快取 KML 檔案時,「不會」使用 HTTP 標頭。
  • 請勿在要求時動態產生檔案。

    請改為在有需要前就產生檔案,並以靜態方式提供。如果伺服器需要較長的時間來傳輸 KML 檔案,KmlLayer 可能無法顯示。
  • 除非您明確知道檔案已更新,否則請勿嘗試略過快取。

    如果網站使用者突然增加,且您提供大型的 KML 檔案,則一律略過快取 (例如透過附加隨機號碼或使用者的時鐘時間做為查詢參數) 會導致伺服器過載。

    此外,如果使用者的時鐘不正確,且 <expires> 標記未正確設定,還可能會導致快取為使用者提供過時的資料。

    請改為使用獨立的新修訂版本編號發布更新後的靜態檔案,然後使用伺服器端程式碼,將傳送至 KmlLayer 的網址動態更新為目前版本。
  • 將您的 KML 檔案變更頻率限制為每分鐘一次。

    如果所有檔案的總大小 (未壓縮) 超過 1 MB,則將變更頻率限制為每 5 分鐘一次。
  • 使用地理空間資料伺服器時,請避免使用查詢參數來限制圖層的可視區域。

    您可以改為使用 bounds_changed 事件來限制地圖可視區域。系統只會向使用者傳送可自動顯示的地圖項目。

    如果地理空間資料伺服器中有大量資料,建議您改用資料層
  • 使用地理空間資料伺服器時,請針對要允許使用者切換的每個地圖項目群組使用多個 KmlLayer,而不要使用具備不同查詢參數的單一 KmlLayer
  • 使用壓縮的 KMZ 檔案縮減檔案大小。
  • 如果您使用 Google Cloud Storage 或其他雲端儲存空間解決方案,請「避免」使用經簽署的網址或臨時權杖等功能來強制執行存取權控管。這類操作可能會意外造成快取作業無法執行。
  • 將所有點的精確度降低為適當的精確度
  • 合併並簡化類似地圖項目 (例如多邊形和折線) 的幾何圖形。
  • 移除所有未使用的元素或圖片資源。
  • 移除所有不支援的元素

如果您需要存取私人資料、防止快取,或是將瀏覽器可視區域傳送至地理空間資料伺服器做為查詢參數,建議您使用資料層,而非 KmlLayer。這會引導使用者的瀏覽器直接向您的網路伺服器要求資源。

支援的 KML 元素

Maps JavaScript API 支援下列 KML 元素。KML 剖析器通常會自動忽略無法辨識的 XML 標記。

  • 地標
  • 圖示
  • 資料夾
  • 描述性 HTML:透過 <BalloonStyle> 和 <text> 的實體替代項目
  • KMZ (壓縮過的 KML,包括附加圖片)
  • 折線和多邊形
  • 折線和多邊形樣式,包括顏色、填滿和不透明度
  • 可動態匯入資料的網路連結
  • 區域疊加層和螢幕疊加層

下表提供支援的 KML 元素完整詳細資料。

KML 元素 API 是否支援? 註解
<address>
<AddressDetails>
<Alias> 不適用 不支援 <Model>
<altitude>
<altitudeMode>
<atom:author>
<atom:link>
<atom:name>
<BalloonStyle> 部分支援 僅支援 <text>
<begin> 不適用 不支援 <TimeSpan>
<bgColor>
<bottomFov> 不適用 不支援 <PhotoOverlay>
<Camera>
<Change> 部分支援 僅支援樣式變更
<color> 部分支援 包含 #AABBGGRR 和 #BBGGRR;<IconStyle>、<ScreenOverlay> 和 <GroundOverlay> 不支援
<colorMode>
<cookie>
<coordinates>
<Create>
<Data>
<Delete>
<description> 允許 HTML 內容,但會經過清除,以免受到跨瀏覽器攻擊。不支援 $[dataName] 表單的實體替代項目。
<displayMode>
<displayName>
<Document> 部分支援 默示支援子項;做為其他地圖項目的子項無效
<drawOrder>
<east>
<end> 不適用 不支援 <TimeSpan>
<expires> 詳情請參閱「摘要」部分
<ExtendedData> 部分支援 僅支援未經類型宣告的 <Data>,不支援 <SimpleData> 或 <Schema>,也不支援 $[dataName] 表單的實體替代項目。
<extrude>
<fill>
<flyToView>
<Folder>
<geomColor> 已淘汰
<GeometryCollection> 已淘汰
<geomScale> 已淘汰
<gridOrigin> 不適用 不支援 <PhotoOverlay>
<GroundOverlay> 無法旋轉
<h> 已淘汰
<heading>
hint 支援 target=...
<hotSpot>
<href>
<httpQuery>
<Icon> 無法旋轉
<IconStyle>
<ImagePyramid> 不適用 不支援 <PhotoOverlay>
<innerBoundaryIs> 依 <LinearRing> 順序默示
<ItemIcon> 不適用 不支援 <ListStyle>
<key> 不適用 不支援 <StyleMap>
<kml>
<labelColor> 已淘汰
<LabelStyle>
<latitude>
<LatLonAltBox>
<LatLonBox>
<leftFov> 不適用 不支援 <PhotoOverlay>
<LinearRing>
<LineString>
<LineStyle>
<Link>
<linkDescription>
<linkName>
<linkSnippet>
<listItemType> 不適用 不支援 <ListStyle>
<ListStyle>
<Location> 不適用 不支援 <Model>
<Lod>
<longitude>
<LookAt>
<maxAltitude>
<maxFadeExtent>
<maxHeight> 不適用 不支援 <PhotoOverlay>
<maxLodPixels>
<maxSessionLength>
<maxWidth> 不適用 不支援 <PhotoOverlay>
<message>
<Metadata> 已淘汰
<minAltitude>
<minFadeExtent>
<minLodPixels>
<minRefreshPeriod> <NetworkLink>
<Model>
<MultiGeometry> 部分支援 已進行算繪,但在左側面板中顯示為獨立地圖項目
<name>
<near> 不適用 不支援 <PhotoOverlay>
<NetworkLink>  
<NetworkLinkControl> 部分支援 部分支援 <Update> 和 <expires>。API 會忽略 HTTP 標頭中的到期時間設定,但會使用 KML 中指定的到期時間設定。如果沒有到期時間設定或在有效期間的間隔內,Google 地圖可能會快取從網際網路擷取的資料 (未指定持續時間)。重新命名文件並以不同網址擷取,或是確保文件包含適當的到期時間設定,都可以強制從網際網路重新擷取資料。
<north>
<open>
<Orientation> 不適用 不支援 <Model>
<outerBoundaryIs> 依 <LinearRing> 順序默示
<outline>
<overlayXY>
<Pair> 不適用 不支援 <StyleMap>
<phoneNumber>
<PhotoOverlay>
<Placemark>
<Point>
<Polygon>
<PolyStyle>
<range>
<refreshInterval> 部分支援 僅限 <Link>;<Icon> 不支援
<refreshMode> 「onExpire」模式不支援 HTTP 標頭。請參閱上方的 <Update> 和 <expires> 註解。
<refreshVisibility>
<Region>
<ResourceMap> 不適用 不支援 <Model>
<rightFov> 不適用 不支援 <PhotoOverlay>
<roll> 不適用 不支援 <Camera> 和 <Model>
<rotation>
<rotationXY>
<Scale> 不適用 不支援 <Model>
<scale>
<Schema>
<SchemaData>
<ScreenOverlay> 無法旋轉
<screenXY>
<shape> 不適用 不支援 <PhotoOverlay>
<SimpleData> 不適用 不支援 <SchemaData>
<SimpleField> 不適用 不支援 <Schema>
<size>
<Snippet>
<south>
<state> 不適用 不支援 <ListStyle>
<Style>
<StyleMap> 不支援滑鼠游標懸停 (醒目顯示) 效果
<styleUrl> 不適用 不支援 <StyleMap>
<targetHref> 部分支援 <Update> 支援,<Alias> 不支援
<tessellate>
<text> 不支援 $[geDirections] 替代項目
<textColor>
<tileSize> 不適用 不支援 <PhotoOverlay>
<tilt>
<TimeSpan>
<TimeStamp>
<topFov> 不適用 不支援 <PhotoOverlay>
<Update> 部分支援 僅樣式變更,不支援 <Create> 或 <Delete>
<Url> 已淘汰
<value>
<viewBoundScale>
<viewFormat>
<viewRefreshMode> 部分支援 支援「onStop」
<viewRefreshTime>
<ViewVolume> 不適用 不支援 <PhotoOverlay>
<visibility> 部分支援 在 <Folder> 上支援 - 子項地標會沿用其中的瀏覽權限
<w> 已淘汰
<west>
<when> 不適用 不支援 <TimeStamp>
<width>
<x> 已淘汰
<y> 已淘汰