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 elMap
en el que se debe renderizar el objetoKmlLayer
. Puedes ocultar un objetoKmlLayer
si configuras este valor ennull
en el métodosetMap()
.preserveViewport
especifica que el mapa no se debe ajustar a los límites del contenido del objetoKmlLayer
cuando se muestre la capa. De forma predeterminada, cuando se muestra un objetoKmlLayer
, 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 objetoKmlLayer
no deben activar la visualización de objetosInfoWindow
.
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 objetoInfoWindow
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 laposition
anterior para anclar la "cola" del objetoInfoWindow
. Para los objetos poligonales, ese desplazamiento suele ser0,0
, pero, para los marcadores, incluye la altura.featureData
: Contiene una estructura JSON deKmlFeatureData
.
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 objetoKmlLayer
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 objetoKmlLayer
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 objetoKmlLayer
. - 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 objetoKmlLayer
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 eventobounds_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 objetoKmlLayer
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> | sí | |
<atom:link> | sí | |
<atom:name> | sí | |
<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> | sí | |
<Create> | no | |
<Data> | sí | |
<Delete> | no | |
<description> | sí | 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> | sí | |
<end> | N/A | No se admite <TimeSpan>. |
<expires> | sí | 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> | sí | |
<flyToView> | no | |
<Folder> | sí | |
<geomColor> | no | obsoleto |
<GeometryCollection> | no | obsoleto |
<geomScale> | no | obsoleto |
<gridOrigin> | N/A | No se admite <PhotoOverlay>. |
<GroundOverlay> | sí | No se puede girar. |
<h> | sí | obsoleto |
<heading> | sí | |
hint | sí | Se admite target=... . |
<hotSpot> | sí | |
<href> | sí | |
<httpQuery> | no | |
<Icon> | sí | No se puede girar. |
<IconStyle> | sí | |
<ImagePyramid> | N/A | No se admite <PhotoOverlay>. |
<innerBoundaryIs> | sí | 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> | sí | |
<labelColor> | no | obsoleto |
<LabelStyle> | no | |
<latitude> | sí | |
<LatLonAltBox> | sí | |
<LatLonBox> | sí | |
<leftFov> | N/A | No se admite <PhotoOverlay>. |
<LinearRing> | sí | |
<LineString> | sí | |
<LineStyle> | sí | |
<Link> | sí | |
<linkDescription> | no | |
<linkName> | no | |
<linkSnippet> | no | |
<listItemType> | N/A | No se admite <ListStyle>. |
<ListStyle> | no | |
<Location> | N/A | No se admite <Model>. |
<Lod> | sí | |
<longitude> | sí | |
<LookAt> | no | |
<maxAltitude> | sí | |
<maxFadeExtent> | sí | |
<maxHeight> | N/A | No se admite <PhotoOverlay>. |
<maxLodPixels> | sí | |
<maxSessionLength> | no | |
<maxWidth> | N/A | No se admite <PhotoOverlay>. |
<message> | no | |
<Metadata> | no | obsoleto |
<minAltitude> | sí | |
<minFadeExtent> | sí | |
<minLodPixels> | sí | |
<minRefreshPeriod> | no | <NetworkLink> |
<Model> | no | |
<MultiGeometry> | parcialmente | Se renderiza, pero se muestra como componentes independientes en el panel lateral izquierdo. |
<name> | sí | |
<near> | N/A | No se admite <PhotoOverlay>. |
<NetworkLink> | sí | |
<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> | sí | |
<open> | sí | |
<Orientation> | N/A | No se admite <Model>. |
<outerBoundaryIs> | sí | Se admite de forma implícita a partir del orden de <LinearRing>. |
<outline> | sí | |
<overlayXY> | no | |
<Pair> | N/A | No se admite <StyleMap>. |
<phoneNumber> | no | |
<PhotoOverlay> | no | |
<Placemark> | sí | |
<Point> | sí | |
<Polygon> | sí | |
<PolyStyle> | sí | |
<range> | sí | |
<refreshInterval> | parcialmente | Solo se admite en <Link>, no en <Icon>. |
<refreshMode> | sí | Los encabezados HTTP no se admiten para el modo "onExpire"; Consulta las notas anteriores sobre <Update> y <expires>. |
<refreshVisibility> | no | |
<Region> | sí | |
<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> | sí | 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> | sí | |
<Snippet> | sí | |
<south> | sí | |
<state> | N/A | No se admite <ListStyle>. |
<Style> | sí | |
<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> | sí | 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> | sí | obsoleto |
<value> | sí | |
<viewBoundScale> | no | |
<viewFormat> | no | |
<viewRefreshMode> | parcialmente | Se admite "onStop". |
<viewRefreshTime> | sí | |
<ViewVolume> | N/A | No se admite <PhotoOverlay>. |
<visibility> | parcialmente | Sí en <Folder>; los marcadores secundarios heredan su visibilidad. |
<w> | sí | obsoleto |
<west> | sí | |
<when> | N/A | No se admite <TimeStamp>. |
<width> | sí | |
<x> | sí | obsoleto |
<y> | sí | obsoleto |