3 de agosto de 2010

Usando a versão 3 da API do Google Maps

A API do Google Maps é uma coleção de classes, estruturas e outros tipos de dados construídos em JavaScript para facilitar o trabalho de manipulação de mapas e rotas em uma página HTML, tanto para exibição nos navegadores tradicionais disponíveis em desktops (Internet Explorer, Firefox, etc.) quanto para dispositivos móveis, cujos recursos são mais limitados.

De acordo com o site do Goggle Maps, a versão 3 foi projetada para ser mais rápida que a anterior, além de dar um suporte melhor à criação de sites com mapas para uso específico em dispositivos móveis (celulares, smartphones, tablets, etc).

Recentemente, a ABC71 passou a usar esse serviço gratuito para exibir no cadastro de Clientes e Fornecedores de seu ERP Omega um mapa com a localização do Cliente ou Fornecedor. A tela também permite que se trace a rota entre a empresa usuária do ERP e seu Cliente ou Fornecedor. Isso foi possível em parte devido à facilidade com que a API permite trabalhar diretamente com endereços reais - a alternativa é o sistema onde temos que fornecer a latitude e longitude do ponto a ser exibido.

O que o Omega faz é preparar um HTML em tempo de execução usando as informações de endereço do Cliente e apresentar esse HTML num navegador embutido na aplicação, segundo a técnica descrita no post Usando "streams" para navegação no TWebBrowser. No presente post eu mostro como construir esse HTML que exibe um endereço.

Todo o conteúdo da API está disponível num único local que precisa ser indicado no HTML de modo que você possa usar as classes e outros símbolos aí definidos. Para isso, basta incluir uma tag script simples na área de cabeçalho do HTML:

<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3.1&sensor=false&language=pt-BR"></script>

Repare que há alguns parâmetros na referência ao endereço do script, permitindo um ajuste mais fino do uso da API. No exemplo, instruo os servidores do Google a me fornecer a versão 3.1 do script e a usar textos traduzidos para o português brasileiro - veja outras configurações possíveis aqui.

Há dois objetos principais na API que devem ser criados para mostrar um mapa. O primeiro é o mapa em si e o segundo chama-se Geocoder, responsável por converter de forma transparente um endereço real em suas respectivas coordenadas (latitude/longitude), usadas internamente pelo mapa.

var map, geocoder;
function initialize() {
var lOptions = {zoom: 15,mapTypeId: google.maps.MapTypeId.ROADMAP};
var lMapNode;
lMapNode = document.getElementById('map_canvas');
map = new google.maps.Map(lMapNode, lOptions);

geocoder = new google.maps.Geocoder();

mostraEndereco ('AVENIDA NAÇÕES UNIDAS, 17-17, BAURU - SP, 17013-035');
}

function mostraEndereco (pEndereco) {
var lRequest = { address: pEndereco, region: 'BR'};
geocoder.geocode( lRequest, trataLocais);
}

O construtor da classe de mapa aceita 2 parâmetros: o nó HTML onde o mapa será desenhado (no exemplo, uma tag DIV cujo nome é map_canvas) e uma estrutura com a configuração inicial do mapa. No HTML acima eu estabeleço explicitamente as opções de nível de zoom e o tipo de visão desejado. O zoom pode variar de 0 (mais afastado) até 20 (maior proximidade), mas nem todos os níveis de zoom estão disponíveis para todos os endereços. O tipo de visão configurada é o mapa de ruas tradicional - outras opções incluem o uso de imagens de satélite ou uma mistura dos dois tipos, por exemplo. A documentação das opções disponíveis pode ser encontrada aqui.

O construtor do Geocoder em si não possui parâmetros mas sua principal função - geocode - sim. Também são 2: o primeiro é uma estrutura do tipo GeocoderRequest, onde passamos informações sobre o local a ser tratado no mapa. Repare na forma com que passei o endereço, separando logradouro, número, cidade, estado e CEP. O segundo parâmetro é uma função que será chamada automaticamente pelo script com a lista dos endereços encontrados pela função geocode. Isso significa que se os dados do GeocoderRequest forem insuficientes para determinar um lugar único - endereço errado ou não mapeado, por exemplo - pode ser retornado mais de um endereço aproximado. Para esses casos, pode-se optar por fornecer o par latitude/longitude diretamente, garantindo a exatidão e unicidade do local que desejamos apresentar. No entanto, você precisará ter essa informação de antemão para poder repassá-la ao mapa - talvez até mesmo cadastrando-a num banco de dados.

De qualquer forma, a função pode simplesmente exibir o primeiro endereço retornado. Veja um exemplo, onde o primeiro local encontrado é centralizado no mapa e identificado por um marcador:

function trataLocais (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({map: map, position: results[0].geometry.location });
}
}

A partir deste momento, temos criado o vinculo entre o mapa e o Geocoder, resultando no mapa interativo abaixo:

O HTML com o exemplo completo pode ser acessado neste link; ele inclui código para tratar a situação em que mais de um endereço atende os parâmetros informados. Para um exemplo traçando rotas, veja o post Traçando Rotas com a API do Google Maps

11 comentários :

Filipe Siciliano disse...

Mto bom post... estou fazendo algumas adaptações para que ele leia os endereços através de um XML e marcar no mapa...

Me ajudou bastante !

Abs.

gildo chagas disse...

Primeiramente, parabéns pelo excelente post, muito bom mesmo.

Gostaria de tirar umas duvidas:

Preciso mapear 180 escolas, e ao digitar o endereço do aluno que o mapa me traga as escolas mais próximas do endereço digitado.

Existe alguma documentação sobre isso?

Desde já agradeço.

Luís Gustavo Fabbro disse...

Gildo

Não sei se há um meio mais prático mas uma solução é criar um banco de dados com os endereços dessas escolas e calcular dinamicamente a distância deles para o endereço fornecido, determinando quais são próximos.

O post http://balaiotecnologico.blogspot.com.br/2012/01/informacoes-sobre-rotas-com-versao-3-da.html mostra como obter a distância entre endereços dados, de acordo com a rota para ir de um a outro sem necessidade de traçá-la no mapa.

Uma outra abordagem é armazenar no banco também o par latitude/longitude dos endereços das escolas - isso precisaria ser feito uma única vez. Qdo um usuário fornecer um endereço, você pode calcular a distância linear em relação aos que estão no banco - use um cálculo simples da distância entre 2 pontos num plano.

A diferença entre ambas as abordagens é que a primeira considera a rota pra calcular a distância, o que pode ser maior que a distância entre os pontos. No entanto, a primeira é mais realista já que é usando a rota que alguém chegará ao destino.

[]s

gildo chagas disse...

luis bom dia,

Mais uma vez agradeço por mais essa informação de grande valia, vou estudar seu resumo.

Sou Analista Programador da Prefeitura Municipal de Duque de Caxias - RJ, estamos desenvolvendo um software de gestão escolar que em breve estaremos disponibilizando para todas as Secretarias de Educação do Pais, agradecemos sua ajuda e não esqueceremos dos seus créditos em nossa aplicação.

Grande Abraço!

Gildo Chagas.

gildo chagas disse...

Luis, bom dia.

Voce saberia me dizer como posso conseguir a latitude e longitude de um endereço fornecido pelo usuario?

Ex.: ao cadastrar o endereço do aluno preciso buscar e mostrar a latitude e longitude do mesmo em tempo real.

Luís Gustavo Fabbro disse...

Gildo

Como respondi no outro post, dê uma olhada no post Usando a versão 3 da API do Google Maps. Ele mostra o básico sobre endereços na API do Google Maps.

Veja que a função do Geocoder que trata os resultados da busca de um endereço recebe como parâmetro um array de GeocoderResult. Uma das propriedades do Result é o par latitude/longitude do endereço encontrado.

[]s

Guilherme Marins disse...

Oi, Sou analista em Geoprocessamento e estou muito admirado com o seu post. Parabéns. Tenho uma Pergunta, gostaria de saber se por este comando geocoder, consigo informar a lat. e long. e ele me devolver o endereço das coordenadas.

Obrigado, espero sua resposta!

Luís Gustavo Fabbro disse...

Guilherme

A função de callback passada ao Geocode (no post, essa função é a trataLocais) recebe uma lista de resultados, cada um com um valor formatted_address. Supondo que o um resultado tenha sido encontrado, a linha abaixo exibe o endereço correspondente, independendo se a requisição foi feita com o próprio endereço ou com um par latitude/longitude:

alert (results[0].formatted_address);

Lembre-se que o callback é chamado de modo assíncrono, isto é, o script continua executando mas o callback só é executado após receber resposta dos servidores do Google.

[]s

Chikikajimo disse...

Fala Luís Gustavo Fabbro
excelente post!! graças a ele consegui implementar meu mapa,
porem surgiu uma duvida,

tenho um caso especifico de varias marcas espalhadas pelo por varios estados, eu gostaria de colocar no Marker também o balão contendo algumas infos sobre o item marcado, como nome do local, telefone etc.

com base neste exemplo que vc passou tem alguma coisa que possa facilitar este processo!? vlw

Luís Gustavo Fabbro disse...

Chikikajimo

Há um post no blog com o título Trabalhando com marcações em mapas com a versão 3 da API do Google Maps que mostra como fazer marcações no mapa com dados em formato XML. Isso facilita a criação dos marcadores pois fica independente de quantos existem.

O exemplo lá também trata Infos e pode ser extendido para acrescentar outras informações às usadas para construir o balão do tipo Info.

[]s

Phillip Cabral disse...

Muito bom seu post, me ajudou muito. Li algumas dúvidas, e estou usando assim. Na minha aplicação uso um banco de endereços e CEPs bem completo e se o cep digitado não for encontrado no banco, é consultado em um webservice da "republicavirtual" e meu banco atualizado, até agora funciona bem. Nesse código eu só informo o cep, e sempre recebo a localização correta.

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.