Back-End

21 jan, 2008

Google Maps API

Publicidade

Neste artigo apresentaremos a Google Maps API v2 e desenvolveremos passo-a-passo um sistema de geolocalização de endereços via Javascript. Além de poder integrar ao seu site um mapa com os mesmos recursos que o Google Maps oferece, você aprenderá a resolver consultas ambígüas que retornam múltiplas coordenadas, através da liguagem Javascript.

Pré-requisitos: Estar familiarizado (a nível de usuário) com a interface apresentada pela ferramenta Google Maps; possuir conhecimentos intermediários de HTML e Javascript.

Objetivos

Ao final desse artigo, espera-se que o leitor seja capaz de:

  • Obter sua própria chave para uso da API em seu site pessoal;
  • Compreender o propósito e o funcionamento geral da API;
  • Implementar um geocodificador que permite a tradução de endereços em coordenadas geográficas;
  • Descobrir o que mais pode ser feito com a exploração dos demais recursos da API.

Introdução

Quando o Google Maps[1] (figura 1) foi lançado em Fevereiro de 2005, ainda em sua versão beta, tornou-se rapidamente a referência magna da revolução que a Internet começara então a experimentar. Com uma interface rica e intuitiva, a aplicação permitia acesso a uma enorme base de dados contendo uma infinidade de mapas de cidades, bairros, ruas e avenidas nos Estados Unidos. Com o tempo, novas localidades foram sendo adicionadas no sistema até que, em meados de maio de 2007, o Google finalmente disponibilizou consultas de endereços no Brasil. Finalmente, em Outubro do ano passado, uma versão extendida para o público brasileiro – e em português – foi oferecida, com a possibilidade de se localizar restaurantes, hotéis, traçar rotas, dentre outras utilidades. Assim, cada vez mais sites brasileiros incluem os mapas do Google em seu conteúdo, com as mais diversas finalidades: desde a simples localização de estabelecimentos comerciais, como no já popular Guia Quatro Rodas, passando pelo auxílio no combate à dengue através do registro de focos suspeitos, como no caso do projeto da secretaria de saúde do estado de Pernambuco, o MapDengue[2, 3].

Talvez agora você esteja se perguntando: “Mas como tudo isso foi possível? Como posso incluir também esses mapas em meu site e construir serviços diferenciados aos meus usuários? Posso usá-los de graça?”. São essas dúvidas que procuraremos sanar nesse artigo.

Figura 1. O Google Maps em ação.Figura 1. O Google Maps em ação.

Os assuntos nesse texto distribúem-se da seguinte forma: a seção 1 apresenta suscintamente a excelente API do Google: suas aplicações, termos de uso e as principais classes. A seção 2 ensina como obter sua própria chave para poder usar a API e ainda fornece uma espécie de “Hello World” – o script para a aplicação mais simple possível . A seção 3 descreve passo-a-passo um script para uma pequena aplicação, porém interessante: um localizador de endereços: você digita o endereço de sua casa e a sua rua é exibida diretamente no mapa! Em caso de ambigüidades (ex. duas ruas com o mesmo nome em cidades diferentes), o sistema lista os resultados encontrados para que você decida qual o endereço correto. Finalmente, a última seção apresenta conclusões e referências para que você siga adiante em seus estudos e na implementação de sistemas mais flexíveis.

1. Visão geral da API

A primeira versão da API (“Application Programming Interface”[4]) do Google Maps foi disponibilizada em Junho de 2005. Desde então, as funcionalidades foram bastante aprimoradas, culminando na versão atual, liberada em Abril de 2006. A API consiste basicamente de um pequeno conjunto de classes JavaScript que fornecem a interface necessária para que o usuário possa construir aplicações para exibir mapas, realizar consultas por endereços (geocoding), realizar funções de zoom, acrescentar pontos de referência e descrições no mapa, dentre outras possibilidades. Tudo dentro da “filosofia” Ajax, sem, no entanto, o usuário ter de se preocupar com os detalhes.

E por falar em preocupação, para quem estiver curioso sobre a licença de uso desse serviço, eis um fato agradável: qualquer pessoa responsável por um domínio da Internet poder utilizar a API de graça, desde que possua uma chave (“API Key”). Essa chave consiste de uma string que deve ser utilizada sempre que se incluir a API em uma página web através de uma tag Html <script> </script>.

Os termos de uso não contêm maiores restrições, a não ser pela proibição em tentar alterar e/ou esconder o logotipo do Google embutidos nos mapas e a óbivia proibição do uso do serviço para atividades ilícitas, como venda de drogas, por exemplo. Se o seu serviço pretende contar com mais de 500 mil visualizações de páginas por dia, também não será possível usar a API diretamente. Quanto ao uso comercial, o Google avisa que a API pode ser utilizada em serviços com fins lucrativos, desde que o acesso aos mapas seja livre e grátis para todos os usuários do serviço. Uma outra restrição é quanto ao uso dos mapas em outros formatos: é proibída a utilização dos mapas em outros meios digitais, que não as páginas autorizadas pelo Google (ou seja, que possuam uma chave).

Veremos agora uma breve descrição das classes utilizadas nos exemplos. Você perceberá que é necessário muito pouco para que a sua aplicação seja realmente funcional.

Tabela 1. As principais classes Javascript da API do Google Maps.Tabela 1. As principais classes Javascript da API do Google Maps.

2. Inserindo um mapa em uma página web

Uma vez que você adquiriu uma noção geral de o que pode ser feito com a API e de como pode ser feito, iremos ver o primeiro exemplo prático. Um autêntico “Olá mundo” ao mundo dos mapas interativos! O primeiro passo para inserir um mapa do Google em seu site é aceitar os termos de uso e obter uma chave para um domínio. Nesse processo, você deve informar o domínio e o diretório no servidor (raíz ou qualquer subpasta) a partir da qual a chave será válida. Note que toda página que pretende usar a API deve estar abaixo do diretório escolhido. Também é possível obter uma chave para testes locais, se você possuir um servidor web instalado em sua máquina. Para isso, digite http://localhost no lugar do domínio. Para obter a sua chave, clique aqui.

Agora que você possui a sua chave, preste atenção no código abaixo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>	

<!--Insira o número da sua chave após a variável "key" na querystring abaixo -->
<script src="http://maps.google.com/maps?file=api&v=2&key=sua_chave" type="text/javascript">
</script>
<script type="text/javascript">
// Variável irá referenciar o objeto que representa o mapa
var meuPrimeiroMapa = "";

// Coordenadas para o centro do mapa mundi
var centroDoMundo = new GLatLng(0,0);

// Nível de zoom inicial (vai de 0 a 17. Em modo satellite, as imagens 
// para alguns níveis mais altos podem não estar disponíveis)
var nivelZoom = 2;
    
// Exibe o mapa em modo normal. As outras opções são
// G_SATELLITE_MAP e G_HYBRID_MAP 
var tipoMapa = G_NORMAL_MAP; 
</script>

</head>
<!-- Criamos o mapa no evento onLoad da página --!>
<body onLoad="criarMapa()">

<!-- Botão para reiniciar o mapa --!>
<input type="button" name="Reinicia" value="Reiniciar" onClick="reiniciar()" />

<!-- Div onde o mapa sera renderizado. Note que o estilo --!>
<!-- CSS define tamanho do mapa --!>
<div id="meuMapa" style="width: 500px; height: 500px"></div>

<!-- Funções utilizadas pelo sistema --!>
<script type="text/javascript">

// Função invocada para renderizar o mapa embutido em uma div html
function criarMapa() {

    // Instanciamos o objeto principal do tipo GMap2 que representa
    // o mapa, passando como argumento do contrutor o objeto DOM
    // que irá receber a renderização
    meuPrimeiroMapa = new GMap2(document.getElementById("meuMapa"));

    // Adicionamos um controle de zoom e de translação do mapa.
    // Uma outra opção seria GSmallMapControl para um controle
    // diminuto
    meuPrimeiroMapa.addControl(new GLargeMapControl());

    // Adiciona as opções de visualização do mapa.
    // As opções disponíveis são: normal, híbrido e satélite
    meuPrimeiroMapa.addControl(new GMapTypeControl());

    // Iniciamos o mapa com as configuações que escolhemos inicialmente
    reiniciar();
}

// Função para configurar alguns aspectos importantes do mapa
function reiniciar() {

    // Define o ponto central de vizualização do mapa,
    // bem como o nível de zoom inicial
    meuPrimeiroMapa.setCenter(centroDoMundo, nivelZoom);

    // Define o tipo inicial do mapa
    meuPrimeiroMapa.setMapType(tipoDoMapa);
}
</script>
</body>
</html>

Se você leu atentamente os comentários no código e se você atende aos pré-requisitos descritos no início do artigo, esse código deve ter sido auto-explicativo. Se você tiver qualquer dúvida sobre Javascript, recomendo os artigos e as colunas disponíveis no iMasters[5]. Caso você obtenha um erro através de um alert com os dizeres “Invalid Key” ou algo parecido, verifique se o número da chave anexo à tag <script> inicial foi escrito corretamente. Note também que javascript não permite quebras de linhas no meio de um literal string.

Se você conseguiu exibir a aplicação corretamente, parabéns. Agora é hora de construírmos uma aplicação mais útil, rica e flexível a qual certamente servirá de base para sistemas mais complexos. Iremos partir para um exemplo que utiliza geocoding, que, nesse artigo, preferi traduzir para “geolocalização”.

3. Um sistema de geolocalização flexível com resolução de ambigüidades

Segundo [6], geolocalização é o processo de atribuir identificadores geográficos (códigos ou coordenadas geográficas expressas como latitude-longitude) para mapear endereços. Na verdade, não apenas endereços de ruas podem ser mapeados em coordenadas, mas qualquer informação que possua um nexo geográfico tal como, por exemplo, um endereço IP. É através do uso ativo de coordenadas geográficas que um Sistema de Informações Geográficas (SIG) pode ser alimentado.

Para o nosso próximo exemplo com a API GoogleMaps, iremos construir uma interface Html (figura 2) para que, através de um campo texto de um form, possamos digitar qualquer endereço válido no mundo e traduzí-lo para coordenadas geográficas, sempre utilizando a base de dados do google. O sistema resolverá, ainda, endereços ambíguos. Por exemplo, suponha que seja digitado o endereço “Domingos Ferreira, Brasil”. Como existem diversas ruas e avenidas com esse nome, o sistema listará as seis primeiras ocorrências com os endereços completos, para que o usuário decida qual localidade melhor se adequa a sua consulta.

Figura 2. Screenshot do sistema que iremos construír.Figura 2. Screenshot do sistema que iremos construír.

Como esse código é um pouco mais complexo que o anterior, listarei separadamente as funções javascript utilizadas para, logo em seguida, fornecer o código completo. Mas antes, iremos conhecer as variáveis necessárias para a lógica do sistema.

// Todas as variáveis utilizadas no sistema

// Referência para a instância de GMap2
var mapaobj;

// Referência para a instância de GClientGeocoder
var geocoder; 

// Array para mapear níveis de Zoom com a precisão do resultado
// Sinta-se livre para realizar o mapeamento achar mais conveniente.
// Note que quanto maior o número, maior o nível de zoom.
var nivelZoom = [];
    nivelZoom[0] = 2;
    nivelZoom[1] = 8;
    nivelZoom[2] = 9;
    nivelZoom[3] = 10;
    nivelZoom[4] = 12;
    nivelZoom[5] = 13;
    nivelZoom[6] = 14;
    nivelZoom[7] = 15;
    nivelZoom[8] = 16;

Agora sim, veremos as funções necessárias.

  • Função inicializa() – Responsável por criar as referências aos objetos necessários à aplicação, como a instância de GMap2 e, como novidade, uma instância de GClientGeocoder a qual realizará as consultas necessárias. Confira o código da função:

// Função chamada ao carregar a página HTML
function inicializa() {
    // Cria o objeto principal referenciando a div 'mapa'
    mapaobj = new GMap2(document.getElementById("mapa"));
    // Centraliza o mapa na coordenada (34, 0) com nível de zoom 3
    mapaobj.setCenter(new GLatLng(34, 0), 3);
    // Cria o objeto que resolverá as consultas de endereço
    geocoder = new GClientGeocoder();
}
  • Função realizaConsulta() – Responsável por realizar a consulta de coordenadas à base do Google.
// Função chamada quando o usuário envia a consulta
function realizaConsulta() {
    // Recebe o endereço digitado no campo 'consulta' do form
    var endereco = document.forms[0].consulta.value;
    // Realiza a consulta. resolverEnderecos é a função callback
    // Javascript que será chamada quando o método getLocations do 
    // objeto geocoder retornar uma resposta.
    geocoder.getLocations(endereco, resolverEnderecos);
}
  • Função resolverEnderecos() – Responsável por tratar a resposta obtida a partir de uma consulta ao geolocalizador.
// Callback para tratar o retorno de uma chamada ao método
// getLocations() do objeto geocoder. O parâmetro resposta será
// usado para acessar os dados retornados. resolverEnderecos também faz 
// uso da função listarLocais que será explicada adiante.
function resolverEnderecos(resposta) {

    // Retira todos os marcadores existentes no mapa.
    mapaobj.clearOverlays(); 
        
    // Verifica o status da resposta
    if (!resposta || resposta.Status.code != G_GEO_SUCCESS) {

        // Caso a resposta seja inválida, exibe o motivo.
        alert("Nao foi possivel localizar o endereco solicitado");
        // Os códigos de erro são úteis para procurer o motivo
        // exato da falha na consulta de endereços na documentação
        // do GoogleMaps API
        alert("Código de erro: " +  resposta.Status.code);

    } else {

        // Caso o status da resposta seja G_GEO_SUCCESS,
        // iremos navegar em todos os resultados retornados,
        // que podem ser vários em caso de uma consulta ambígüa

        // Extrai o número de resultados retornados. O atributo
        // Placemark matém toda a informação de que precisamos
        // acerca das localidades encontradas.
        var num_resultados = resposta.Placemark.length;
        // Obtemos a referência DOM à div na qual os locais encontrados
        // serão listados através do Javascript
        var alvo = document.getElementById("locais");

        // Invoca a função listarLocais, explicada posteriormente
        listarLocais(alvo, resposta.Placemark);           

        // Caso haja múltiplos resultados, informa o fato ao usuário
        if (num_resultados > 1) {
              
              alert('A sua consulta retornou resultados ambígüos.' +
                    '\nEscolha a localidade mais adequada à consulta.');

        } else {

          // Caso haja um único resultado, 

          // Obtém uma referência ao endereço retornado
          var local = resposta.Placemark[0];

          // Extrai o um objeto GLatLng representando as coordenadas
          // do endereço solicitado
          var ponto = local.Point.coordinates;

          // Extrai a precisão do endereço. Accuracy é um número que
          // indica se o endereço retornado corresponde a um país, 
          // provincial, estado, cidade, bairro, rua, etc. Depende da
          // consulta que foi realizada. Com essa informação em mãos,
          // podemos decidir qual o nível de zoom mais adequado
          var acc = resposta.Placemark[0].AddressDetails.Accuracy;

          // Chama a função centralizaMapa passando como argumento
          // as coordenadas do ponto (posição 1 para latitude, 0 para
          // longitude); O endereço completo do ponto encontrado; a 
          // precisão do endereço para controlar o nível de zoom
          centralizaMapa(ponto[1],ponto[0],resposta.Placemark[0].address, acc);
         
       }
    }
}
  • Função listarLocais – Lista todos os locais encontrados, escrevendo a resposta em uma div html.
// Função lista as localizações encontradas na consulta.
// Os parâmetros são: alvo --> a referência DOM da div que receberá os 
// endereços; placemark --> referência a um array de objetos representando as
// localidades encontradas
function listarLocais(alvo, placemark) {

    //Começa a escrita na div informando a quantidade de resultados
    // encontrados. O máximo retornado pelo geocoder são seis endereços
    alvo.innerHTML = "<p> A pesquisa retornou " +
                         placemark.length + " resultado(s): </p>";

    // Loop para escrever informações de cada endereço
    for (var i=0; i<placemark.length; ++i) {

        // Obtém a informação da Unidade Federativa, no caso de um 
        // endereço no Brasil
        var uf = placemark[i].AddressDetails.Country
                            .AdministrativeArea.AdministrativeAreaName;	

        // Obtém a informação sobre a precisão do endereço  
	var acc = placemark[i].AddressDetails.Accuracy;

        // Obtém um ponto GLatLng com as coordenadas da localidade i
        var p = placemark[i].Point.coordinates;
	  
        // Obtém o endereço textual completo
        var info = placemark[i].address;
	
        // Começa a escrita de um link para a função centralizaMapa do
        // endereço i encontrado
        alvo.innerHTML +="<a href='javascript:centralizaMapa(" + p[1] + 
                         "," + p[0] + ",\"" + info + "\", " + acc +
                         ")'>" + placemark[i].address +"</a><br />";
      }
  } 
  • Função centralizaMapa – Última função necessária para o funcionamento do sistema, permite que o mapa seja centralizado no ponto correspondente ao endereço solicitado
// Função para centralizar o mapa no ponto solicitado
// Parâmetros: x à latitude; y à longitude; info à Um texto que será
// exibido em um quadro informativo que aponta para o endereço;
// acc à a precisão do endereço para utilizar o zoom adequado
function centralizaMapa(x, y, info, acc) {
   
    // Cria um ponto GLatLng
    var p = new GLatLng(x,y);
    
    // Obtém o nível de zoom conforme a precisão do endereço
    var zoom = nivelZoom[acc];

    // Define o novo centro do mapa e o seu novo nível de zoom
    mapaobj.setCenter(p,zoom);

    // Cria um novo marcador que sera exibido no ponto p solicitado
    marcador = new GMarker(p);

    // Adiciona o marcador ao mapa
    mapaobj.addOverlay(marcador);

    // Exibe uma caixa de informação com o texto informado
    // Note que esse método aceita qualquer string com uma
    // formatação html arbitrária
    marcador.openInfoWindowHtml("<b> " + info + "</b>");    
  }

Agora que conhecemos cada função necessária para o funcionamento do sistema, resta montar a lógica de apresentação em Html; o que não será difícil. Para os nossos propósitos, o código HTML abaixo será suficiente para o funcionamento de nosso sistema.

<!-- Chama a função inicializa ao carregar a página html --!>
<body onLoad="inicializa()">

  <h2> 
    Exemplo de geolocalização endereços com resolução de ambigüidades
  </h2>

  <!-- Div para a listagem dos endereços --!>  
  <div id="locais"></div>

  <!-- Formulário para o envio de consultas. Note que a função --!>
  <!-- realizaConsulta é invocada no evento onSubmit da tag <form> --!>        
  <form action="" onsubmit="realizaConsulta(); return false;">
    <p>
      <input type="text" name="consulta" size = "50" /> 
      <input type="submit" name="Ok" value="Consultar" />
    </p>
</form>

  <!-- Div onde o mapa será renderizado --!>
  <div id="mapa" style="widht: 500px; height: 300px"></div>

  <!--Créditos :) --!>
  <h3>
      por Carlos Renato Belo Azevedo. <br />
      Bacharelando em Ciência da Computação <br />
      Universidade Católica de Pernambuco <br />
  </h3>
</body>

Agora, é só juntar tudo e ver funcionando, não esquecendo de incluir o link para a API e a chave para o seu domínio. Imagine agora o que você não será capaz de fazer ao salvar as coordenadas obtidas com o sistema de geocoding do Google em sua própria base de dados local, integrando suas próprias informações em mapas personalizados. Esse é apenas o começo.

Conclusões

Uma rápida introdução a API de mapas do Google foi apresentada, fornecendo uma visão geral de quais tipos de sistema podem ser cnstruídos através dessa poderesa interface de programação. Ainda, os primeiros passos para aproveitar os recursos oferecidos foram discutidos, assim como pequenos exemplos práticos de grande utilidade para que o leitor continue seus estudos e seja capaz a incrementar as idéias aqui apresentadas na construção de Sistemas de Informação Geográficos.

Muitos outros recursos da API podem ser explorados, oferecendo uma flexibilidade ainda maior tais como eventos de mouse, ícones personalizados para os marcadores, exibição de fotos nos mapas, cálculo de rotas, dentre outros. Esses e outros assuntos, entretanto, podem ser encontrados diretamente na rica documentação da API disponível em [7].

Agradeço a paciência de todos e recomendo a busca incessante pelo aperfeiçoamento nos estudo, nos conceitos e nas teorias inerentes a suas áreas de atuação. Até a próxima.

Referências

[1] Google Maps. Disponível em http://maps.google.com.

[2] Serviço de mapas do Guia Quatro Rodas. Disponível em http://webservices.maplink2.com.br/viajeaqui/mapa_de_ruas.aspx

[3] Sistema de combate à dengue da secretaria de saúde do estado de Pernambuco. Disponível em http://www.dengue.pe.gov.br

[4] Artigo sobre API na Wikpedia (em inglês). Disponível em http://en.wikipedia.org/wiki/Application_Programming_Interface

[5] Seção sobre Javascript do iMasters. Disponível em https://imasters.com.br/secao/javascript/

[6] Artigo sobre geocoding na Wikipedia (em inglês). Disponível em http://en.wikipedia.org/wiki/Geocoding

[7] Documentação do Google Maps API. Disponível em http://code.google.com/apis/maps/documentation/