Capas KML y GeoRSS

Selecciona la plataforma: Android iOS JavaScript

El objeto 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. Ambos formatos se muestran en el mapa usando un objeto KmlLayer, cuyo constructor toma la URL de un archivo KML o GeoRSS accesible públicamente.

Nota: La clase KmlLayer que genera superposiciones KML en la API de Maps JavaScript utiliza un servicio alojado por Google para recuperar y analizar archivos KML para su renderización. En consecuencia, solo es posible mostrar archivos KML si se encuentran alojados en una URL accesible públicamente que no requiere autenticación para el acceso.

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 que utilices capas de datos en lugar de KmlLayer. De esta forma, los navegadores de los usuarios recibirán la instrucción de solicitar recursos directamente de tu servidor web.

La API de Maps JavaScript convierte los datos XML geográficos proporcionados en una representación KML que se muestra en el mapa mediante una superposición de mosaicos de la API de Maps JavaScript. Esa representación KML se ve (y, en cierta medida, se comporta) como los elementos conocidos de superposiciones 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, mientras que los elementos <Polygon>, como polígonos. Del mismo modo, los elementos <GroundOverlay> se renderizan como imágenes rectangulares en el mapa. Sin embargo, 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 aparecen en el mapa después de que se configura su propiedad map. Para quitarlos del mapa, debes llamar a setMap() y pasar null. Para administrar la renderización de estos elementos secundarios, el objeto KmlLayer recupera de forma automática los componentes adecuados dentro de los límites específicos del mapa. A medida que cambian los límites, los componentes del viewport actual se renderizan automáticamente.

Dado que los componentes de un objeto KmlLayer se renderizan bajo demanda, 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, pero sí admiten eventos de clic que muestran datos sobre cada uno de ellos.

Opciones de capas KML

Si lo deseas, puedes pasar ciertas KmlLayerOptions en el constructor KmlLayer():

  • map especifica el Map en el que se debe renderizar el objeto KmlLayer. Puedes ocultar un objeto 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 del objeto KmlLayer cuando se muestre la capa. De forma predeterminada, cuando se muestra un objeto KmlLayer, el mapa se acerca y se posiciona para mostrar todo el contenido de la capa.
  • suppressInfoWindows indica que los componentes que admiten la posibilidad de hacer clics dentro del objeto KmlLayer no deben activar la visualización de objetos InfoWindow.

Además, una vez que se renderiza, el objeto KmlLayer contiene una propiedad metadata inmutable que incluye el nombre, la descripción, el fragmento y el autor de la capa dentro de un literal de 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 se completaron los datos de la propiedad.

En el siguiente ejemplo, se construye un objeto KmlLayer a partir del feed de 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 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>

Prueba la muestra

En el siguiente ejemplo, se construye un objeto KmlLayer a partir del feed de 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 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>

Prueba la muestra

Detalles de los componentes KML

Dado que el formato KML puede incluir una gran cantidad de componentes, no puedes acceder a los datos de los componentes directamente desde el objeto KmlLayer. Aun así, a medida que se muestran los componentes, se renderizan con el aspecto de superposiciones de la API de Maps JavaScript que admiten la posibilidad de hacer clics. De forma predeterminada, cuando se hace clic en componentes individuales, aparece un objeto InfoWindow con la información de <title> y <description> en formato KML para el componente específico. Además, el clic en un componente KML genera un KmlMouseEvent, que pasa la siguiente información:

  • position: Indica las coordenadas de latitud y longitud en las que se debe anclar el objeto InfoWindow para ese componente KML. Para los polígonos, las polilíneas y los objetos GroundOverlay, esta posición suele ser la ubicación en la que se hace clic; en cambio, para los marcadores, indica el verdadero origen.
  • pixelOffset: Indica el desplazamiento desde la position anterior para anclar la "cola" del objeto InfoWindow. Para los objetos poligonales, ese desplazamiento suele ser 0,0, pero, para los marcadores, incluye la altura.
  • featureData: Contiene una estructura JSON de KmlFeatureData.

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

{
  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 de <Description> del componente KML 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 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>

Prueba la muestra

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

La API de Maps JavaScript tiene limitaciones en cuanto al 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 componentes en 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 solo mapa de Google. Si se supera ese límite, no se mostrará ninguna capa en el mapa, y se notificará 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 objeto KmlLayer nuevo que creas consume una porción del límite de la capa y una porción 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 variará según la aplicación. En promedio, deberías poder cargar entre 10 y 20 capas sin alcanzar el límite. Si alcanzas el límite, puedes usar un acortador de URLs para acortar las URLs de KML. También puedes crear un solo archivo KML que contenga los NetworkLinks a las URLs individuales de KML.

Consideraciones de rendimiento y almacenamiento en caché

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

Para lograr el mejor rendimiento, te recomendamos lo siguiente:

  • Usa una etiqueta <expires> adecuada en el archivo KML.

    El objeto 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 tarda mucho tiempo en transmitir el archivo KML, es posible que no se muestre el objeto KmlLayer.
  • No intentes evitar el almacenamiento en caché, salvo que sepas con certeza que tu archivo se actualizó.

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

    También puede provocar que la caché entregue datos inactivos a los usuarios si el reloj de algún 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 al objeto KmlLayer con la versión actual.
  • Limita los cambios de tus archivos KML a una vez por minuto.

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

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

    Si hay una gran cantidad de datos en tu servidor de datos geoespaciales, considera usar capas de datos en su lugar.
  • Cuando uses un servidor de datos geoespaciales, agrega varios objetos KmlLayer para cada grupo de componentes que desees que los usuarios puedan activar o desactivar, en lugar de utilizar un solo objeto KmlLayer con diferentes parámetros de consulta.
  • Para reducir el tamaño de los archivos, usa archivos KMZ comprimidos.
  • Si usas Google Cloud Storage o alguna otra solución de almacenamiento en la nube, evita utilizar funciones como URLs firmadas o tokens temporales para aplicar controles de acceso, Estas pueden impedir el almacenamiento en caché de manera no intencional.
  • Reduce la precisión de todos los puntos hasta alcanzar un nivel de precisión adecuado.
  • Combina y simplifica la geometría de componentes similares, como polígonos y polilíneas.
  • Quita los elementos o recursos de imagen que no se utilicen.
  • Quita los elementos no compatibles.

Si necesitas acceder a datos privados, evitar el almacenamiento en caché o enviar el viewport del navegador a un servidor de datos geoespaciales como parámetro de consulta, te recomendamos que uses capas de datos en lugar del objeto KmlLayer. De esta forma, los navegadores de los usuarios recibirán la instrucción de solicitar recursos directamente de tu servidor web.

Elementos KML admitidos

La API de Maps JavaScript admite los siguientes elementos KML. En general, el analizador de KML ignora de forma automática las etiquetas XML si no puede interpretarlas.

  • 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 de pantalla

En la siguiente tabla, se proporciona la información detallada de los elementos KML admitidos.

Elemento KML ¿Se admite en la API? Explicación
<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> ni <GroundOverlay>.
<colorMode> no
<cookie> no
<coordinates>
<Create> no
<Data>
<Delete> no
<description> El contenido HTML está permitido, pero se depura para brindar protección contra ataques en navegadores. No se admiten reemplazos de entidades con el formato $[dataName].
<displayMode> no
<displayName> no
<Document> parcialmente Se admiten elementos secundarios de forma implícita. No tiene efecto como elemento secundario de otros componentes.
<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 admiten <SimpleData> ni <Schema>, como tampoco 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 girar.
<h> obsoleto
<heading>
hint Se admite target=....
<hotSpot>
<href>
<httpQuery> no
<Icon> No se puede girar.
<IconStyle>
<ImagePyramid> N/A No se admite <PhotoOverlay>.
<innerBoundaryIs> Se admite de forma implícita a partir del orden de <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 componentes independientes en el panel lateral izquierdo.
<name>
<near> N/A No se admite <PhotoOverlay>.
<NetworkLink>  
<NetworkLinkControl> parcialmente Se admiten <Update> y <expires> parcialmente. La API ignora la configuración de vencimiento en los encabezados de HTTP, pero usa la especificada en KML. Ante la ausencia de una configuración de vencimiento, o dentro del intervalo de validez, Google Maps puede almacenar en caché datos recuperados 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 correcta.
<north>
<open>
<Orientation> N/A No se admite <Model>.
<outerBoundaryIs> Se admite de forma implícita a partir del orden de <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 girar.
<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 (destacar contenido).
<styleUrl> N/A No se admite <StyleMap>.
<targetHref> parcialmente Se admite en <Update>, pero no en <Alias>.
<tessellate> no
<text> No se admite en 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, pero 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 Sí en <Folder>; los marcadores secundarios heredan su visibilidad.
<w> obsoleto
<west>
<when> N/A No se admite <TimeStamp>.
<width>
<x> obsoleto
<y> obsoleto