Crea un servicio de búsqueda de negocios cercanos con Google Maps Platform (JavaScript)

1. Antes de comenzar

Aprende a usar las APIs de Maps y Places de Google Maps Platform para crear una búsqueda de empresas locales que geolocalice al usuario y muestre lugares interesantes cercanos. La app integra la ubicación geográfica, Place Details, Place Photos y mucho más.

Requisitos previos

  • Conocimientos básicos de HTML, CSS y JavaScript
  • Un proyecto con una cuenta de facturación (sigue las instrucciones del siguiente paso si no tienes una)
  • Para este paso, debes habilitar la API de Maps JavaScript y la API de Places.
  • Es una clave de API para el proyecto anterior.

Cómo comenzar a utilizar Google Maps Platform

Si nunca usaste Google Maps Platform, sigue la guía Cómo comenzar a utilizar Google Maps Platform o mira la lista de reproducción Cómo comenzar a utilizar Google Maps Platform para completar los siguientes pasos:

  1. Crear una cuenta de facturación
  2. Crear un proyecto
  3. Habilitar las API y los SDK de Google Maps Platform (enumerados en la sección anterior)
  4. Generar una clave de API

Actividades

  • Crea una página web que muestre un mapa de Google Maps
  • Se centró el mapa en la ubicación del usuario.
  • Encontrar lugares cercanos y mostrar los resultados como marcadores en los que se puede hacer clic
  • Recuperar y mostrar más detalles sobre cada lugar

ae1caf211daa484d.png

Requisitos

  • Un navegador web, como Google Chrome (recomendado), Firefox, Safari o Internet Explorer
  • Tu editor de texto o código favorito

Obtén el código de muestra

  1. Abre la interfaz de línea de comandos (Terminal en macOS o Símbolo del sistema en Windows) y descarga el código de muestra con este comando:
git clone https://github.com/googlecodelabs/google-maps-nearby-search-js/

Si eso no funciona, haz clic en el siguiente botón para descargar todo el código de este codelab y, luego, descomprime el archivo:

Descarga el código

  1. Cambia al directorio que acabas de clonar o descargar.
cd google-maps-nearby-search-js

Las carpetas stepN contienen el estado final deseado de cada paso de este codelab. Están disponibles como referencia. Realiza todo el trabajo de codificación en el directorio llamado work.

2. Cómo crear un mapa con un centro predeterminado

Para crear un mapa de Google Maps en tu página web, sigue estos tres pasos:

  1. Crea una página HTML
  2. Agrega un mapa
  3. Pega tu clave de API

1. Crea una página HTML

A continuación, se muestra el mapa creado en este paso. El mapa está centrado en la Ópera de Sídney, en Sídney, Australia. Si el usuario rechaza el permiso para obtener su ubicación, el mapa se establecerá de forma predeterminada en esta ubicación y seguirá proporcionando resultados de búsqueda interesantes.

569b9781658fec74.png

  1. Cambia los directorios a tu carpeta work/. En el resto del codelab, realiza las ediciones en la versión de la carpeta work/.
cd work
  1. En el directorio work/, usa tu editor de texto para crear un archivo en blanco llamado index.html.
  2. Copia el siguiente código en 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. Abre el archivo index.html en tu navegador web.
open index.html

2. Agrega un mapa.

En esta sección, se muestra cómo cargar la API de Maps JavaScript en tu página web y escribir tu propio código JavaScript que use la API para agregar un mapa a la página web.

  1. Agrega este código de secuencia de comandos donde veas <!-- TODO: Step 1B, Add a map --> después de la etiqueta map div y antes de la etiqueta de cierre </body>.

step1/index.html

<!-- 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. Pega tu clave de API

  1. En la línea posterior a <!-- TODO: Step 1C, Get an API key -->, copia y reemplaza el valor del parámetro key en la URL de la fuente del script por la clave de API que creaste durante los requisitos previos.

step1/index.html

<!-- 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. Guarda el archivo HTML en el que has estado trabajando.

Pruébalo

Vuelve a cargar la vista del navegador del archivo que estuviste editando. Ahora deberías ver un mapa en el lugar donde antes estaba el rectángulo gris. Si ves un mensaje de error, asegúrate de haber reemplazado "YOUR_API_KEY" en la etiqueta <script> final por tu propia clave de API. Consulta la sección anterior para obtener una clave de API si aún no tienes una.

Código de muestra completo

El código completo de este proyecto hasta este punto está disponible en GitHub.

3. Cómo geolocalizar a tu usuario

A continuación, querrás mostrar la ubicación geográfica del usuario o el dispositivo en un mapa de Google Maps con la función de ubicación geográfica HTML5 de tu navegador y la API de Maps JavaScript.

Este es un ejemplo de un mapa que muestra tu ubicación geográfica si estuvieras navegando desde Mountain View, California:

1dbb3fec117cd895.png

¿Qué es la ubicación geográfica?

La ubicación geográfica permite identificar dónde se encuentran un usuario o un dispositivo a través de diferentes mecanismos de recopilación de datos. Generalmente, la mayoría de los servicios de ubicación geográfica usan direcciones de enrutamiento de red o dispositivos GPS internos para determinar la ubicación. Esta app usa la propiedad navigator.geolocation estándar de ubicación geográfica de W3C del navegador web para determinar la ubicación del usuario.

Pruébalo

Reemplaza el código entre los comentarios TODO: Step 2, Geolocate your user y END TODO: Step 2, Geolocate your user por el siguiente:

step2/index.html

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

Pruébalo

  1. Guarda el archivo.
  2. Vuelve a cargar la página.

Ahora, el navegador debería pedirte permiso para compartir tu ubicación con la app.

  1. Haz clic en Bloquear una vez para ver si controla el error correctamente y permanece centrado en Sídney.
  2. Vuelve a cargar la página y haz clic en Permitir para ver si la ubicación geográfica funciona y mueve el mapa a tu ubicación actual.

Código de muestra completo

El código completo de este proyecto hasta este punto está disponible en GitHub.

4. Busca lugares cercanos

Una búsqueda de sitios cercanos te permite buscar sitios dentro de un área especificada a través de palabras claves o tipos. En una búsqueda de sitios cercanos siempre debe incluirse una ubicación, que puede especificarse con dos métodos:

  • Un objeto LatLngBounds que define un área de búsqueda rectangular
  • Un área circular definida como la combinación de la propiedad location (que especifica el centro del círculo como un objeto LatLng) y un radio, medido en metros

Inicia una Búsqueda cercana con una llamada al método PlacesService nearbySearch(), que devolverá un array de objetos PlaceResult.

A. Carga la biblioteca de Places

Primero, para acceder a los servicios de la biblioteca de Places, actualiza la URL de origen de tu secuencia de comandos para introducir el parámetro libraries y agrega places como 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. Llama a la solicitud de Places Nearby Search y controla la respuesta

A continuación, crea una solicitud de PlaceSearch. Los campos obligatorios mínimos son los siguientes:

Los campos obligatorios mínimos son los siguientes:

  • bounds: Debe ser un objeto google.maps.LatLngBounds que defina el área de búsqueda rectangular, o un location y un radius. El primero toma un objeto google.maps.LatLng y el segundo toma un número entero que representa el radio del círculo en metros. El radio máximo permitido es de 50,000 metros. Ten en cuenta que, cuando rankBy se configura como DISTANCE, debes especificar una ubicación, pero no puedes especificar un radio ni límites.
  • Un keyword para el que se buscarán coincidencias con todos los campos disponibles, incluidos, sin limitaciones, el nombre, el tipo y la dirección, así como las opiniones de los clientes y otro contenido de terceros, o un type, que restringe los resultados a los lugares que coinciden con el tipo especificado. Solo se puede especificar un tipo (si se proporciona más de un tipo, se ignoran todos los siguientes a la primera entrada). Consulta la lista de tipos admitidos.

En este codelab, usarás la posición actual del usuario como ubicación para la búsqueda y clasificarás los resultados por distancia.

  1. Agrega lo siguiente en el comentario TODO: Step 3B1 para escribir dos funciones que llamen a la búsqueda y controlen la respuesta.

La palabra clave sushi se usa como término de búsqueda, pero puedes cambiarla. El código para definir la función createMarkers se proporciona en la siguiente sección.

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. Agrega esta línea al final de la función initMap en el comentario TODO: Step 3B2.
/* TODO: Step 3B2, Call the Places Nearby Search */
// Call Places Nearby Search on user's location
getNearbyPlaces(pos);
  1. Agrega esta línea al final de la función handleLocationError en el comentario TODO: Step 3B3.
/* TODO: Step 3B3, Call the Places Nearby Search */
// Call Places Nearby Search on the default location
getNearbyPlaces(pos);

C. Genera marcadores para los resultados de la búsqueda

Los marcadores identifican una ubicación en un mapa. De manera predeterminada, los marcadores llevan una imagen estándar. Para obtener información sobre cómo personalizar las imágenes de los marcadores, consulta Marcadores.

El constructor google.maps.Marker toma un solo literal del objeto Marker options, que especifica las propiedades iniciales del marcador.

Los campos siguientes tienen particular importancia y normalmente se configuran al construir un marcador:

  • position (obligatorio) especifica un objeto LatLng que identifica la ubicación inicial del marcador.
  • map (opcional) especifica el mapa en el que se debe colocar el marcador. Si no especificas el mapa al construir el marcador, este se creará, pero no se adjuntará al mapa (ni se mostrará en él). Puedes agregar el marcador más adelante llamando al método setMap() del marcador.
  • Agrega el siguiente código después del comentario TODO: Step 3C para establecer la posición, el mapa y el título de un marcador por lugar que se muestre en la respuesta. También usas el método extend de la variable bounds para asegurarte de que el centro y todos los marcadores sean visibles en el 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 */

Pruébalo

  1. Guarda y vuelve a cargar la página, y haz clic en Permitir para otorgar permisos de ubicación geográfica.

Deberías ver hasta 20 marcadores rojos alrededor de la ubicación central del mapa.

  1. Vuelve a cargar la página y, esta vez, bloquea los permisos de ubicación geográfica.

¿Aún obtienes resultados en el centro predeterminado de tu mapa (en el ejemplo, el valor predeterminado está en Sídney, Australia)?

Código de muestra completo

El código completo de este proyecto hasta este punto está disponible en GitHub.

5. Mostrar detalles del lugar a pedido

Una vez que tengas el ID de lugar de un lugar (que se entrega como uno de los campos en los resultados de tu Búsqueda cercana), puedes solicitar detalles adicionales sobre el lugar, como su dirección completa, número de teléfono y calificaciones y opiniones de los usuarios. En este codelab, crearás una barra lateral para mostrar Place Details enriquecidos y harás que los marcadores sean interactivos para que el usuario pueda seleccionar lugares y ver sus detalles.

A. Crea una barra lateral genérica

Necesitas un lugar para mostrar los detalles del lugar, por lo que aquí tienes un código simple para una barra lateral que puedes usar para deslizar y mostrar los detalles del lugar cuando el usuario hace clic en un marcador.

  1. Agrega el siguiente código a la etiqueta style después del comentario 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. En la sección body, justo antes del div map, agrega un div para el panel de detalles.
<!-- TODO: Step 4A2: Add a generic sidebar -->
<!-- The slide-out panel for showing place details -->
<div id="panel"></div>
  1. En la función initMap(), después del comentario TODO: Step 4A3, inicializa la variable infoPane de la siguiente manera:
/* TODO: Step 4A3: Add a generic sidebar */
infoPane = document.getElementById('panel');

B. Agrega objetos de escucha de clics a los marcadores

  1. En la función createMarkers, agrega un objeto de escucha de clics a cada marcador a medida que los creas.

El objeto de escucha de clics recupera detalles sobre el lugar asociado a ese marcador y llama a la función para mostrar los detalles.

  1. Pega el siguiente código dentro de la función createMarkers en el comentario de código TODO: Step 4B.

El método showDetails se implementa en la siguiente sección.

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)
    });
});

En la solicitud addListener, la propiedad placeId especifica un solo lugar para la solicitud de detalles, y la propiedad fields es un array de nombres de campos para la información que deseas que se muestre sobre el lugar. Para obtener una lista completa de los campos que puedes solicitar, consulta la interfaz PlaceResult.

C. Cómo mostrar detalles del lugar en una ventana de información

Una ventana de información muestra contenido (por lo general, texto o imágenes) en un diálogo sobre una ubicación determinada en un mapa. La ventana de información tiene un área de contenido y un tallo cónico. La punta del tallo se conecta a una ubicación especificada del mapa. Por lo general, las ventanas de información se adjuntan a los marcadores, pero también puedes adjuntar una ventana de información a una latitud o longitud específica.

  1. Agrega el siguiente código en el comentario TODO: Step 4C para crear un InfoWindow que muestre el nombre y la calificación de la empresa, y adjunte esa ventana al marcador.

Definirás showPanel en la siguiente sección para mostrar detalles en una 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. Cómo cargar detalles de un lugar en una barra lateral

Usa los mismos detalles que se devolvieron en el objeto PlaceResult para completar otro div. En este ejemplo, usa infoPane, que es un nombre de variable arbitrario para el div con el ID "panel". Cada vez que el usuario hace clic en un marcador nuevo, este código cierra la barra lateral si ya estaba abierta, borra los detalles anteriores, agrega los detalles nuevos y abre la barra lateral.

  1. Agrega el siguiente código después del comentario 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. Cómo mostrar una foto del lugar con los detalles del lugar

El resultado de getDetails devuelve un array de hasta 10 fotos asociadas con el placeId. Aquí, muestras la primera foto sobre el nombre del lugar en la barra lateral.

  1. Coloca este código antes de la creación del elemento name si quieres que la foto aparezca en la parte superior de la 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);
}

Pruébalo

  1. Guarda y vuelve a cargar la página en tu navegador, y permite los permisos de ubicación geográfica.
  2. Haz clic en un marcador para ver la ventana de información que aparece desde el marcador con algunos detalles y la barra lateral que se desliza desde la izquierda para mostrar más detalles.
  3. Prueba si la búsqueda también funciona si vuelves a cargar la página y rechazas los permisos de ubicación geográfica. Edita tu palabra clave de búsqueda para realizar una consulta diferente y explora el resultado que se muestra para esa búsqueda.

ae1caf211daa484d.png

Código de muestra completo

El código completo de este proyecto hasta este punto está disponible en GitHub.

6. Felicitaciones

¡Felicitaciones! Usaste muchas funciones de la API de Maps JavaScript, incluida la biblioteca Places.

Temas abordados

Más información

Para hacer aún más con los mapas, explora la documentación de la API de Maps JavaScript y la documentación de la biblioteca de Places, que contienen guías, instructivos, la referencia de la API, más muestras de código y canales de asistencia. Algunas funciones populares son Importar datos a Maps, Comenzar a diseñar tu mapa y agregar el Servicio de Street View.

¿Qué tipo de codelab te gustaría que creáramos a continuación?

Más ejemplos del uso de información enriquecida de Places Más codelabs que usan la API de Maps JavaScript de Maps Platform Más codelabs para Android Más codelabs para iOS Cómo visualizar datos basados en la ubicación en mapas Diseño personalizado de mapas Cómo usar Street View

¿El codelab que quieres no figura arriba? Crea un nuevo problema aquí para solicitarlo.