Crea un servicio de búsqueda empresarial cercano con Google Maps Platform (JavaScript)

1. Antes de comenzar

Aprende a usar las API de Maps y Places de Google Maps Platform para crear una búsqueda de empresa local, que ubica geográficamente al usuario y muestra lugares interesantes cerca. 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 en el paso siguiente si no tienes esto).
  • Para este paso, debes habilitar la API de Maps JavaScript y la API de Places.
  • Una clave de API para el proyecto anterior.

Comienza con 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 centra el mapa en la ubicación del usuario.
  • Busca lugares cercanos y muestra los resultados como marcadores en los que se puede hacer clic.
  • Recupera y muestra 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 el código de este codelab y, luego, descomprime el archivo:

Descarga el código

  1. Cambie al directorio que acaba 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

Existen tres pasos para crear un mapa de Google en tu página web:

  1. Cómo crear una página HTML
  2. Agrega un mapa
  3. Pega la clave de API

1. Cómo crear una página HTML

A continuación, se muestra el mapa que se creó en este paso. El mapa se centra en la Ópera de Sídney, en Sídney, Australia. Si el usuario rechaza el permiso para obtener su ubicación, el mapa se establece de forma predeterminada en esta ubicación y proporciona resultados de la búsqueda interesantes.

569b9781658fec74.png

  1. Cambia los directorios a la carpeta work/. Durante 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. Cómo agregar un mapa

En esta sección, se muestra la manera de 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 del div de map 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 después de <!-- TODO: Step 1C, Get an API key -->, copia y reemplaza el valor del parámetro clave de la URL de origen de la secuencia de comandos 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ía aparecer un mapa donde antes se encontraba el rectángulo gris. Si ves un mensaje de error, asegúrate de haber reemplazado YOUR_API_KEY en la etiqueta final <script> por tu propia clave de API. Consulta la sección anterior sobre cómo obtener una clave de API si aún no la tienes.

Código de muestra completo

El código completo para este proyecto hasta el momento está disponible en GitHub.

3. Cómo localizar geográficamente a un usuario

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

A continuación, se incluye un ejemplo de un mapa que muestra tu ubicación geográfica cuando navegas desde Mountain View, California:

1dbb3fec117cd895.png

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

La ubicación geográfica hace referencia a la identificación de la ubicación geográfica de un usuario o dispositivo informático a través de una variedad de 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 la ubicación geográfica W3C del navegador para determinar la ubicación del usuario.

Pruébalo tú mismo

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

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. Guarde el archivo.
  2. Vuelve a cargar la página.

El navegador ahora debería pedirte permiso para compartir tu ubicación con la app.

  1. Haz clic en Bloquear una vez para ver si se resuelve el error de forma correcta y permanece centrado en Sídney.
  2. Vuelve a cargar la página y haz clic en Permitir para comprobar 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 para este proyecto hasta el momento 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 de Nearby con una llamada al método PlacesService nearbySearch(), que mostrará un arreglo de objetos PlaceResult.

A. Carga la Biblioteca de Places

Primero, para acceder a los servicios de la Biblioteca de Places, actualiza la URL de la secuencia de comandos de origen a fin de ingresar 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 Nearby Search de Places y controla la respuesta

A continuación, forma una solicitud de PlaceSearch. Estos son los campos obligatorios mínimos:

Estos son los campos obligatorios mínimos:

  • bounds, que 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 simple 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 esté configurado en DISTANCE, deberás especificar una ubicación, pero no puedes definir un radio ni un límite.
  • Una keyword que debe coincidir con todos los campos disponibles, incluidos, sin limitaciones, el nombre, el tipo y la dirección, así como con las opiniones de clientes y otro contenido de terceros, o una type, que restringe los resultados a 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 tipos que siguen a la primera entrada). Consulta la lista de tipos compatibles.

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

  1. Agrega lo siguiente en el comentario TODO: Step 3B1 a fin de escribir dos funciones para llamar a la búsqueda y administrar la respuesta.

La palabra clave sushi se usa como término de búsqueda, pero puede 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 la personalización de imágenes, consulta Marcadores.

El constructor google.maps.Marker toma un solo literal de objeto Marker options, en el que se especifican las propiedades iniciales del marcador.

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

  • position (obligatorio) especifica un LatLng que identifica la ubicación inicial del marcador.
  • map (opcional) especifica el mapa en el que se colocará el marcador. Si no especificas el mapa al construir el marcador, este último se crea, pero no se adjunta al mapa (ni se muestra en él). Puedes agregar el marcador más tarde 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 cada lugar mostrado en la respuesta. También puedes usar el método extend de la variable bounds para asegurarte de que el centro y todos los marcadores estén 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 la página y vuelve a cargarla, 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 bloquea los permisos de ubicación geográfica esta vez.

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

Código de muestra completo

El código completo para este proyecto hasta el momento está disponible en GitHub.

5. Muestra Place Details a pedido

Una vez que tengas un ID de lugar (se proporciona como uno de los campos en los resultados de la búsqueda de sitios cercanos), puedes solicitar detalles adicionales acerca del lugar, como la dirección completa, el número de teléfono y las opiniones y calificaciones de los usuarios. En este codelab, realizarás una barra lateral a fin de mostrar detalles de Place Details y hacer que los marcadores sean interactivos para que el usuario pueda seleccionar lugares a fin de ver los detalles.

A. Crea una barra lateral genérica

Necesitas un lugar para mostrar la información de Place Details, así que aquí encontrarás código simple para una barra lateral que puedes usar a fin de 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 de 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. Cómo agregar 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 lo crees.

El objeto de escucha de clics recupera los detalles del lugar asociado con 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 campo 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 de PlaceResult.

C. Muestra los detalles de Place Details en una ventana de información

Una ventana de información muestra contenido (por lo general, texto o imágenes) en un cuadro de 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 adjuntarlas a una latitud y longitud específicas.

  1. Agrega el siguiente código al 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.

Define 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 del lugar en una barra lateral

Use los mismos detalles que se muestran en el objeto PlaceResult a fin de propagar otro div. En este ejemplo, use 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. Muestra una foto de un lugar con la información de Place Details

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

  1. Coloca este código antes de crear el 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 el navegador y habilita los permisos de ubicación geográfica.
  2. Haz clic en un marcador para que aparezca la ventana de información emergente en la que se muestran algunos detalles, y la barra lateral desliza el dedo desde la izquierda para mostrar más detalles.
  3. Prueba si la búsqueda también funciona si vuelves a cargar y rechazas los permisos de ubicación geográfica. Edite su palabra clave de búsqueda para una búsqueda diferente y explore el resultado que se muestra para esa búsqueda.

ae1caf211daa484d.png

Código de muestra completo

El código completo para este proyecto hasta el momento 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 aprovechar aún más 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 ejemplos de código y canales de asistencia. Algunas funciones populares son Importar datos a Maps, Comenzar a aplicar estilos a tu mapa y agregar el servicio Street View.

¿Qué tipo de codelab deseas que compilemos a continuación?

Más ejemplos del uso de la información enriquecida de Places Más codelabs con la API de Maps Platform JavaScript Más codelabs para Android Más codelabs para iOS Visualización de datos basados en la ubicación en mapas Estilos personalizados de mapas Uso de Street View

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