KML 图层和 GeoRSS 图层

请选择平台: Android iOS JavaScript

KmlLayer 可将 KML 和 GeoRSS 元素渲染成 Maps JavaScript API 图块叠加层。

概览

Maps JavaScript API 支持用于显示地理信息的 KML 和 GeoRSS 数据格式。这些数据格式利用 KmlLayer 对象显示在地图上,该对象的构造函数接受可公开访问的 KML 或 GeoRSS 文件的网址。

注意KmlLayer 类会在 Maps JavaScript API 中生成 KML 叠加层,它使用 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 指定在哪个 Map 上渲染 KmlLayer。您可以隐藏 KmlLayer,只需在 setMap() 方法中将此值设置为 null 即可。
  • preserveViewport 指定在显示图层时不应根据 KmlLayer 内容的边界调整地图。默认情况下,在显示 KmlLayer 时,地图会缩放并调整位置,以显示图层的全部内容。
  • suppressInfoWindows 指示 KmlLayer 内的可点击地图项不应触发 InfoWindow 对象的显示。

此外,经过渲染后,KmlLayer 会包含一个不可更改的 metadata 属性,该属性的 KmlLayerMetadata 对象字面量中包含该图层的名称、说明、摘要和作者。您可以使用 getMetadata() 方法检查此类信息。由于渲染 KmlLayer 对象需要与外部服务器进行异步通信,因此您需要监听 metadata_changed 事件,该事件将指明属性已填充完毕。

下面的示例根据指定的 GeoRSS Feed 构造了 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 Feed 构造了 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 叠加层。默认情况下,点击各个地图项时,系统会显示 InfoWindow,其中包含有关指定地图项的 KML <title><description> 信息。此外,点击 KML 地图项还会生成 KmlMouseEvent,后者会传递以下信息:

  • position 表示锚定此 KML 地图项的 InfoWindow 时所在的纬度/经度坐标。对于多边形、多段线和 GroundOverlays,该位置通常是所点击的位置;但对于标记,则是坐标原点。
  • 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)的大小上限
3MB
未压缩的 KML 文件的大小上限
10MB
KMZ 文件中未压缩的图片文件的大小上限
每个文件 500KB
网络链接数量上限
10 个
文档范围内地图项的总数上限
1,000 个
KML 图层的数量
单个 Google 地图上可显示的 KML 图层数量存在限制。如果超过该限制,所有图层都不会显示在地图上,并且网络浏览器的 JavaScript 控制台中将会报错。该限制是综合考虑创建的 KmlLayer 类的数量与创建这些图层时使用的所有网址的总长度确定的。您创建的每个新 KmlLayer 都会占用图层限额的一部分,并且根据加载的 KML 文件所在网址的长度,还会再占用一部分限额。因此,您可以添加的图层数量因应用而异;平均而言,您应该可以加载 10 到 20 个图层而不达到上限。如果您还是达到了上限,请使用 URL Shortener 缩短 KML 网址。此外,您也可以创建单个 KML 文件,在其中包含指向各 KML 网址的 NetworkLink

性能和缓存方面的注意事项

Google 的服务器会暂时缓存 KML 文件,以减少您的服务器的负载。此外,这还可以在用户点击、平移和缩放地图时,通过为 KML 文件提供可节省空间的相应线段表示法,提升用户的性能体验。

为实现最佳性能,建议您执行以下操作:

  • 在 KML 中使用适当的 <expires> 标记。

    KmlLayer 不会使用 HTTP 标头确定缓存 KML 文件的方式。
  • 请勿在请求时动态生成文件。

    相反,这些文件应在需要使用之前生成,然后以静态方式传送。如果您的服务器传输 KML 文件需要很长时间,那么 KmlLayer 可能不会显示。
  • 除非您明确知道文件已更新,否则请勿尝试绕过缓存。

    如果您的网站使用人数突然增多,您要传送较大的 KML 文件,那么始终绕过缓存(例如,通过以查询参数的形式附加随机数字或用户的时钟时间)的做法很容易导致您的服务器超负荷运转。

    如果任意用户的时钟不正确,并且 <expires> 标记尚未正确设置,这还会导致缓存向用户传送过时数据。

    您应改为使用独立的新修订版本号发布更新后的静态文件,并使用服务器端代码将传递到 KmlLayer 的网址动态更新为最新版本。
  • 将对 KML 文件的更改限制为每分钟一次。

    如果所有文件的总大小(未压缩)超过 1MB,则将更改限制为每 5 分钟一次。
  • 使用地理空间数据服务器时,请避免使用查询参数限制图层的视口。

    您可以改为使用 bounds_changed 事件限制地图视口。这样,系统就只会向用户发送可自动显示的地图项。

    如果您的地理空间数据服务器中包含大量数据,建议您改用数据层
  • 使用地理空间数据服务器时,请为您希望允许用户切换的每组地图项使用多个 KmlLayer,而不是使用包含不同查询参数的单个 KmlLayer
  • 使用压缩的 KMZ 文件缩减文件大小。
  • 如果您使用的是 Google Cloud Storage 或其他云端存储空间解决方案,请避免使用签名网址或临时令牌等功能强制执行访问权限控制。这可能会意外阻止缓存。
  • 将所有点的精确度降低到适当的精确度
  • 合并并简化相似地图项的几何图形,例如多边形和多段线。
  • 移除任何未使用的元素或图片资源。
  • 移除任何不受支持的元素

如果您需要访问私密数据、阻止缓存,或者将浏览器视口作为查询参数发送到地理空间数据服务器,建议您使用数据层,而不是 KmlLayer。这将引导您用户的浏览器直接从您的 Web 服务器请求资源。

支持的 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> 已弃用