Criar um serviço de pesquisa de empresas nas proximidades com a Plataforma Google Maps (JavaScript)

1. Antes de começar

Aprenda a usar as APIs Maps e Places na Plataforma Google Maps para criar uma pesquisa de empresa local, que localiza o usuário e mostra lugares interessantes nas proximidades. O aplicativo integra geolocalização, detalhes do local, fotos e muito mais.

Pré-requisitos

  • Conhecimento básico de HTML, CSS e JavaScript
  • Um projeto com uma conta de faturamento. Siga as instruções na próxima etapa se você não tiver essa opção.
  • Para a etapa abaixo, é necessário ativar a API Maps JavaScript e a API Places.
  • Uma chave de API para o projeto acima.

Comece a usar a Plataforma Google Maps

Se você nunca usou a Plataforma Google Maps, siga o guia Primeiros passos com a Plataforma Google Maps ou assista à playlist Primeiros passos na Plataforma Google Maps para concluir as seguintes etapas:

  1. Criar uma conta de faturamento
  2. Criar um projeto
  3. Ative as APIs e os SDKs da Plataforma Google Maps (listados na seção anterior).
  4. Gerar uma chave de API

O que você aprenderá

  • Criar uma página da Web que exiba um mapa do Google Maps
  • Centralizar o mapa no local do usuário
  • Encontrar lugares por perto e exibir os resultados como marcadores clicáveis
  • Busque e mostre mais detalhes sobre cada lugar

ae1caf211daa484d.png

O que é necessário

  • Um navegador da Web, como o Google Chrome (recomendado), o Firefox, o Safari ou o Internet Explorer
  • Seu editor de texto ou de código favorito

Buscar o exemplo de código

  1. Abra sua interface de linha de comando (Terminal no MacOS ou prompt de comando no Windows) e faça o download do exemplo de código com este comando:
git clone https://github.com/googlecodelabs/google-maps-nearby-search-js/

Se isso não funcionar, clique no botão a seguir para fazer o download de todo o código para este codelab e descompacte o arquivo:

Fazer o download do código

  1. Mude para o diretório que você acabou de clonar ou fazer o download.
cd google-maps-nearby-search-js

As pastas stepN contêm o estado final desejado de cada etapa deste codelab. Elas servem como referência. Faça todo o trabalho de programação no diretório chamado work.

2. Criar um mapa com um centro padrão

Há três etapas para criar um mapa do Google na sua página da Web:

  1. Criar uma página HTML
  2. Adicionar um mapa
  3. Cole a chave de API

1. Criar uma página HTML

Veja abaixo o mapa criado nesta etapa. O mapa está centralizado na Ópera de Sydney, em Sydney, na Austrália. Se o usuário negar a permissão de acesso ao local, o mapa será padronizado para esse local e ainda fornecerá resultados da pesquisa interessantes.

569b9781658fec74.png

  1. Mude os diretórios para a pasta work/. Durante o restante do codelab, faça as edições na versão na pasta work/.
cd work
  1. No diretório work/, use um editor de texto para criar um arquivo em branco chamado index.html.
  2. Copie o seguinte código para index.html.

index.html

<!DOCTYPE html>
<html>

<head>
  <title>Sushi Finder</title>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
  <meta charset="utf-8">
  <style>
    /* Always set the map height explicitly to define the size of the div
     * element that contains the map. */
    #map {
      height: 100%;
      background-color: grey;
    }

    /* Optional: Makes the sample page fill the window. */
    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
    }

    /* TODO: Step 4A1: Make a generic sidebar. */
  </style>
</head>

<body>
  <!-- TODO: Step 4A2: Add a generic sidebar -->

  <!-- Map appears here -->
  <div id="map"></div>

  <!-- TODO: Step 1B, Add a map -->
</body>

</html>
  1. Abra o arquivo index.html no navegador da Web.
open index.html

2. Adicionar um mapa

Esta seção mostra como carregar a API Maps JavaScript na sua página da Web e escrever seu próprio JavaScript que usa a API para adicionar um mapa à página.

  1. Adicione esse código de script em que você vê <!-- TODO: Step 1B, Add a map --> depois do div map e antes da tag de fechamento </body>.

step1/index.html (link em inglês)

<!-- TODO: Step 1B, Add a map -->
<script>
    /* Note: This example requires that you consent to location sharing when
     * prompted by your browser. If you see the error "Geolocation permission
     * denied.", it means you probably did not give permission for the browser * to locate you. */

    /* TODO: Step 2, Geolocate your user
     * Replace the code from here to the END TODO comment with new code from
     * codelab instructions. */
    let pos;
    let map;
    function initMap() {
        // Set the default location and initialize all variables
        pos = {lat: -33.857, lng: 151.213};
        map = new google.maps.Map(document.getElementById('map'), {
            center: pos,
            zoom: 15
        });
    }
    /* END TODO: Step 2, Geolocate your user */
</script>

<!-- TODO: Step 1C, Get an API key -->
<!-- TODO: Step 3A, Load the Places Library -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>

3. Cole a chave de API.

  1. Na linha após <!-- TODO: Step 1C, Get an API key -->, copie e substitua o valor do parâmetro chave no URL da origem do script pela chave de API que você criou durante os pré-requisitos.

step1/index.html (link em inglês)

<!-- TODO: Step 1C, Get an API key -->
<!-- TODO: Step 3A, Load the Places Library -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
  1. Salve o arquivo HTML em que você está trabalhando.

Realizar o teste

Atualize a visualização do arquivo que você está editando no navegador. Você verá um mapa onde o retângulo cinza era exibido. Se você vir uma mensagem de erro, substitua "quot;YOUR_API_KEY" na tag <script> final pela sua própria chave de API. Veja acima como receber uma chave de API se você ainda não tiver uma.

Exemplo de código completo

O código completo do projeto até este momento está disponível no GitHub (link em inglês).

3. Geolocalizar o usuário

Em seguida, você quer exibir a localização geográfica do usuário ou do dispositivo em um mapa do Google usando a geolocalização do HTML5 do seu navegador com a API Maps JavaScript.

Veja um exemplo de mapa que exibe sua localização geográfica se você estiver navegando em Mountain View, Califórnia:

1dbb3fec117cd895.png

O que é geolocalização?

Geolocalização refere-se à identificação da localização geográfica de um usuário ou dispositivo de computação por meio de vários mecanismos de coleta de dados. Normalmente, a maior parte dos serviços de geolocalização usam endereços de roteamento de rede ou dispositivos internos de GPS para determinar esse local. Este app usa a propriedade navigator.geolocation padrão da geolocalização do W3C do navegador da Web para determinar o local do usuário.

Faça o teste

Substitua o código entre os comentários TODO: Step 2, Geolocate your user e END TODO: Step 2, Geolocate your user pelo seguinte:

step2/index.html (link em inglês)

/* TODO: Step 2, Geolocate your user
    * Replace the code from here to the END TODO comment with this code
    * from codelab instructions. */
let pos;
let map;
let bounds;
let infoWindow;
let currentInfoWindow;
let service;
let infoPane;
function initMap() {
    // Initialize variables
    bounds = new google.maps.LatLngBounds();
    infoWindow = new google.maps.InfoWindow;
    currentInfoWindow = infoWindow;
    /* TODO: Step 4A3: Add a generic sidebar */

    // Try HTML5 geolocation
    if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(position => {
        pos = {
        lat: position.coords.latitude,
        lng: position.coords.longitude
        };
        map = new google.maps.Map(document.getElementById('map'), {
        center: pos,
        zoom: 15
        });
        bounds.extend(pos);

        infoWindow.setPosition(pos);
        infoWindow.setContent('Location found.');
        infoWindow.open(map);
        map.setCenter(pos);

        /* TODO: Step 3B2, Call the Places Nearby Search */
    }, () => {
        // Browser supports geolocation, but user has denied permission
        handleLocationError(true, infoWindow);
    });
    } else {
    // Browser doesn't support geolocation
    handleLocationError(false, infoWindow);
    }
}

// Handle a geolocation error
function handleLocationError(browserHasGeolocation, infoWindow) {
    // Set default location to Sydney, Australia
    pos = {lat: -33.856, lng: 151.215};
    map = new google.maps.Map(document.getElementById('map'), {
    center: pos,
    zoom: 15
    });

    // Display an InfoWindow at the map center
    infoWindow.setPosition(pos);
    infoWindow.setContent(browserHasGeolocation ?
    'Geolocation permissions denied. Using default location.' :
    'Error: Your browser doesn\'t support geolocation.');
    infoWindow.open(map);
    currentInfoWindow = infoWindow;

    /* TODO: Step 3B3, Call the Places Nearby Search */
}
/* END TODO: Step 2, Geolocate your user */
/* TODO: Step 3B1, Call the Places Nearby Search */

Realizar o teste

  1. Salve o arquivo.
  2. Atualize a página.

Agora, seu navegador precisa pedir permissão para compartilhar seu local com o app.

  1. Clique em Block para verificar se ele processa o erro corretamente e permanece centralizado em Sydney.
  2. Atualize o local e clique em Permitir para ver se a geolocalização funciona e mova o mapa para seu local atual.

Exemplo de código completo

O código completo do projeto até este momento está disponível no GitHub (link em inglês).

4. Pesquisar lugares por perto

Uma Nearby Search permite pesquisar locais em uma área especificada por palavra-chave ou tipo. Uma Nearby Search deve sempre incluir uma localização, que pode ser especificada de duas formas:

  • Um objeto LatLngBounds que define uma área de pesquisa retangular
  • Uma área circular definida como a combinação da propriedade location, especificando o centro do círculo como um objeto LatLng, e um raio, medido em metros

Inicie uma Nearby Search com uma chamada para o método PlacesService nearbySearch(), que retornará uma matriz de objetos PlaceResult.

A. Carregar a biblioteca do Places

Primeiro, para acessar os serviços da biblioteca do Places, atualize o URL de origem do script para incluir o parâmetro libraries e adicione places como um valor.

step3/index.html

<!-- TODO: Step 3A, Load the Places Library -->
<script async defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap">

B. Chame a solicitação do Places Nearby Search e processe a resposta.

Em seguida, faça uma solicitação do PlaceSearch. Os campos mínimos obrigatórios são:

Os campos mínimos obrigatórios são:

  • bounds, que precisa ser um objeto google.maps.LatLngBounds que define a área de pesquisa retangular, ou um location e um radius. O primeiro usa um objeto google.maps.LatLng, e o segundo usa um número inteiro simples que representa o raio do círculo em metros. O raio máximo permitido é de 50.000 metros. Quando rankBy é definido como DISTANCE, é necessário especificar um local, mas não é possível especificar um raio ou limites.
  • Uma keyword para corresponder a todos os campos disponíveis, incluindo, mas não se limitando a, nome, tipo e endereço, bem como avaliações de clientes e outros conteúdos de terceiros, ou um type, que restringe os resultados aos lugares que correspondem ao tipo especificado. Somente um tipo pode ser especificado (se mais de um tipo for fornecido, todos os tipos após a primeira entrada serão ignorados). Veja a lista de tipos compatíveis.

Neste codelab, você usará a posição atual do usuário como o local da pesquisa e classificará os resultados por distância.

  1. Adicione o seguinte no comentário TODO: Step 3B1 para escrever duas funções e chamar a pesquisa e processar a resposta.

A palavra-chave sushi é usada como termo de pesquisa, mas você pode alterá-la. O código para definir a função createMarkers será fornecido na próxima seção.

step3/index.html

/* TODO: Step 3B1, Call the Places Nearby Search */
// Perform a Places Nearby Search Request
function getNearbyPlaces(position) {
    let request = {
    location: position,
    rankBy: google.maps.places.RankBy.DISTANCE,
    keyword: 'sushi'
    };

    service = new google.maps.places.PlacesService(map);
    service.nearbySearch(request, nearbyCallback);
}

// Handle the results (up to 20) of the Nearby Search
function nearbyCallback(results, status) {
    if (status == google.maps.places.PlacesServiceStatus.OK) {
    createMarkers(results);
    }
}

/* TODO: Step 3C, Generate markers for search results */
  1. Adicione essa linha ao fim da função initMap no comentário TODO: Step 3B2.
/* TODO: Step 3B2, Call the Places Nearby Search */
// Call Places Nearby Search on user's location
getNearbyPlaces(pos);
  1. Adicione essa linha ao fim da função handleLocationError no comentário TODO: Step 3B3.
/* TODO: Step 3B3, Call the Places Nearby Search */
// Call Places Nearby Search on the default location
getNearbyPlaces(pos);

C. Gerar marcadores para resultados da pesquisa

Um marcador identifica uma localização no mapa. Por padrão, um marcador usa uma imagem padrão. Para obter informações sobre como personalizar imagens de marcadores, consulte Marcadores.

O construtor do google.maps.Marker usa um único literal de objeto Marker options, especificando as propriedades iniciais do marcador.

Os campos a seguir são particularmente importantes e são normalmente definidos na construção de um marcador:

  • position (obrigatório) especifica um LatLng que identifica o local inicial do marcador.
  • map (opcional) especifica o mapa em que o marcador será colocado. Se você não especificar o mapa durante a construção do marcador, o marcador será criado, mas não anexado (ou exibido) no mapa. Você pode adicionar o marcador posteriormente chamando o método setMap() do marcador.
  • Adicione o seguinte código após o comentário TODO: Step 3C para definir a posição, o mapa e o título de um marcador por lugar retornado na resposta. Você também pode usar o método extend da variável bounds para garantir que o centro e todos os marcadores estejam visíveis no mapa.

step3/index.html

/* TODO: Step 3C, Generate markers for search results */
// Set markers at the location of each place result
function createMarkers(places) {
    places.forEach(place => {
    let marker = new google.maps.Marker({
        position: place.geometry.location,
        map: map,
        title: place.name
    });

    /* TODO: Step 4B: Add click listeners to the markers */

    // Adjust the map bounds to include the location of this marker
    bounds.extend(place.geometry.location);
    });
    /* Once all the markers have been placed, adjust the bounds of the map to
    * show all the markers within the visible area. */
    map.fitBounds(bounds);
}

/* TODO: Step 4C: Show place details in an info window */

Realizar o teste

  1. Salve e atualize a página e clique em Permitir para conceder permissões de geolocalização.

Você verá até 20 marcadores vermelhos em torno do local central do mapa.

  1. Atualize a página novamente e bloqueie as permissões de geolocalização dessa vez.

Você ainda recebe resultados na central padrão do mapa (na amostra, o padrão é Sydney, Austrália)?

Exemplo de código completo

O código completo do projeto até este momento está disponível no GitHub (link em inglês).

5. Mostrar detalhes do lugar sob demanda

Quando você tiver o ID de lugar de um lugar (fornecido como um dos campos nos resultados da Pesquisa de locais próximos), poderá solicitar detalhes adicionais sobre o lugar, como endereço completo, número de telefone e classificações e avaliações de usuários. Neste codelab, você criará uma barra lateral para exibir detalhes de lugares e tornar os marcadores interativos para que o usuário possa selecionar lugares para ver detalhes.

A. Criar uma barra lateral genérica

Como você precisa de um lugar para exibir detalhes do lugar, este é um código simples de uma barra lateral que pode ser usado para deslizar para exibir os detalhes do lugar quando o usuário clicar em um marcador.

  1. Adicione o seguinte código à tag style após o comentário TODO: Step 4A1:

step4/index.html

/* TODO: Step 4A1: Make a generic sidebar */
/* Styling for an info pane that slides out from the left. 
    * Hidden by default. */
#panel {
    height: 100%;
    width: null;
    background-color: white;
    position: fixed;
    z-index: 1;
    overflow-x: hidden;
    transition: all .2s ease-out;
}

.open {
    width: 250px;
}

/* Styling for place details */
.hero {
    width: 100%;
    height: auto;
    max-height: 166px;
    display: block;
}

.place,
p {
    font-family: 'open sans', arial, sans-serif;
    padding-left: 18px;
    padding-right: 18px;
}

.details {
    color: darkslategrey;
}

a {
    text-decoration: none;
    color: cadetblue;
}
  1. Na seção body, antes do div map, adicione um div ao painel de detalhes.
<!-- TODO: Step 4A2: Add a generic sidebar -->
<!-- The slide-out panel for showing place details -->
<div id="panel"></div>
  1. Na função initMap() após o comentário TODO: Step 4A3, inicialize a variável infoPane desta forma:
/* TODO: Step 4A3: Add a generic sidebar */
infoPane = document.getElementById('panel');

B. Adicionar listeners de clique aos marcadores

  1. Na função createMarkers, adicione um listener de clique a cada marcador à medida que você os cria.

O listener de clique busca detalhes sobre o lugar associado a esse marcador e chama a função para exibir os detalhes.

  1. Cole o seguinte código na função createMarkers no comentário do código TODO: Step 4B.

O método showDetails será implementado na próxima seção.

step4/index.html

/* TODO: Step 4B: Add click listeners to the markers */
// Add click listener to each marker
google.maps.event.addListener(marker, 'click', () => {
    let request = {
    placeId: place.place_id,
    fields: ['name', 'formatted_address', 'geometry', 'rating',
        'website', 'photos']
    };

    /* Only fetch the details of a place when the user clicks on a marker.
    * If we fetch the details for all place results as soon as we get
    * the search response, we will hit API rate limits. */
    service.getDetails(request, (placeResult, status) => {
    showDetails(placeResult, marker, status)
    });
});

Na solicitação addListener, a propriedade placeId especifica um único local para a solicitação de detalhes, e a propriedade fields é uma matriz de nomes de campos para informações a serem retornadas sobre o local. Para ver uma lista completa de campos que você pode solicitar, consulte Interface do PlaceResult.

C. Mostrar detalhes do lugar em uma janela de informações

Uma janela de informações exibe conteúdo (geralmente texto ou imagens) em uma caixa de diálogo acima de um determinado local em um mapa. A janela de informações tem uma área de conteúdo e uma ponta afunilada. A extremidade da ponta é conectada a uma localização especificada no mapa. Normalmente, as janelas de informações são anexadas a marcadores, mas você também pode anexar uma janela de informações a uma latitude/longitude específica.

  1. Adicione o seguinte código no comentário TODO: Step 4C para criar uma InfoWindow que mostre o nome e a nota da empresa e anexe essa janela ao marcador.

Você definirá showPanel na próxima seção para exibir detalhes em uma barra lateral.

step4/index.html

/* TODO: Step 4C: Show place details in an info window */
// Builds an InfoWindow to display details above the marker
function showDetails(placeResult, marker, status) {
    if (status == google.maps.places.PlacesServiceStatus.OK) {
    let placeInfowindow = new google.maps.InfoWindow();
    placeInfowindow.setContent('<div><strong>' + placeResult.name +
        '</strong><br>' + 'Rating: ' + placeResult.rating + '</div>');
    placeInfowindow.open(marker.map, marker);
    currentInfoWindow.close();
    currentInfoWindow = placeInfowindow;
    showPanel(placeResult);
    } else {
    console.log('showDetails failed: ' + status);
    }
}

/* TODO: Step 4D: Load place details in a sidebar */

D. Carregar detalhes do lugar em uma barra lateral

Use os mesmos detalhes retornados no objeto PlaceResult para preencher outro div. Neste exemplo, use infoPane, que é um nome de variável arbitrário para o div com o ID "panel". Sempre que o usuário clica em um novo marcador, esse código fecha a barra lateral se ela já estiver aberta, apaga os detalhes antigos, adiciona os novos detalhes e abre a barra lateral.

  1. Adicione o seguinte código após o comentário TODO: Step 4D.

step4/index.html

/* TODO: Step 4D: Load place details in a sidebar */
// Displays place details in a sidebar
function showPanel(placeResult) {
    // If infoPane is already open, close it
    if (infoPane.classList.contains("open")) {
    infoPane.classList.remove("open");
    }

    // Clear the previous details
    while (infoPane.lastChild) {
    infoPane.removeChild(infoPane.lastChild);
    }

    /* TODO: Step 4E: Display a Place Photo with the Place Details */

    // Add place details with text formatting
    let name = document.createElement('h1');
    name.classList.add('place');
    name.textContent = placeResult.name;
    infoPane.appendChild(name);
    if (placeResult.rating != null) {
    let rating = document.createElement('p');
    rating.classList.add('details');
    rating.textContent = `Rating: ${placeResult.rating} \u272e`;
    infoPane.appendChild(rating);
    }
    let address = document.createElement('p');
    address.classList.add('details');
    address.textContent = placeResult.formatted_address;
    infoPane.appendChild(address);
    if (placeResult.website) {
    let websitePara = document.createElement('p');
    let websiteLink = document.createElement('a');
    let websiteUrl = document.createTextNode(placeResult.website);
    websiteLink.appendChild(websiteUrl);
    websiteLink.title = placeResult.website;
    websiteLink.href = placeResult.website;
    websitePara.appendChild(websiteLink);
    infoPane.appendChild(websitePara);
    }

    // Open the infoPane
    infoPane.classList.add("open");
}

E. Exibir uma foto de local com detalhes do lugar

O resultado getDetails retorna uma matriz de até 10 fotos associadas à placeId. Aqui, você exibe a primeira foto acima do nome do lugar na barra lateral.

  1. Coloque este código antes da criação do elemento name se quiser que a foto apareça na parte superior da barra lateral.

step4/index.html

/* TODO: Step 4E: Display a Place Photo with the Place Details */
// Add the primary photo, if there is one
if (placeResult.photos != null) {
    let firstPhoto = placeResult.photos[0];
    let photo = document.createElement('img');
    photo.classList.add('hero');
    photo.src = firstPhoto.getUrl();
    infoPane.appendChild(photo);
}

Realizar o teste

  1. Salve e recarregue a página no seu navegador e permita permissões de geolocalização.
  2. Clique em um marcador para ver a janela de informações pop-up no marcador exibindo alguns detalhes e a barra lateral deslizando para a esquerda para exibir mais detalhes.
  3. Teste se a pesquisa também funciona se você recarregar e negar as permissões de geolocalização. Edite sua palavra-chave da rede de pesquisa para uma consulta diferente e veja o resultado retornado.

ae1caf211daa484d.png

Exemplo de código completo

O código completo do projeto até este momento está disponível no GitHub (link em inglês).

6. Parabéns

Parabéns! Você usou vários recursos da API Maps JavaScript, incluindo a biblioteca Places.

O que vimos

Saiba mais

Para fazer ainda mais com os mapas, confira a documentação da API Maps JavaScript e a documentação da biblioteca do Places, que contêm guias, tutoriais, a referência da API, mais amostras de código e canais de suporte. Alguns recursos muito usados são Importar dados para o Maps, Começar a estilizar o mapa e adicionar o Serviço do Street View.

Que tipo de codelab você mais quer criar?

Mais exemplos de uso de informações avançadas do Places Mais codelabs usando a API Maps Platform JavaScript Mais codelabs para Android Mais codelabs para iOS Visualização de dados baseados em localização em mapas Estilo personalizado de mapas Uso do StreetView

O codelab que você quer ver não está listado acima? Solicite-o aqui.