API Place Autocomplete Data

Développeurs de l'Espace économique européen (EEE)

L'API Place Autocomplete Data vous permet d'extraire des prédictions de lieux de manière programmatique, afin de créer des expériences de saisie semi-automatique personnalisées avec un degré de contrôle plus précis que celui possible avec le widget de saisie semi-automatique. Dans ce guide, vous allez apprendre à utiliser l'API Place Autocomplete Data pour envoyer des requêtes de saisie semi-automatique en fonction des requêtes des utilisateurs.

L'exemple suivant montre une intégration de saisie semi-automatique simplifiée. Saisissez votre requête, par exemple "pizza" ou "poke", puis cliquez sur le résultat souhaité.

Requêtes Autocomplete

Une requête Autocomplete prend une chaîne de requête en entrée et renvoie une liste de prédictions de lieux. Pour envoyer une requête d'autocomplete, appelez fetchAutocompleteSuggestions() et transmettez une requête avec les propriétés requises. La propriété input contient la chaîne à rechercher. Dans une application classique, cette valeur est mise à jour à mesure que l'utilisateur saisit une requête. La requête doit inclure un sessionToken, qui est utilisé à des fins de facturation.

L'extrait suivant montre comment créer un corps de requête et ajouter un jeton de session, puis appeler fetchAutocompleteSuggestions() pour obtenir une liste de PlacePrediction.

// Add an initial request body.
let request = {
  input: "Tadi",
  locationRestriction: {
    west: -122.44,
    north: 37.8,
    east: -122.39,
    south: 37.78,
  },
  origin: { lat: 37.7893, lng: -122.4039 },
  includedPrimaryTypes: ["restaurant"],
  language: "en-US",
  region: "us",
};
// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

Limiter les prédictions de saisie semi-automatique

Par défaut, Place Autocomplete présente tous les types de lieux, avec une pondération en faveur des prédictions de lieux proches de l'utilisateur, et extrait tous les champs de données disponibles pour le lieu qu'il sélectionne. Définissez des options Place Autocomplete pour présenter des prédictions plus pertinentes en limitant ou en pondérant les résultats.

Si vous limitez les résultats, le widget de saisie semi-automatique ignore tous les résultats en dehors de la zone de restriction. Une pratique courante consiste à limiter les résultats aux limites de la carte. Pondérer la saisie semi-automatique permet d'afficher les résultats dans la zone spécifiée. Toutefois, certaines correspondances peuvent se trouver en dehors de cette zone.

Utilisez la propriété origin pour spécifier le point d'origine à partir duquel calculer la distance géodésique jusqu'à la destination. Si cette valeur est omise, la distance n'est pas renvoyée.

Utilisez la propriété includedPrimaryTypes pour spécifier jusqu'à cinq types de lieux. Si aucun type n'est spécifié, les lieux de tous les types seront renvoyés.

Consulter la documentation de référence de l'API

Obtenir des informations sur un lieu

Pour renvoyer un objet Place à partir d'un résultat de prédiction de lieu, appelez d'abord toPlace(), puis fetchFields() sur l'objet Place résultant (l'ID de session de la prédiction de lieu est automatiquement inclus). Appeler fetchFields() met fin à la session de saisie semi-automatique.

let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.

await place.fetchFields({
  fields: ["displayName", "formattedAddress"],
});

const placeInfo = document.getElementById("prediction");

placeInfo.textContent =
  "First predicted place: " +
  place.displayName +
  ": " +
  place.formattedAddress;

Jetons de session

Les jetons de session regroupent les phases de requête et de sélection d'une recherche de saisie semi-automatique d'un utilisateur dans une session distincte à des fins de facturation. La session commence lorsque l'utilisateur commence à saisir du texte. La session se termine lorsque l'utilisateur sélectionne un lieu et qu'un appel à Place Details est effectué.

Pour créer un jeton de session et l'ajouter à une requête, créez une instance de AutocompleteSessionToken, puis définissez la propriété sessionToken de la requête pour utiliser les jetons, comme indiqué dans l'extrait de code suivant :

// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

Une session se termine lorsque fetchFields() est appelé. Après avoir créé l'instance Place, vous n'avez pas besoin de transmettre le jeton de session à fetchFields(), car cela est géré automatiquement.

await place.fetchFields({
  fields: ["displayName", "formattedAddress"],
});

Créez un jeton de session pour la prochaine session en créant une instance de AutocompleteSessionToken.

Recommandations concernant les jetons de session :

  • Utilisez des jetons de session pour tous les appels Place Autocomplete.
  • Générez un nouveau jeton pour chaque session.
  • Transmettez un jeton de session unique pour chaque nouvelle session. Si vous utilisez le même jeton pour plusieurs sessions, chaque requête est facturée individuellement.

Vous pouvez éventuellement omettre le jeton de session Autocomplete d'une requête. Si le jeton de session est omis, chaque requête est facturée séparément, ce qui déclenche le SKU Autocomplete – Per Request. Si vous en réutilisez un, la session est considérée comme non valide, et les requêtes sont facturées comme si aucun jeton n'avait été fourni.

Exemple

À mesure que l'utilisateur saisit une requête, une requête de saisie semi-automatique est appelée toutes les quelques frappes (et non à chaque caractère), et une liste de résultats possibles est renvoyée. Lorsque l'utilisateur effectue une sélection dans la liste des résultats, cette sélection est considérée comme une demande. Toutes les demandes effectuées lors de la recherche sont regroupées et comptabilisées comme une seule demande. Si l'utilisateur sélectionne un lieu, la requête de recherche est disponible sans frais, et seuls les frais de demande de données sur le lieu sont facturés. Si l'utilisateur ne fait pas de sélection dans les minutes qui suivent le début de la session, seule la requête de recherche est facturée.

Du point de vue d'une application, le flux d'événements se déroule comme suit :

  1. Un utilisateur commence à saisir une requête pour rechercher "Paris, France".
  2. Lorsqu'une saisie utilisateur est détectée, l'application crée un jeton de session, "Jeton A".
  3. À mesure que l'utilisateur saisit du texte, l'API envoie une requête de saisie semi-automatique tous les quelques caractères, en affichant une nouvelle liste de résultats potentiels pour chacun :
    "P"
    "Par"
    "Paris,"
    "Paris, Fr"
  4. Lorsque l'utilisateur effectue une sélection :
    • Toutes les requêtes résultant de la requête sont regroupées et ajoutées à la session représentée par "Jeton A", en tant que requête unique.
    • La sélection de l'utilisateur est comptabilisée comme une demande Place Details et ajoutée à la session représentée par le jeton A.
  5. La session se termine et l'application supprime le jeton A.
En savoir plus sur la facturation des sessions

Exemple de code complet

Cette section contient des exemples complets montrant comment utiliser l'API Place Autocomplete Data .

Prédictions de saisie semi-automatique de lieux

L'exemple suivant montre comment appeler fetchAutocompleteSuggestions() pour l'entrée "Tadi", puis comment appeler toPlace() sur le premier résultat de prédiction, suivi d'un appel à fetchFields() pour obtenir des informations sur le lieu.

TypeScript

/**
 * Demonstrates making a single request for Place predictions, then requests Place Details for the first result.
 */
async function init() {
    // @ts-ignore
    const { Place, AutocompleteSessionToken, AutocompleteSuggestion } = await google.maps.importLibrary("places") as google.maps.PlacesLibrary;

    // Add an initial request body.
    let request = {
        input: "Tadi",
        locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78 },
        origin: { lat: 37.7893, lng: -122.4039 },
        includedPrimaryTypes: ["restaurant"],
        language: "en-US",
        region: "us",
    };

    // Create a session token.
    const token = new AutocompleteSessionToken();
    // Add the token to the request.
    // @ts-ignore
    request.sessionToken = token;
    // Fetch autocomplete suggestions.
    const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

    const title = document.getElementById('title') as HTMLElement;
    title.appendChild(document.createTextNode('Query predictions for "' + request.input + '":'));

    for (let suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;

        // Create a new list element.
        const listItem = document.createElement('li');
        const resultsElement = document.getElementById("results") as HTMLElement;
        listItem.appendChild(document.createTextNode(placePrediction.text.toString()));
        resultsElement.appendChild(listItem);
    }

    let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.
    await place.fetchFields({
        fields: ['displayName', 'formattedAddress'],
    });

    const placeInfo = document.getElementById("prediction") as HTMLElement;
    placeInfo.textContent = 'First predicted place: ' + place.displayName + ': ' + place.formattedAddress;

}

init();

JavaScript

/**
 * Demonstrates making a single request for Place predictions, then requests Place Details for the first result.
 */
async function init() {
  // @ts-ignore
  const { Place, AutocompleteSessionToken, AutocompleteSuggestion } =
    await google.maps.importLibrary("places");
  // Add an initial request body.
  let request = {
    input: "Tadi",
    locationRestriction: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
    origin: { lat: 37.7893, lng: -122.4039 },
    includedPrimaryTypes: ["restaurant"],
    language: "en-US",
    region: "us",
  };
  // Create a session token.
  const token = new AutocompleteSessionToken();

  // Add the token to the request.
  // @ts-ignore
  request.sessionToken = token;

  // Fetch autocomplete suggestions.
  const { suggestions } =
    await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
  const title = document.getElementById("title");

  title.appendChild(
    document.createTextNode('Query predictions for "' + request.input + '":'),
  );

  for (let suggestion of suggestions) {
    const placePrediction = suggestion.placePrediction;
    // Create a new list element.
    const listItem = document.createElement("li");
    const resultsElement = document.getElementById("results");

    listItem.appendChild(
      document.createTextNode(placePrediction.text.toString()),
    );
    resultsElement.appendChild(listItem);
  }

  let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.

  await place.fetchFields({
    fields: ["displayName", "formattedAddress"],
  });

  const placeInfo = document.getElementById("prediction");

  placeInfo.textContent =
    "First predicted place: " +
    place.displayName +
    ": " +
    place.formattedAddress;
}

init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

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

HTML

<html>
  <head>
    <title>Place Autocomplete Data API Predictions</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="title"></div>
    <ul id="results"></ul>
    <p><span id="prediction"></span></p>
    <img
      class="powered-by-google"
      src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png"
      alt="Powered by Google"
    />

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script>
  </body>
</html>

Essayer avec un exemple

Saisie semi-automatique Place Autocomplete avec sessions

Cet exemple illustre les concepts suivants :

  • Appel de fetchAutocompleteSuggestions() en fonction des requêtes des utilisateurs et affichage d'une liste de lieux prédits en réponse.
  • Utilisation de jetons de session pour regrouper une requête utilisateur avec la requête Place Details finale.
  • Récupérer les détails du lieu sélectionné et afficher un repère.
  • Utiliser l'emplacement de contrôle pour imbriquer des éléments d'UI dans l'élément gmp-map.

TypeScript

const mapElement = document.querySelector('gmp-map') as google.maps.MapElement;
let innerMap: google.maps.Map;
let marker: google.maps.marker.AdvancedMarkerElement;
let titleElement = document.querySelector('.title') as HTMLElement;
let resultsContainerElement = document.querySelector('.results') as HTMLElement;
let inputElement = document.querySelector('input') as HTMLInputElement;
let tokenStatusElement = document.querySelector('.token-status') as HTMLElement;
let newestRequestId = 0;
let tokenCount = 0;

// Create an initial request body.
const request: google.maps.places.AutocompleteRequest = {
    input: '',
    includedPrimaryTypes: [
        'restaurant',
        'cafe',
        'museum',
        'park',
        'botanical_garden',
    ],
}

async function init() {
    await google.maps.importLibrary('maps');
    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Update request center and bounds when the map bounds change.
    google.maps.event.addListener(innerMap, 'bounds_changed', async () => {
        request.locationRestriction = innerMap.getBounds();
        request.origin = innerMap.getCenter();
    });

    inputElement.addEventListener('input', makeAutocompleteRequest);
}

async function makeAutocompleteRequest(inputEvent) {
    // To avoid race conditions, store the request ID and compare after the request.
    const requestId = ++newestRequestId;

    const { AutocompleteSuggestion } = (await google.maps.importLibrary(
        'places'
    )) as google.maps.PlacesLibrary;

    if (!inputEvent.target?.value) {
        titleElement.textContent = '';
        resultsContainerElement.replaceChildren();
        return;
    }

    // Add the latest char sequence to the request.
    request.input = (inputEvent.target as HTMLInputElement).value;

    // Fetch autocomplete suggestions and show them in a list.
    const { suggestions } =
        await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

    // If the request has been superseded by a newer request, do not render the output.
    if (requestId !== newestRequestId) return;

    titleElement.innerText = `Place predictions for "${request.input}"`;

    // Clear the list first.
    resultsContainerElement.replaceChildren();

    for (const suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;

        if (!placePrediction) {
            continue;
        }

        // Create a link for the place, add an event handler to fetch the place.
        // We are using a button element to take advantage of its a11y capabilities.
        const placeButton = document.createElement('button');
        placeButton.addEventListener('click', () => {
            onPlaceSelected(placePrediction.toPlace());
        });
        placeButton.textContent = placePrediction.text.toString();
        placeButton.classList.add('place-button');

        // Create a new list item element.
        const li = document.createElement('li');
        li.appendChild(placeButton);
        resultsContainerElement.appendChild(li);
    }
}

// Event handler for clicking on a suggested place.
async function onPlaceSelected(place: google.maps.places.Place) {
    const { AdvancedMarkerElement } = (await google.maps.importLibrary(
        'marker'
    )) as google.maps.MarkerLibrary;

    await place.fetchFields({
        fields: ['displayName', 'formattedAddress', 'location'],
    });

    resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`;
    titleElement.textContent = 'Selected Place:';
    inputElement.value = '';

    await refreshToken();

    // Remove the previous marker, if it exists.
    if (marker) {
        marker.remove();
    }

    // Create a new marker.
    marker = new AdvancedMarkerElement({
        map: innerMap,
        position: place.location,
        title: place.displayName,
    })

    // Center the map on the selected place.
    if (place.location) {
        innerMap.setCenter(place.location);
        innerMap.setZoom(15);
    }
}

// Helper function to refresh the session token.
async function refreshToken() {
    const { AutocompleteSessionToken } = (await google.maps.importLibrary(
        'places'
    )) as google.maps.PlacesLibrary;

    // Increment the token counter.
    tokenCount++;

    // Create a new session token and add it to the request.
    request.sessionToken = new AutocompleteSessionToken();
    tokenStatusElement.textContent = `Session token count: ${tokenCount}`;
}

init();

JavaScript

const mapElement = document.querySelector('gmp-map');
let innerMap;
let marker;
let titleElement = document.querySelector('.title');
let resultsContainerElement = document.querySelector('.results');
let inputElement = document.querySelector('input');
let tokenStatusElement = document.querySelector('.token-status');
let newestRequestId = 0;
let tokenCount = 0;
// Create an initial request body.
const request = {
    input: '',
    includedPrimaryTypes: [
        'restaurant',
        'cafe',
        'museum',
        'park',
        'botanical_garden',
    ],
};
async function init() {
    await google.maps.importLibrary('maps');
    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });
    // Update request center and bounds when the map bounds change.
    google.maps.event.addListener(innerMap, 'bounds_changed', async () => {
        request.locationRestriction = innerMap.getBounds();
        request.origin = innerMap.getCenter();
    });
    inputElement.addEventListener('input', makeAutocompleteRequest);
}
async function makeAutocompleteRequest(inputEvent) {
    // To avoid race conditions, store the request ID and compare after the request.
    const requestId = ++newestRequestId;
    const { AutocompleteSuggestion } = (await google.maps.importLibrary('places'));
    if (!inputEvent.target?.value) {
        titleElement.textContent = '';
        resultsContainerElement.replaceChildren();
        return;
    }
    // Add the latest char sequence to the request.
    request.input = inputEvent.target.value;
    // Fetch autocomplete suggestions and show them in a list.
    const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
    // If the request has been superseded by a newer request, do not render the output.
    if (requestId !== newestRequestId)
        return;
    titleElement.innerText = `Place predictions for "${request.input}"`;
    // Clear the list first.
    resultsContainerElement.replaceChildren();
    for (const suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;
        if (!placePrediction) {
            continue;
        }
        // Create a link for the place, add an event handler to fetch the place.
        // We are using a button element to take advantage of its a11y capabilities.
        const placeButton = document.createElement('button');
        placeButton.addEventListener('click', () => {
            onPlaceSelected(placePrediction.toPlace());
        });
        placeButton.textContent = placePrediction.text.toString();
        placeButton.classList.add('place-button');
        // Create a new list item element.
        const li = document.createElement('li');
        li.appendChild(placeButton);
        resultsContainerElement.appendChild(li);
    }
}
// Event handler for clicking on a suggested place.
async function onPlaceSelected(place) {
    const { AdvancedMarkerElement } = (await google.maps.importLibrary('marker'));
    await place.fetchFields({
        fields: ['displayName', 'formattedAddress', 'location'],
    });
    resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`;
    titleElement.textContent = 'Selected Place:';
    inputElement.value = '';
    await refreshToken();
    // Remove the previous marker, if it exists.
    if (marker) {
        marker.remove();
    }
    // Create a new marker.
    marker = new AdvancedMarkerElement({
        map: innerMap,
        position: place.location,
        title: place.displayName,
    });
    // Center the map on the selected place.
    if (place.location) {
        innerMap.setCenter(place.location);
        innerMap.setZoom(15);
    }
}
// Helper function to refresh the session token.
async function refreshToken() {
    const { AutocompleteSessionToken } = (await google.maps.importLibrary('places'));
    // Increment the token counter.
    tokenCount++;
    // Create a new session token and add it to the request.
    request.sessionToken = new AutocompleteSessionToken();
    tokenStatusElement.textContent = `Session token count: ${tokenCount}`;
}
init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

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

.place-button {
  height: 3rem;
  width: 100%;
  background-color: transparent;
  text-align: left;
  border: none;
  cursor: pointer;
}

.place-button:focus-visible {
  outline: 2px solid #0056b3;
  border-radius: 2px;
}

.input {
  width: 300px;
  font-size: small;
  margin-bottom: 1rem;
}

/* Styles for the floating panel */
.controls {
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
  font-family: sans-serif;
  font-size: small;
  margin: 12px;
  padding: 1rem;
}

.title {
  font-weight: bold;
  margin-top: 1rem;
  margin-bottom: 0.5rem;
}

.results {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.results li:not(:last-child) {
  border-bottom: 1px solid #ddd;
}

.results li:hover {
  background-color: #eee;
}

HTML

<html>
    <head>
        <title>Place Autocomplete Data API Session</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <!-- prettier-ignore -->
        <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});</script>
    </head>
    <body>
        <gmp-map center="37.7893, -122.4039" zoom="12" map-id="DEMO_MAP_ID">
            <div
                class="controls"
                slot="control-inline-start-block-start"
            >
                <input
                    type="text"
                    class="input"
                    placeholder="Search for a place..."
                    autocomplete="off"
                /><!-- Turn off the input's own autocomplete (not supported by all browsers).-->
                <div class="token-status"></div>
                <div class="title"></div>
                <ol class="results"></ol>
            </div>
        </gmp-map>
    </body>
</html>

Essayer l'exemple