Capas KML y GeoRSS

Seleccionar plataforma: Android iOS JavaScript

La KmlLayer renderiza elementos KML y GeoRSS en una superposición de mosaicos de la API de Maps JavaScript.

Descripción general

La API de Maps JavaScript admite los formatos de datos KML y GeoRSS para mostrar información geográfica. Estos formatos de datos se muestran en un mapa con un objeto KmlLayer, cuyo constructor toma la URL de un archivo KML o GeoRSS de acceso público.

Nota: La clase KmlLayer que genera superposiciones KML en la API de Maps JavaScript usa un servicio alojado por Google a fin de recuperar y analizar archivos KML para su renderización. En consecuencia, solo es posible mostrar archivos KML si están alojados en una URL de acceso público que no requiere autenticación para acceder.

Si necesitas acceder a archivos privados, tener un control detallado del almacenamiento en caché o enviar el viewport del navegador a un servidor de datos geoespaciales como un parámetro de consulta, te recomendamos usar capas de datos en lugar de KmlLayer. Esto hará que los navegadores de los usuarios soliciten recursos directamente a tu servidor web.

La API de Maps JavaScript convierte los datos geográficos XML proporcionados en una representación KML que se muestra en el mapa mediante una superposición de mosaicos de la API de Maps JavaScript. Este KML tiene un aspecto (y, en cierta medida, un comportamiento) similar al de los elementos de superposición de la API de Maps JavaScript. Los elementos KML <Placemark> y GeoRSS point se renderizan como marcadores. Por ejemplo, los elementos <LineString> se renderizan como polilíneas y los elementos <Polygon>, como polígonos. De manera similar, los elementos <GroundOverlay> se renderizan como imágenes rectangulares en el mapa. No obstante, es importante destacar que estos objetos no son Markers, Polylines, Polygons ni GroundOverlays de la API de Maps JavaScript, sino que se renderizan en un solo objeto en el mapa.

Los objetos KmlLayer aparecerán en un mapa una vez que se haya configurado su propiedad map. Para quitarlos del mapa, llama a setMap() y pasa null. El objeto KmlLayer administra la renderización de estos elementos secundarios mediante la recuperación automática de los elementos correspondientes para los límites determinados del mapa. A medida que cambian los límites, los elementos del viewport actual se renderizan automáticamente.

Dado que los componentes de una KmlLayer se renderizan a pedido, la capa te permite administrar con facilidad la renderización de miles de marcadores, polilíneas y polígonos. Ten en cuenta que no puedes acceder a estos objetos constituyentes de forma directa, aunque cada uno de ellos proporciona eventos de clic que muestran datos sobre esos objetos individuales.

Opciones de capas KML

De manera opcional, el constructor KmlLayer() pasa una cantidad de KmlLayerOptions:

  • map especifica el Map en el que se renderizará la KmlLayer. Puedes ocultar una KmlLayer si configuras este valor en null en el método setMap().
  • preserveViewport especifica que el mapa no se debe ajustar a los límites del contenido de KmlLayer cuando se muestra la capa. De forma predeterminada, cuando se muestra una KmlLayer, el mapa se acerca y se posiciona para mostrar todo el contenido de la capa.
  • suppressInfoWindows indica que los elementos en los que se puede hacer clic en la KmlLayer no deben activar la visualización de objetos InfoWindow.

Además, una vez que se renderiza la KmlLayer, contiene una propiedad metadata inmutable que incluye el nombre, la descripción, el fragmento y el autor de la capa en un literal del objeto KmlLayerMetadata. Puedes inspeccionar esta información con el método getMetadata(). Debido a que la renderización de objetos KmlLayer requiere una comunicación asíncrona con un servidor externo, te recomendamos que escuches el evento metadata_changed, que indicará que la propiedad se propagó.

En el siguiente ejemplo, se construye una KmlLayer a partir del feed GeoRSS proporcionado:

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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>

Prueba la muestra

En el siguiente ejemplo, se construye una KmlLayer a partir del feed KML proporcionado:

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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>

Prueba la muestra

Detalles de los componentes KML

Debido a que KML puede incluir una gran cantidad de elementos, es posible que no puedas acceder a los datos de los elementos directamente desde el objeto KmlLayer. En su lugar, a medida que los elementos se muestran, se renderizan para que parezcan superposiciones de la API de Maps JavaScript en las que se puede hacer clic. De forma predeterminada, cuando haces clic en elementos individuales, aparece una InfoWindow con información de <title> y <description> de KML sobre el elemento correspondiente. Además, cuando se hace clic en un elemento KML, se genera un KmlMouseEvent que pasa la siguiente información:

  • position indica las coordenadas de latitud y longitud en las que se debe anclar la InfoWindow de este elemento KML. Esta posición generalmente corresponde a la ubicación en que se hace clic para polígonos, polilíneas y objetos GroundOverlay, y al origen real en el caso de los marcadores.
  • pixelOffset indica el desplazamiento desde la position anterior para anclar la "cola" de InfoWindow. En el caso de los objetos poligonales, este desplazamiento suele ser de 0,0, pero para los marcadores se incluye la altura.
  • featureData contiene una estructura JSON de KmlFeatureData.

A continuación, se incluye un objeto KmlFeatureData de muestra:

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

En el siguiente ejemplo, se muestra el texto del componente KML <Description> en un <div> lateral cuando se hace clic en el componente:

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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>

Prueba la muestra

Restricciones de tamaño y complejidad para la renderización de KML

La API de Maps JavaScript tiene limitaciones respecto del tamaño y la complejidad de los archivos KML cargados. A continuación, se ofrece un resumen de los límites actuales.

Nota: Estos límites están sujetos a cambios en cualquier momento.

Tamaño máximo del archivo recuperado (KML sin procesar, GeoRSS sin procesar o KMZ comprimido)
3 MB
Tamaño máximo del archivo KML sin comprimir
10 MB
Tamaño máximo del archivo de imagen sin comprimir en archivos KMZ
500 KB por archivo
Cantidad máxima de vínculos de red
10
Cantidad máxima de elementos totales de todo el documento
1,000
Cantidad de capas KML
Existe un límite para la cantidad de capas KML que se pueden mostrar en un mapa de Google Maps. Si se supera ese límite, ninguna de las capas aparecerá en el mapa y se informará un error en la Consola de JavaScript de tu navegador web. El límite se basa en una combinación de la cantidad de clases KmlLayer creadas y la longitud total de todas las URLs usadas para crear esas capas. Cada KmlLayer nueva que creas ocupa una parte del límite de la capa y una parte adicional del límite según la longitud de la URL desde la que se cargó el archivo KML. En consecuencia, la cantidad de capas que puedes agregar varía según la aplicación. En promedio, deberías poder cargar entre 10 y 20 capas sin alcanzar el límite. Si aun así alcanzas el límite, usa un acortador de URL para acortar las URLs de KML. También puedes crear un solo archivo KML que contenga NetworkLinks a las URLs individuales de KML.

Consideraciones de rendimiento y almacenamiento en caché

Los servidores de Google almacenarán en caché los archivos KML temporalmente para reducir la carga de tus servidores. Esto también mejorará el rendimiento para tus usuarios, ya que se publicará una representación eficiente en el espacio de los segmentos adecuados de tu archivo KML a medida que los usuarios hacen clic en el mapa, se desplazan lateralmente o hacen zoom.

Para obtener un mejor rendimiento, te recomendamos lo siguiente:

  • Usa una etiqueta <expires> adecuada en KML.

    KmlLayer no usará encabezados HTTP al decidir cómo almacenar en caché los archivos KML.
  • No generes archivos de forma dinámica en el momento de la solicitud.

    En su lugar, genera los archivos antes de que sean necesarios y publícalos de forma estática. Si tu servidor demora mucho tiempo en transmitir el archivo KML, es posible que no se muestre la KmlLayer.
  • No intentes omitir el almacenamiento en caché, a menos que sepas con certeza que tu archivo se actualizó.

    Omitir siempre el almacenamiento en caché (por ejemplo, agregando un número al azar o la hora del reloj del usuario como parámetro de consulta) puede causar que se saturen fácilmente tus servidores si tu sitio de repente se vuelve popular y publican archivos KML grandes.

    También puede provocar que la caché muestre datos inactivos a los usuarios, si el reloj de un usuario es incorrecto y la etiqueta <expires> no se configuró correctamente.

    En su lugar, publica archivos estáticos actualizados con un nuevo número de revisión discreto y usa código del servidor para actualizar de forma dinámica la URL que se pasa a KmlLayer con la versión actual.
  • Limita los cambios en tus archivos KML a una vez por minuto.

    Si todos los archivos tienen un tamaño superior a 1 MB (sin comprimir), limita los cambios a una vez cada 5 minutos.
  • Cuando uses un servidor de datos geoespaciales, evita usar parámetros de consulta para limitar el viewport de las capas.

    En su lugar, puedes limitar el viewport del mapa con el evento bounds_changed. Los usuarios solo recibirán elementos que se puedan mostrar automáticamente.

    Si hay una gran cantidad de datos en tu servidor de datos geoespaciales, considera usar capas de datos.
  • Cuando uses un servidor de datos geoespaciales, usa varias KmlLayer para cada grupo de elementos que desees que los usuarios puedan activar o desactivar, en lugar de una sola KmlLayer con diferentes parámetros de consulta.
  • Usa archivos KMZ comprimidos para reducir el tamaño del archivo.
  • Si usas Google Cloud Storage o alguna otra solución de almacenamiento en la nube, evita usar funciones como URLs firmadas o tokens temporales para aplicar los controles de acceso de manera forzosa. Estos pueden impedir involuntariamente el almacenamiento en caché.
  • Reduce la precisión de todos los puntos a una precisión adecuada.
  • Combina y simplifica la geometría de los elementos similares, como polígonos y polilíneas.
  • Quita los elementos o recursos de imagen que no se usen.
  • Quita todos los elementos no admitidos.

Si necesitas acceder a datos privados, evitar el almacenamiento en caché o enviar el viewport del navegador a un servidor de datos geoespaciales como un parámetro de consulta, te recomendamos usar capas de datos en lugar de KmlLayer. Esto hará que los navegadores de los usuarios soliciten recursos directamente a tu servidor web.

Elementos KML admitidos

La API de Maps JavaScript admite los siguientes elementos KML. El analizador de KML generalmente ignora de forma automática las etiquetas XML que no comprende.

  • Marcadores
  • Íconos
  • Carpetas
  • HTML descriptivo: Reemplazo de entidades mediante <BalloonStyle> y <text>
  • KMZ (KML comprimido, incluidas las imágenes adjuntas)
  • Polilíneas y polígonos
  • Diseños para polilíneas y polígonos, incluidos el color, el relleno y la opacidad
  • Vínculos de red para importar datos de forma dinámica
  • Superposiciones de suelo y superposiciones de pantalla

En la siguiente tabla, se proporcionan detalles completos de los elementos KML admitidos.

Elemento KML ¿Admitido en la API? Comentario
<address> no
<AddressDetails> no
<Alias> N/A No se admite <Model>.
<altitude> no
<altitudeMode> no
<atom:author>
<atom:link>
<atom:name>
<BalloonStyle> parcialmente Solo se admite <text>.
<begin> N/A No se admite <TimeSpan>.
<bgColor> no
<bottomFov> N/A No se admite <PhotoOverlay>.
<Camera> no
<Change> parcialmente Solo se admiten cambios de estilo.
<color> parcialmente Incluye #AABBGGRR y #BBGGRR; no se admite en <IconStyle>, <ScreenOverlay> y <GroundOverlay>.
<colorMode> no
<cookie> no
<coordinates>
<Create> no
<Data>
<Delete> no
<description> El contenido HTML está permitido, pero se depura para brindar protección en caso de ataques en diferentes navegadores. No se admiten los reemplazos de entidades con el formato $[dataName].
<displayMode> no
<displayName> no
<Document> parcialmente De forma implícita, se admiten los elementos secundarios. No tienen ningún efecto como campos secundarios de otros elementos.
<drawOrder> no
<east>
<end> N/A No se admite <TimeSpan>.
<expires> Consulta la sección Resumen para obtener información detallada.
<ExtendedData> parcialmente Solo <Data> sin tipo. No se admite <SimpleData> ni <Schema> ni los reemplazos de entidades con el formato $[dataName].
<extrude> no
<fill>
<flyToView> no
<Folder>
<geomColor> no obsoleto
<GeometryCollection> no obsoleto
<geomScale> no obsoleto
<gridOrigin> N/A No se admite <PhotoOverlay>.
<GroundOverlay> No se puede rotar.
<h> obsoleto
<heading>
hint Se admite target=....
<hotSpot>
<href>
<httpQuery> no
<Icon> No se puede rotar.
<IconStyle>
<ImagePyramid> N/A No se admite <PhotoOverlay>.
<innerBoundaryIs> Implícitamente, a partir del pedido <LinearRing>.
<ItemIcon> N/A No se admite <ListStyle>.
<key> N/A No se admite <StyleMap>.
<kml>
<labelColor> no obsoleto
<LabelStyle> no
<latitude>
<LatLonAltBox>
<LatLonBox>
<leftFov> N/A No se admite <PhotoOverlay>.
<LinearRing>
<LineString>
<LineStyle>
<Link>
<linkDescription> no
<linkName> no
<linkSnippet> no
<listItemType> N/A No se admite <ListStyle>.
<ListStyle> no
<Location> N/A No se admite <Model>.
<Lod>
<longitude>
<LookAt> no
<maxAltitude>
<maxFadeExtent>
<maxHeight> N/A No se admite <PhotoOverlay>.
<maxLodPixels>
<maxSessionLength> no
<maxWidth> N/A No se admite <PhotoOverlay>.
<message> no
<Metadata> no obsoleto
<minAltitude>
<minFadeExtent>
<minLodPixels>
<minRefreshPeriod> no <NetworkLink>
<Model> no
<MultiGeometry> parcialmente Se renderiza, pero se muestra como elementos independientes en el panel lateral izquierdo.
<name>
<near> N/A No se admite <PhotoOverlay>.
<NetworkLink>  
<NetworkLinkControl> parcialmente <Update> y <expires> se admiten parcialmente. La API ignora la configuración de vencimiento en los encabezados HTTP, pero usa la configuración de vencimiento especificada en KML. Ante la ausencia de una configuración de vencimiento, o dentro del intervalo de validez, Google Maps puede almacenar en caché los datos obtenidos de Internet durante períodos indefinidos. Para forzar una nueva recuperación de datos de Internet, puedes cambiar el nombre del documento y recuperarlo a través de una URL diferente, o bien puedes asegurarte de que el documento contenga la configuración de vencimiento adecuada.
<north>
<open>
<Orientation> N/A No se admite <Model>.
<outerBoundaryIs> Implícitamente, a partir del pedido <LinearRing>.
<outline>
<overlayXY> no
<Pair> N/A No se admite <StyleMap>.
<phoneNumber> no
<PhotoOverlay> no
<Placemark>
<Point>
<Polygon>
<PolyStyle>
<range>
<refreshInterval> parcialmente Solo se admite en <Link>, no en <Icon>.
<refreshMode> Los encabezados HTTP no se admiten para el modo "onExpire". Consulta las notas anteriores sobre <Update> y <expires>.
<refreshVisibility> no
<Region>
<ResourceMap> N/A No se admite <Model>.
<rightFov> N/A No se admite <PhotoOverlay>.
<roll> N/A No se admiten <Camera> ni <Model>.
<rotation> no
<rotationXY> no
<Scale> N/A No se admite <Model>.
<scale> no
<Schema> no
<SchemaData> no
<ScreenOverlay> No se puede rotar.
<screenXY> no
<shape> N/A No se admite <PhotoOverlay>.
<SimpleData> N/A No se admite <SchemaData>.
<SimpleField> N/A No se admite <Schema>.
<size>
<Snippet>
<south>
<state> N/A No se admite <ListStyle>.
<Style>
<StyleMap> no No se admiten efectos de desplazamiento (destacado).
<styleUrl> N/A No se admite <StyleMap>.
<targetHref> parcialmente Se admite en <Update>, no en <Alias>.
<tessellate> no
<text> No se admite el reemplazo de $[geDirections].
<textColor> no
<tileSize> N/A No se admite <PhotoOverlay>.
<tilt> no
<TimeSpan> no
<TimeStamp> no
<topFov> N/A No se admite <PhotoOverlay>.
<Update> parcialmente Solo se admiten cambios de diseño; se excluyen <Create> y <Delete>.
<Url> obsoleto
<value>
<viewBoundScale> no
<viewFormat> no
<viewRefreshMode> parcialmente Se admite "onStop".
<viewRefreshTime>
<ViewVolume> N/A No se admite <PhotoOverlay>.
<visibility> parcialmente Se admite en <Folder>; los marcadores secundarios heredan su visibilidad.
<w> obsoleto
<west>
<when> N/A No se admite <TimeStamp>.
<width>
<x> obsoleto
<y> obsoleto