Créer un service de recherche d'établissements à proximité avec Google Maps Platform (JavaScript)
À propos de cet atelier de programmation
1. Avant de commencer
Découvrez comment utiliser les API Google Maps Platform et Places pour créer une recherche d'établissement local, qui géolocalise l'utilisateur et affiche des lieux intéressants à proximité. L'application intègre la géolocalisation, les informations sur le lieu, Place Photos et plus encore.
Conditions préalables
- Connaissances de base en HTML, CSS et JavaScript
- Un projet avec un compte de facturation (suivez les instructions à l'étape suivante si vous n'en avez pas).
- Pour réaliser l'étape ci-dessous, vous devez activer l'API Maps JavaScript et l'API Places.
- Clé API pour le projet ci-dessus.
Premiers pas avec Google Maps Platform
Si vous n'avez jamais utilisé Google Maps Platform, suivez le guide Premiers pas avec Google Maps Platform ou regardez la playlist de démarrage avec Google Maps Platform pour effectuer les étapes suivantes :
- Créer un compte de facturation
- Créer un projet
- Activer les SDK et les API Google Maps Platform (répertoriés dans la section précédente)
- Générer une clé API
Objectifs de l'atelier
- Créer une page Web affichant une carte Google
- Centre la carte sur la position de l'utilisateur
- Trouver des adresses à proximité et afficher les résultats sous forme de repères cliquables
- Extraire et afficher plus d'informations sur chaque lieu
Prérequis
- Un navigateur Web, par exemple Google Chrome (recommandé), Firefox, Safari ou Internet Explorer
- Votre éditeur de texte ou de code favori
Obtenir l'exemple de code
- Ouvrez votre interface de ligne de commande (Terminal sous macOS ou Invite de commandes sous Windows), puis téléchargez l'exemple de code à l'aide de la commande suivante:
git clone https://github.com/googlecodelabs/google-maps-nearby-search-js/
Si cela ne fonctionne pas, cliquez sur le bouton suivant pour télécharger l'ensemble du code de cet atelier de programmation, puis décompressez le fichier:
- Accédez au répertoire que vous venez de cloner ou de télécharger.
cd google-maps-nearby-search-js
Les dossiers stepN
contiennent l'état final souhaité de chaque étape de cet atelier de programmation. Ils sont fournis à titre de référence. Effectuez votre codage dans le répertoire work
.
2. Créer une carte avec un centre par défaut
Pour créer une carte Google sur votre page Web, trois étapes sont nécessaires:
- Créer une page HTML
- Ajouter une carte
- Collez votre clé API
1. Créer une page HTML
Voici la carte créée lors de cette étape. La carte est centrée sur l'opéra de Sydney, en Australie. Si l'utilisateur refuse l'autorisation d'obtenir sa position, la carte est affichée par défaut pour ce lieu et continue d'afficher des résultats de recherche intéressants.
- Modifiez les répertoires dans votre dossier
work/
. Dans la suite de l'atelier de programmation, effectuez les modifications dans la version du dossierwork/
.
cd work
- Dans le répertoire
work/
, utilisez votre éditeur de texte pour créer un fichier vierge appeléindex.html
. - Copiez le code suivant dans
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>
- Ouvrez le fichier
index.html
dans votre navigateur Web.
open index.html
2. Ajouter une carte
Cette section explique comment charger l'API Maps JavaScript sur votre page Web et écrire votre propre code JavaScript qui utilise l'API pour ajouter une carte à la page Web.
- Ajoutez ce code de script à l'emplacement
<!-- TODO: Step 1B, Add a map -->
après l'élément divmap
et avant la balise</body>
fermante.
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. Collez votre clé API
- Dans la ligne après
<!-- TODO: Step 1C, Get an API key -->
, copiez et remplacez la valeur du paramètre de clé dans l'URL de la source du script par la clé API que vous avez créée lors des prérequis.
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>
- Enregistrez le fichier HTML sur lequel vous travaillez.
Tester le code
Actualisez la vue du fichier que vous avez modifié dans le navigateur. Vous devriez voir une carte apparaître là où le rectangle gris se trouvait auparavant. Si un message d'erreur s'affiche à la place, veillez à remplacer "&YOUR_API_KEY
" dans la balise <script>
finale par votre propre clé API. Consultez la section ci-dessus pour savoir comment obtenir une clé API si vous n'en avez pas.
Exemple de code complet
Le code complet pour ce projet jusqu'à présent est disponible sur GitHub.
3. Géolocaliser votre utilisateur
Vous souhaitez maintenant afficher la position géographique de l'utilisateur ou de l'appareil sur une carte Google via la fonctionnalité de géolocalisation HTML5 de votre navigateur et l'API Maps JavaScript.
Voici un exemple de carte indiquant votre position géographique si vous naviguez à Mountain View, en Californie:
Qu'est-ce que la géolocalisation ?
La géolocalisation correspond à l'identification de la position géographique d'un utilisateur ou d'un appareil informatique par le biais de divers mécanismes de collecte de données. La plupart des services de géolocalisation s'appuient sur des adresses d'acheminement réseau ou des appareils GPS internes pour déterminer cette position. Cette application utilise la propriété Geolocation standard navigator.geolocation
du navigateur Web W3C pour déterminer la position de l'utilisateur.
Essayer vous-même
Remplacez le code entre les commentaires TODO: Step 2, Geolocate your user
et END TODO: Step 2, Geolocate your user
par le code suivant:
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 */
Tester le code
- Enregistrez votre fichier.
- Actualisez la page.
Votre navigateur devrait maintenant vous demander l'autorisation de partager votre position avec l'application.
- Cliquez une fois sur Bloquer pour voir si elle gère l'erreur de manière fluide et qu'elle reste centrée sur Sydney.
- Actualisez de nouveau la page et cliquez sur Autoriser pour vérifier si la géolocalisation fonctionne et déplace la carte vers votre position actuelle.
Exemple de code complet
Le code complet pour ce projet jusqu'à présent est disponible sur GitHub.
4. Rechercher des adresses à proximité
Une requête Nearby Search permet de rechercher des lieux dans une zone définie par mot clé ou par type. Une requête Nearby Search doit toujours inclure un point géographique, qui doit être spécifié en utilisant au choix :
- Un objet
LatLngBounds
définissant une zone de recherche rectangulaire - Zone circulaire définie en tant que combinaison de la propriété
location
(spécifiant le centre du cercle en tant qu'objetLatLng
) et un rayon (en mètres)
Lancez une recherche à proximité en appelant la méthode nearbySearch()
PlacesService
, qui renvoie un tableau d'objets PlaceResult
.
A. Charger la bibliothèque Places
Tout d'abord, pour accéder aux services de la bibliothèque Places, mettez à jour l'URL de la source de votre script afin d'introduire le paramètre libraries
et ajoutez places
comme valeur.
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. Appelez la fonctionnalité Search Nearby Search et gérez la réponse.
Ensuite, créez une requête PlaceSearch. Les champs obligatoires minimum sont les suivants:
Les champs obligatoires minimum sont les suivants:
bounds
, qui doit être un objetgoogle.maps.LatLngBounds
définissant la zone de recherche rectangulaire, ou unlocation
et unradius
; le premier prend un objetgoogle.maps.LatLng
et le second un entier simple représentant le rayon du cercle en mètres. Le rayon maximal autorisé est de 50 000 mètres. Notez que lorsquerankBy
est défini surDISTANCE
, vous devez spécifier un lieu, mais pas un rayon ni des limites.keyword
pouvant être mis en correspondance avec tous les champs disponibles, y compris, mais sans s'y limiter, le nom, le type et l'adresse, ainsi que les avis de clients et d'autres contenus tiers, ou untype
, ce qui limite les résultats aux lieux correspondant au type spécifié. Vous ne pouvez spécifier qu'un seul type (si vous indiquez plusieurs types, tous les types suivants seront ignorés). Consultez la liste des types acceptés.
Dans cet atelier de programmation, vous utiliserez la position actuelle de l'utilisateur en tant qu'emplacement de la recherche, et vous pourrez classer les résultats en fonction de la distance.
- Ajoutez le code suivant au commentaire
TODO: Step 3B1
pour écrire deux fonctions permettant d'appeler la recherche et de gérer la réponse.
Le mot clé sushi
est utilisé comme terme de recherche, mais vous pouvez le modifier. Le code permettant de définir la fonction createMarkers
est fourni dans la section suivante.
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 */
- Ajoutez cette ligne à la fin de la fonction
initMap
au commentaireTODO: Step 3B2
.
/* TODO: Step 3B2, Call the Places Nearby Search */
// Call Places Nearby Search on user's location
getNearbyPlaces(pos);
- Ajoutez cette ligne à la fin de la fonction
handleLocationError
au commentaireTODO: Step 3B3
.
/* TODO: Step 3B3, Call the Places Nearby Search */
// Call Places Nearby Search on the default location
getNearbyPlaces(pos);
C. Générer des repères pour les résultats de recherche
Un marqueur identifie un point géographique sur une carte. Par défaut, les marqueurs utilisent des images standard. Pour savoir comment personnaliser les images de repère, consultez Repères.
Le constructeur google.maps.Marker
utilise un seul littéral d'objet Marker options
spécifiant les propriétés initiales du repère.
Les champs suivants sont particulièrement importants et généralement définis lors de la construction d'un marqueur :
position
(obligatoire) spécifie unLatLng
identifiant l'emplacement initial du repère.map
(facultatif) spécifie la carte sur laquelle placer le repère. Si vous ne spécifiez pas la carte lors de sa construction, le repère est créé, mais n'est pas associé (ni affiché) à la carte. Vous pouvez ajouter le repère ultérieurement en appelant la méthodesetMap()
du repère.- Ajoutez le code suivant après le commentaire
TODO: Step 3C
pour définir la position, la carte et le titre d'un repère par lieu renvoyé dans la réponse. Utilisez également la méthodeextend
de la variablebounds
pour vous assurer que le centre et tous les repères sont visibles sur la carte.
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 */
Tester le code
- Enregistrez et actualisez la page, puis cliquez sur Autoriser pour accorder des autorisations de géolocalisation.
Vous devez voir jusqu'à 20 repères rouges autour du centre de la carte.
- Actualisez la page et bloquez les autorisations de géolocalisation pour le moment.
Obtenez-vous toujours des résultats au centre par défaut de votre carte (dans l'exemple, la valeur par défaut se trouve à Sydney, en Australie) ?
Exemple de code complet
Le code complet pour ce projet jusqu'à présent est disponible sur GitHub.
5. Afficher Place Details sur demande
Une fois que vous avez un identifiant de lieu (affiché dans les champs de votre recherche Nearby), vous pouvez demander des détails supplémentaires, tels que son adresse complète, son numéro de téléphone, ainsi que les notes et les avis des utilisateurs. Dans cet atelier de programmation, vous allez créer une barre latérale pour afficher des détails Place Details détaillés et rendre les repères interactifs pour que l'utilisateur puisse sélectionner des lieux pour voir les détails.
A. Créer une barre latérale générique
Vous avez besoin d'un lieu pour afficher les détails du lieu. Voici un code simple pour une barre latérale qui vous permet de faire glisser le curseur et d'afficher les détails du lieu lorsque l'utilisateur clique sur un repère.
- Ajoutez le code suivant à la balise
style
après le commentaireTODO: 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;
}
- Dans la section
body
juste avant l'élément divmap
, ajoutez un élément DIV pour le panneau des détails.
<!-- TODO: Step 4A2: Add a generic sidebar -->
<!-- The slide-out panel for showing place details -->
<div id="panel"></div>
- Dans la fonction
initMap()
après le commentaireTODO: Step 4A3
, initialisez la variableinfoPane
comme suit:
/* TODO: Step 4A3: Add a generic sidebar */
infoPane = document.getElementById('panel');
B. Ajouter des écouteurs de clics aux repères
- Dans la fonction
createMarkers
, ajoutez un écouteur de clics à chaque repère lors de sa création.
L'écouteur de clics extrait les détails du lieu associé à ce repère, puis appelle la fonction pour afficher les détails.
- Collez le code suivant dans la fonction
createMarkers
du commentaireTODO: Step 4B
.
La méthode showDetails
est implémentée dans la section suivante.
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)
});
});
Dans la requête addListener
, la propriété placeId
spécifie un lieu unique pour la requête de détails, et la propriété fields
est un tableau de noms de champs correspondant aux informations que vous souhaitez obtenir sur le lieu. Pour obtenir la liste complète des champs que vous pouvez demander, consultez l'interface PlaceResult.
C. Afficher les détails du lieu dans une fenêtre d'informations
Une fenêtre d'informations affiche du contenu (généralement du texte ou des images) dans une boîte de dialogue au-dessus d'un emplacement donné sur la carte. La fenêtre d'info est composée d'une zone de contenu et d'un pied effilé. L'extrémité du pied est reliée à un point géographique spécifié sur la carte. En règle générale, les fenêtres d'informations sont associées à des repères, mais vous pouvez également les associer à une latitude/longitude spécifique.
- Ajoutez le code suivant au commentaire
TODO: Step 4C
pour créer unInfoWindow
qui affiche le nom et la note de l'établissement, et associe cette fenêtre au repère.
Vous allez définir showPanel
dans la section suivante pour afficher les détails dans une barre latérale.
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. Charger les détails sur le lieu dans une barre latérale
Utilisez les mêmes informations renvoyées dans l'objet PlaceResult
pour insérer un autre élément DIV. Dans cet exemple, utilisez infoPane
un nom de variable arbitraire pour l'élément div associé à l'ID "."panel
Chaque fois que l'utilisateur clique sur un nouveau repère, ce code ferme la barre latérale si elle est déjà ouverte. Il efface les anciennes informations.
- Ajoutez le code suivant après le commentaire
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. Afficher une photo de lieu avec les détails sur ce lieu
Le résultat getDetails
renvoie un tableau de 10 photos maximum associées à placeId
. Dans cet exemple, la première photo s'affiche au-dessus du nom du lieu dans la barre latérale.
- Placez-le avant la création de l'élément
name
si vous souhaitez que la photo s'affiche en haut de la barre latérale.
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);
}
Tester le code
- Enregistrez et actualisez la page dans votre navigateur, puis autorisez les autorisations de géolocalisation.
- Cliquez sur un repère pour afficher la fenêtre d'informations qui s'affiche à partir du repère et afficher quelques détails dans la barre latérale de gauche.
- Vérifiez si la recherche fonctionne également si vous rechargez et refusez les autorisations de géolocalisation. Modifiez votre mot clé de recherche pour une autre requête et explorez le résultat obtenu.
Exemple de code complet
Le code complet pour ce projet jusqu'à présent est disponible sur GitHub.
6. Félicitations
Félicitations ! Vous avez utilisé de nombreuses fonctionnalités de l'API Maps JavaScript, y compris la bibliothèque Places
.
Points abordés
- Créer une carte avec la classe google.maps.Map
- Utilisation du navigateur de l'utilisateur pour la position et afficher les résultats sur une carte
- Ajouter des repères à votre carte et répondre aux événements de clics des utilisateurs
- Ajouter des fenêtres d'informations pour afficher plus d'informations lorsqu'un utilisateur clique sur un repère
- Charger la bibliothèque Places et effectuer une recherche à proximité
- Extraction et affichage des détails du lieu et des photos de lieux
Learn more
Pour en savoir plus sur les cartes, explorez la documentation de l'API Maps JavaScript et la documentation Places Library, qui contiennent des guides, des tutoriels, la documentation de référence de l'API, des exemples de code et des canaux d'assistance. Parmi les fonctionnalités populaires, citons Importer des données dans Maps, Commencer à styliser votre carte et ajouter le service Street View.
Quel type d'atelier souhaitez-vous utiliser pour la suite ?
L'atelier de programmation que vous souhaitez suivre ne figure pas dans la liste ci-dessus ? Demandez-le en décrivant un nouveau problème ici.