O KmlLayer
renderiza elementos KML e GeoRSS em uma sobreposição de blocos da API Maps JavaScript.
Visão geral
A API Maps JavaScript é compatível com os formatos de dados KML e GeoRSS para exibição de informações geográficas. Esses formatos de dados são mostrados em um mapa por meio de um objeto KmlLayer
, cujo construtor obtém o URL de um arquivo KML ou GeoRSS acessível publicamente.
Observação: a classe KmlLayer
que gera sobreposições de KML na API Maps JavaScript usa um serviço hospedado pelo Google para recuperar e analisar arquivos KML para renderização.
Por isso, só é possível mostrar arquivos KML se eles estiverem hospedados em um URL acessível publicamente que não exige autenticação para ser acessado.
Se você precisar de acesso a arquivos particulares, controle detalhado sobre os caches ou enviar a janela de visualização do navegador a um servidor de dados geoespaciais como um parâmetro de consulta,
recomendamos o uso de camadas de dados, em vez de KmlLayer
. Isso fará com que os navegadores dos usuários solicitem recursos do seu servidor da Web.
A API Maps JavaScript converte os dados XML geográficos fornecidos em uma representação KML que é exibida no mapa usando uma sobreposição de blocos da API Maps JavaScript. Esse KML parece (e de alguma forma se comporta) como elementos conhecidos de sobreposição da API Maps JavaScript. Os elementos KML <Placemark>
e GeoRSS point
são renderizados como marcadores. Por exemplo, elementos <LineString>
são renderizados como polilinhas e elementos <Polygon>
são renderizados como polígonos. Da mesma forma, os elementos <GroundOverlay>
são renderizados como imagens retangulares no mapa. É importante ressaltar, no entanto, que esses objetos não são da API Maps JavaScript Markers
, Polylines
, Polygons
ou GroundOverlays
. Em vez disso, eles são renderizados em um único objeto no mapa.
Os objetos KmlLayer
aparecem no mapa depois que suas propriedades map
são definidas. Você pode remover esse itens do mapa chamando o setMap()
e passando null
. O objeto KmlLayer
gerencia a renderização desses elementos filhos recuperando automaticamente os recursos apropriados para os limites do mapa. À medida que os limites mudam, os recursos da porta de visualização atual são automaticamente renderizados.
Como os componentes dentro de um KmlLayer
são mostrados sob demanda, a camada permite que você gerencie facilmente o processamento de milhares de marcadores, polilinhas e polígonos. Não é possível acessar esses objetos envolvidos diretamente, embora todos ofereçam eventos de clique que retornam dados sobre cada um individualmente.
Opções de camada KML
O construtor KmlLayer()
pode passar vários KmlLayerOptions
:
- O
map
especifica oMap
em que oKmlLayer
deve aparecer. Você pode ocultar umKmlLayer
definindo esse valor comonull
dentro do métodosetMap()
. - O
preserveViewport
especifica que o mapa não deve ser ajustado para os limites do conteúdo doKmlLayer
ao mostrar a camada. Por padrão, ao exibir umKmlLayer
, o mapa é ampliado e posicionado para mostrar todo o conteúdo da camada. - O
suppressInfoWindows
indica que os elementos clicáveis noKmlLayer
não devem iniciar a exibição de objetosInfoWindow
.
Além disso, após ser exibido, o KmlLayer
contém uma propriedade metadata
imutável, com o nome, a descrição, o snippet e o autor da camada dentro de um literal do objeto KmlLayerMetadata
. Você pode inspecionar essas informações usando o método getMetadata()
. Como a exibição de objetos KmlLayer
requer comunicação assíncrona com um servidor externo, use uma escuta para o evento metadata_changed
, que vai mostrar quando a propriedade for preenchida.
O exemplo abaixo constrói um KmlLayer
a partir do feed GeoRSS fornecido:
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>
Testar amostra
O exemplo abaixo constrói um objeto KmlLayer
com base no feed KML enviado:
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>
Testar amostra
Detalhes de elemento KML
Como o formato KML pode incluir vários elementos, talvez não seja possível acessar dados de elementos diretamente a partir do objeto KmlLayer
. Em vez disso, conforme os elementos são mostrados, eles são processados para que se pareçam com superposições clicáveis da API do Google Maps.
Se você clicar em elementos individuais, vai acessar, por padrão, um InfoWindow
contendo informações <title>
e <description>
do KML sobre o elemento especificado.
Além disso, se você clicar em um elemento KML, será gerado um KmlMouseEvent
que vai passar as seguintes informações:
position
indica as coordenadas de latitude/longitude da posição em que oInfoWindow
será ancorado para esse elemento KML. Essa posição normalmente é a localização clicada para polígonos, polilinhas e GroundOverlays. Para marcadores, é a origem verdadeira.pixelOffset
indica o deslocamento do item acima deposition
para fixar a "cauda" doInfoWindow
. Para objetos poligonais, esse deslocamento normalmente é0,0
, mas, para marcadores, ele inclui a altura.featureData
contém uma estrutura JSON doKmlFeatureData
.
Veja abaixo um exemplo do objeto KmlFeatureData
:
{ author: { email: "nobody@google.com", name: "Mr Nobody", uri: "http://example.com" }, description: "description", id: "id", infoWindowHtml: "html", name: "name", snippet: "snippet" }
O exemplo abaixo mostra o texto de <Description>
do elemento KML, dentro de um <div>
lateral quando o elemento é clicado:
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>
Testar amostra
Restrições de complexidade e tamanho para renderização de KML
A API Maps JavaScript tem limitações no tamanho e na complexidade dos arquivos KML carregados. Veja um resumo dos limites atuais abaixo:
Observação: esses limites estão sujeitos a mudanças a qualquer momento.
- Tamanho máximo do arquivo obtido (KML bruto, GeoRSS bruto ou KMZ compactado)
- 3 MB
- Tamanho máximo do arquivo KML descompactado
- 10 MB
- Tamanho máximo do arquivo de imagem não compactado em arquivos KMZ
- 500 KB por arquivo
- Número máximo de Links de rede
- 10
- Número máximo de recursos do tamanho total do documento
- 1.000
- Número de camadas KML
- Há um limite no número de Camadas KML que podem aparecer em um único Google Map. Se você exceder este limite, nenhuma das suas camadas aparecerão no mapa e um erro será informado ao console JavaScript do navegador da Web. O limite se baseia em uma combinação de números das classes
KmlLayer
criadas e no comprimento total de todos os URLs usados para criar essas camadas. Cada novaKmlLayer
que você cria toma uma porção do limite para a camada e uma porção a mais do limite, dependendo do comprimento do URL de onde o arquivo KML foi carregado. Consequentemente, o número de camadas que você pode adicionar varia com o aplicativo; em média, é possível carregar entre 10 e 20 camadas sem exceder o limite. Se você ainda atingir o limite, use um encurtador de URL para reduzir os URLs KML. Como alternativa, crie um único arquivo KML que consiste em NetworkLinks para os URLs de KML individuais.
Considerações sobre performance e armazenamento em cache
Os servidores do Google armazenam temporariamente os arquivos KML em cache para reduzir a carga dos seus. Isso também melhora a performance dos usuários, mostrando uma representação com eficiência de espaço dos segmentos apropriados no arquivo KML, à medida que os usuários clicam, movimentam e aplicam zoom ao mapa.
Para alcançar os melhores resultados, recomendamos que você faça o seguinte:
- Use uma tag
<expires>
adequada em KML.
OKmlLayer
não usa cabeçalhos HTTP para decidir como armazenar arquivos KML em cache. - Não gere arquivos dinamicamente no momento da solicitação.
Faça isso antes que eles sejam necessários e adote a veiculação estática. Se o servidor demorar muito para transmitir o arquivo KML, talvez oKmlLayer
não apareça. - Não tente ignorar os caches, a menos que você saiba de maneira definitiva que seu arquivo foi atualizado.
Ignorar sempre os caches (por exemplo, anexando um número aleatório ou o horário do relógio do usuário como um parâmetro de consulta) pode facilmente sobrecarregar seus servidores se o site se tornar conhecido de repente e você disponibilizar arquivos KML grandes.
Isso também pode fazer com que o cache veicule dados desatualizados para os usuários, se o relógio deles estiver incorreto e a tag<expires>
não tiver sido definida corretamente.
Em vez disso, publique os arquivos estáticos atualizados com um novo número de revisão e use o código do lado do servidor para atualizar dinamicamente o URL transmitido paraKmlLayer
com a versão atual. - Faça mudanças nos arquivos KML apenas uma vez por minuto.
Se todos os arquivos tiverem mais de 1 MB (não compactados), defina o limite de uma mudança a cada 5 minutos. - Ao usar um servidor de dados geoespaciais, evite usar parâmetros de consulta para limitar a janela de visualização das camadas.
Em vez disso, você pode limitar a janela de visualização do mapa com o eventobounds_changed
. Os usuários só vão receber recursos que podem aparecer automaticamente.
Se houver uma grande quantidade de dados no servidor de dados geoespaciais, considere usar as camadas de dados. - Ao usar um servidor de dados geoespaciais, use vários
KmlLayer
s para cada grupo de recursos que você quer permitir aos usuários adotar de maneira alternada, em vez de um únicoKmlLayer
com parâmetros de consulta diferentes. - Use arquivos KMZ compactados para reduzir o tamanho do arquivo.
- Se você estiver usando o Google Cloud Storage ou outra solução de armazenamento em nuvem, evite recursos como URLs assinados ou tokens temporários para utilizar os controles de acesso. Isso pode impedir involuntariamente o armazenamento em cache.
- Ajuste todos os pontos para uma precisão apropriada.
- Mescle e simplifique a geometria de recursos semelhantes, como polígonos e polilinhas.
- Remova todos os elementos ou recursos de imagem não utilizados.
- Remova todos os elementos não compatíveis.
Caso você precise acessar dados particulares, impedir o armazenamento em cache ou enviar a janela de visualização do navegador a um servidor de dados geoespaciais como um parâmetro de consulta, recomendamos o uso de camadas de dados em vez de KmlLayer
. Isso vai fazer com que os navegadores dos usuários solicitem recursos do seu servidor da Web.
Elementos KML suportados
A API Maps JavaScript é compatível com os elementos KML citados a seguir. O analisador de KML ignora silenciosamente, geralmente, tags XML que não entende.
- Marcadores
- Ícones
- Pastas
- HTML descritivo: substituição de entidade via <BalloonStyle> e <text>
- KMZ (KML compactado, incluindo imagens anexadas)
- Polilinhas e polígonos
- Estilos para polilinhas e polígonos, incluindo cor, preenchimento e opacidade
- Links de rede para importar dados dinamicamente
- Sobreposições de solo e sobreposições de tela
A tabela a seguir fornece detalhes completos dos elementos KML compatíveis.
Elemento KML | Compatível na API? | Comentário |
---|---|---|
<address> | não | |
<AddressDetails> | não | |
<Alias> | N/A | <Model> não é compatível |
<altitude> | não | |
<altitudeMode> | não | |
<atom:author> | sim | |
<atom:link> | sim | |
<atom:name> | sim | |
<BalloonStyle> | parcialmente | somente <text> é compatível |
<begin> | N/A | <TimeSpan> não é compatível |
<bgColor> | não | |
<bottomFov> | N/A | <PhotoOverlay> não é compatível |
<Camera> | não | |
<Change> | parcialmente | somente mudanças de estilo são aceitas |
<color> | parcialmente | inclui #AABBGGRR e #BBGGRR, não são compatíveis em <IconStyle>, <ScreenOverlay> e <GroundOverlay> |
<colorMode> | não | |
<cookie> | não | |
<coordinates> | sim | |
<Create> | não | |
<Data> | sim | |
<Delete> | não | |
<description> | sim | O conteúdo do HTML é compatível, mas é verificado para proteger contra ataques entre navegadores. Não é possível substituir entidades da forma $[dataName] . |
<displayMode> | não | |
<displayName> | não | |
<Document> | parcialmente | implicitamente, filhos não são compatíveis; nenhum efeito como filho de outros Recursos |
<drawOrder> | não | |
<east> | sim | |
<end> | N/A | <TimeSpan> não é compatível |
<expires> | sim | consulte a seção "Resumo" para mais detalhes |
<ExtendedData> | parcialmente | somente <Data> não digitados, sem <SimpleData> ou <Schema>, e substituições de entidades da forma $[dataName] não são compatíveis.
|
<extrude> | não | |
<fill> | sim | |
<flyToView> | não | |
<Folder> | sim | |
<geomColor> | não | descontinuado |
<GeometryCollection> | não | descontinuado |
<geomScale> | não | descontinuado |
<gridOrigin> | N/A | <PhotoOverlay> não é compatível |
<GroundOverlay> | sim | não pode ser girado |
<h> | sim | descontinuado |
<heading> | sim | |
<hint> | sim | target=... compatível |
<hotSpot> | sim | |
<href> | sim | |
<httpQuery> | não | |
<Icon> | sim | não pode ser girado |
<IconStyle> | sim | |
<ImagePyramid> | N/A | <PhotoOverlay> não é compatível |
<innerBoundaryIs> | sim | implicitamente a partir da ordem de <LinearRing> |
<ItemIcon> | N/A | <ListStyle> não é compatível |
<key> | N/A | <StyleMap> não é suportado |
<kml> | sim | |
<labelColor> | não | descontinuado |
<LabelStyle> | não | |
<latitude> | sim | |
<LatLonAltBox> | sim | |
<LatLonBox> | sim | |
<leftFov> | N/A | <PhotoOverlay> não é compatível |
<LinearRing> | sim | |
<LineString> | sim | |
<LineStyle> | sim | |
<Link> | sim | |
<linkDescription> | não | |
<linkName> | não | |
<linkSnippet> | não | |
<listItemType> | N/A | <ListStyle> não é compatível |
<ListStyle> | não | |
<Location> | N/A | <Model> não é compatível |
<Lod> | sim | |
<longitude> | sim | |
<LookAt> | não | |
<maxAltitude> | sim | |
<maxFadeExtent> | sim | |
<maxHeight> | N/A | <PhotoOverlay> não é compatível |
<maxLodPixels> | sim | |
<maxSessionLength> | não | |
<maxWidth> | N/A | <PhotoOverlay> não é compatível |
<message> | não | |
<Metadata> | não | descontinuado |
<minAltitude> | sim | |
<minFadeExtent> | sim | |
<minLodPixels> | sim | |
<minRefreshPeriod> | não | <NetworkLink> |
<Model> | não | |
<MultiGeometry> | parcialmente | renderizado, mas mostrado como recursos separados no painel do lado esquerdo |
<name> | sim | |
<near> | N/A | <PhotoOverlay> não é compatível |
<NetworkLink> | sim | |
<NetworkLinkControl> | parcialmente | <Update> e <expires> parcialmente compatíveis. A API ignora as configurações de expiração nos cabeçalhos HTTP, mas não usa as configurações de expiração especificadas no KML. Na ausência de configurações de expiração ou dentro do intervalo de validade, o Google Maps pode armazenar em cache os dados obtidos da Internet por durações não especificadas. Uma nova busca de dados da Internet pode ser forçada renomeando e obtendo o documento com um URL diferente, ou garantindo que o documento contenha configurações de expiração adequadas. |
<north> | sim | |
<open> | sim | |
<Orientation> | N/A | <Model> não é compatível |
<outerBoundaryIs> | sim | implicitamente a partir da ordem de <LinearRing> |
<outline> | sim | |
<overlayXY> | não | |
<Pair> | N/A | <StyleMap> não é suportado |
<phoneNumber> | não | |
<PhotoOverlay> | não | |
<Placemark> | sim | |
<Point> | sim | |
<Polygon> | sim | |
<PolyStyle> | sim | |
<range> | sim | |
<refreshInterval> | parcialmente | somente <Link>; não em <Icon> |
<refreshMode> | sim | Os cabeçalhos HTTP não são compatíveis com o modo "onExpire". Veja as observações sobre <Update> e <expires> acima. |
<refreshVisibility> | não | |
<Region> | sim | |
<ResourceMap> | N/A | <Model> não é compatível |
<rightFov> | N/A | <PhotoOverlay> não é compatível |
<roll> | N/A | <Camera> e <Model> não são compatíveis |
<rotation> | não | |
<rotationXY> | não | |
<Scale> | N/A | <Model> não é compatível |
<scale> | não | |
<Schema> | não | |
<SchemaData> | não | |
<ScreenOverlay> | sim | não pode ser girado |
<screenXY> | não | |
<shape> | N/A | <PhotoOverlay> não é compatível |
<SimpleData> | N/A | <SchemaData> não é compatível |
<SimpleField> | N/A | <Schema> não é compatível |
<size> | sim | |
<Snippet> | sim | |
<south> | sim | |
<state> | N/A | <ListStyle> não é compatível |
<Style> | sim | |
<StyleMap> | não | efeitos de rollover (destaque) não são suportados |
<styleUrl> | N/A | <StyleMap> não é suportado |
<targetHref> | parcialmente | suportado no <Update>, não no <Alias> |
<tessellate> | não | |
<text> | sim | não é possível substituir $[geDirections] |
<textColor> | não | |
<tileSize> | N/A | <PhotoOverlay> não é compatível |
<tilt> | não | |
<TimeSpan> | não | |
<TimeStamp> | não | |
<topFov> | N/A | <PhotoOverlay> não é compatível |
<Update> | parcialmente | somente alterações de estilo, não <Create> ou <Delete> |
<Url> | sim | descontinuado |
<value> | sim | |
<viewBoundScale> | não | |
<viewFormat> | não | |
<viewRefreshMode> | parcialmente | "onStop" é suportado |
<viewRefreshTime> | sim | |
<ViewVolume> | N/A | <PhotoOverlay> não é compatível |
<visibility> | parcialmente | sim, em <Folder> - marcadores filhos herdam a visibilidade |
<w> | sim | descontinuado |
<west> | sim | |
<when> | N/A | <TimeStamp> não é compatível |
<width> | sim | |
<x> | sim | descontinuado |
<y> | sim | descontinuado |