Camadas KML e GeoRSS

Selecione a plataforma: Android iOS JavaScript

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 o Map em que o KmlLayer deve aparecer. Você pode ocultar um KmlLayer definindo esse valor como null dentro do método setMap().
  • O preserveViewport especifica que o mapa não deve ser ajustado para os limites do conteúdo do KmlLayer ao mostrar a camada. Por padrão, ao exibir um KmlLayer, o mapa é ampliado e posicionado para mostrar todo o conteúdo da camada.
  • O suppressInfoWindows indica que os elementos clicáveis no KmlLayer não devem iniciar a exibição de objetos InfoWindow.

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

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

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 o InfoWindow 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 de position para fixar a "cauda" do InfoWindow. Para objetos poligonais, esse deslocamento normalmente é 0,0, mas, para marcadores, ele inclui a altura.
  • featureData contém uma estrutura JSON do KmlFeatureData.

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

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 nova KmlLayer 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.

    O KmlLayer 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 o KmlLayer 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 para KmlLayer 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 evento bounds_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 KmlLayers para cada grupo de recursos que você quer permitir aos usuários adotar de maneira alternada, em vez de um único KmlLayer 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