ווידג'ט להשלמה אוטומטית של מקומות (תצוגה מקדימה)

הווידג'ט להשלמה אוטומטית של Place יוצר שדה להזנת טקסט, מספק חיזויים לגבי מקומות ברשימת בחירה של ממשק המשתמש ומחזיר את פרטי המקום לפי הבחירה של המשתמש. אפשר להשתמש בווידג'ט להשלמה אוטומטית של Place כדי להטמיע בדף האינטרנט ממשק משתמש מלא של השלמה אוטומטית.

דרישות מוקדמות

כדי להשתמש בהשלמה אוטומטית של Place (Preview), יש להפעיל את Places API בפרויקט ב-Google Cloud ולציין את ערוץ הבטא (v: "beta") ב-bootraploader. אפשר לקרוא פרטים נוספים במאמר תחילת העבודה.

מה חדש

השלמה אוטומטית של מקומות (תצוגה מקדימה) השתפרה בדרכים הבאות:

  • ממשק המשתמש של הווידג'ט להשלמה אוטומטית תומך בלוקליזציה אזורית (כולל שפות RTL), ב-placeholder של קלט טקסט, בלוגו של רשימת החיזויים ובחיזויים של מקומות.
  • נגישות משופרת, כולל תמיכה בקוראי מסך ובאינטראקציה עם המקלדת.
  • הווידג'ט להשלמה אוטומטית מחזיר את הערך החדש Place class כדי לפשט את הטיפול באובייקט שמוחזר.
  • תמיכה טובה יותר במכשירים ניידים ובמסכים קטנים.
  • ביצועים טובים יותר ומראה גרפי משופר.

הוספת ווידג'ט של השלמה אוטומטית

אתם יכולים להוסיף ווידג'ט של השלמה אוטומטית לדף אינטרנט או למפה של Google. הווידג'ט להשלמה אוטומטית יוצר שדה להזנת טקסט, מספק חיזויים למקומות ברשימת בחירה של ממשק משתמש ומחזיר את פרטי המקום בתגובה לקליק של משתמש באמצעות ה-listen של gmp-placeselect. בקטע הזה מוסבר איך להוסיף ווידג'ט של השלמה אוטומטית לדף אינטרנט או למפת Google.

הוספת ווידג'ט של השלמה אוטומטית לדף אינטרנט

כדי להוסיף לדף אינטרנט את הווידג'ט של ההשלמה האוטומטית, צריך ליצור google.maps.places.PlaceAutocompleteElement חדש ולצרף אותו לדף, כמו בדוגמה הבאה:

TypeScript

// Request needed libraries.
//@ts-ignore
const [{ Map }] = await Promise.all([
    google.maps.importLibrary("places"),
]);
// Create the input HTML element, and append it.
//@ts-ignore
const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();
//@ts-ignore
document.body.appendChild(placeAutocomplete);

JavaScript

// Request needed libraries.
//@ts-ignore
const [{ Map }] = await Promise.all([google.maps.importLibrary("places")]);
// Create the input HTML element, and append it.
//@ts-ignore
const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();

//@ts-ignore
document.body.appendChild(placeAutocomplete);

דוגמה לקוד המלא

הוספת ווידג'ט של השלמה אוטומטית למפה

כדי להוסיף ווידג'ט של השלמה אוטומטית למפה, יוצרים מכונה חדשה של google.maps.places.PlaceAutocompleteElement, מוסיפים את PlaceAutocompleteElement ל-div ודוחפים אותו למפה כפקד מותאם אישית, כמו בדוגמה הבאה:

TypeScript

//@ts-ignore
const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();
//@ts-ignore
placeAutocomplete.id = 'place-autocomplete-input';

const card = document.getElementById('place-autocomplete-card') as HTMLElement;
//@ts-ignore
card.appendChild(placeAutocomplete);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

JavaScript

//@ts-ignore
const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();

//@ts-ignore
placeAutocomplete.id = "place-autocomplete-input";

const card = document.getElementById("place-autocomplete-card");

//@ts-ignore
card.appendChild(placeAutocomplete);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

דוגמה לקוד המלא

הגבלת חיזויים של השלמה אוטומטית

כברירת מחדל, ההשלמה האוטומטית של המקום מציגה את כל סוגי המקומות, עם הטיה לגבי חיזויים שנמצאים בקרבת המיקום של המשתמש, ומאחזרת את כל שדות הנתונים שזמינים למקום שנבחר על ידי המשתמש. אתם יכולים להגדיר אפשרויות להשלמה אוטומטית של מקומות כדי להציג חיזויים רלוונטיים יותר, על ידי הגבלה או הטייה של התוצאות.

הגבלת התוצאות גורמת לווידג'ט של ההשלמה האוטומטית להתעלם מכל התוצאות שנמצאות מחוץ לאזור ההגבלה. אחת מהשיטות הנפוצות היא להגביל תוצאות לגבולות המפה. אם יש הטיה בתוצאות החיפוש, לווידג'ט ההשלמה האוטומטית יוצגו תוצאות באזור שצוין, אבל יכול להיות שחלק מההתאמות יהיו מחוץ לאזור הזה.

הגבלת החיפוש של מקומות לפי מדינה

כדי להגביל את החיפוש של מקומות למדינה ספציפית אחת או יותר, אפשר להשתמש במאפיין componentRestrictions כדי לציין את קודי המדינות, כפי שמוצג בקטע הקוד הבא:

const pac = new google.maps.places.PlaceAutocompleteElement({
  componentRestrictions: {country: ['us', 'au']},
});

הגבלת חיפוש מקום לגבולות מפה

כדי להגביל חיפוש של מקום לגבולות מפה, משתמשים במאפיין locationRestrictions כדי להוסיף את הגבולות, כפי שמוצג בקטע הקוד הבא:

const pac = new google.maps.places.PlaceAutocompleteElement({
  locationRestriction: map.getBounds(),
});

כשמגבילים את גבולות המפה, חשוב להוסיף אוזן כדי לעדכן את הגבולות כשהם משתנים:

map.addListener('bounds_changed', () => {
  autocomplete.locationRestriction = map.getBounds();
});

כדי להסיר את locationRestriction, צריך להגדיר אותו ל-null.

תוצאות חיפוש של מקומות עם דעה קדומה

הטיית תוצאות חיפוש לאזור מעגלי על ידי שימוש בתכונה locationBias והעברת רדיוס, כפי שמוצג כאן:

const autocomplete = new google.maps.places.PlaceAutocompleteElement({
  locationBias: {radius: 100, center: {lat: 50.064192, lng: -130.605469}},
});

כדי להסיר את locationBias, צריך להגדיר אותו ל-null.

הגבלת תוצאות החיפוש של מקומות לסוגים מסוימים

הגבלת תוצאות חיפוש של מקומות לסוגים מסוימים של מקומות באמצעות המאפיין types וציון סוג אחד או יותר, כפי שמוצג כאן:

const autocomplete = new google.maps.places.PlaceAutocompleteElement({
  types: ['establishment'],
});

לרשימה המלאה של הסוגים הנתמכים, ראו טבלה 3: סוגים שנתמכים בבקשות להשלמה אוטומטית.

קבלת פרטים על מקום

כדי לקבל את פרטי המקום לגבי המקום שנבחר, צריך להוסיף אוזן gmp-place-select ל-PlaceAutocompleteElement, כמו בדוגמה הבאה:

TypeScript

// Add the gmp-placeselect listener, and display the results.
//@ts-ignore
placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => {
    await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'] });

    selectedPlaceTitle.textContent = 'Selected Place:';
    selectedPlaceInfo.textContent = JSON.stringify(
        place.toJSON(), /* replacer */ null, /* space */ 2);
});

JavaScript

// Add the gmp-placeselect listener, and display the results.
//@ts-ignore
placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => {
  await place.fetchFields({
    fields: ["displayName", "formattedAddress", "location"],
  });
  selectedPlaceTitle.textContent = "Selected Place:";
  selectedPlaceInfo.textContent = JSON.stringify(
    place.toJSON(),
    /* replacer */ null,
    /* space */ 2,
  );
});

דוגמה לקוד המלא

בדוגמה הקודמת, ה-event listener מחזיר אובייקט של Place class. קוראים לפונקציה place.fetchFields() כדי לקבל את שדות הנתונים של פרטי המקום שנדרשים לאפליקציה.

בדוגמה הבאה, ה-listener מבקש מידע על מקום ומציג אותם במפה.

TypeScript

// Add the gmp-placeselect listener, and display the results on the map.
//@ts-ignore
placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => {
    await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'] });

    // If the place has a geometry, then present it on a map.
    if (place.viewport) {
        map.fitBounds(place.viewport);
    } else {
        map.setCenter(place.location);
        map.setZoom(17);
    }

    let content = '<div id="infowindow-content">' +
    '<span id="place-displayname" class="title">' + place.displayName + '</span><br />' +
    '<span id="place-address">' + place.formattedAddress + '</span>' +
    '</div>';

    updateInfoWindow(content, place.location);
    marker.position = place.location;
});

JavaScript

// Add the gmp-placeselect listener, and display the results on the map.
//@ts-ignore
placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => {
  await place.fetchFields({
    fields: ["displayName", "formattedAddress", "location"],
  });
  // If the place has a geometry, then present it on a map.
  if (place.viewport) {
    map.fitBounds(place.viewport);
  } else {
    map.setCenter(place.location);
    map.setZoom(17);
  }

  let content =
    '<div id="infowindow-content">' +
    '<span id="place-displayname" class="title">' +
    place.displayName +
    "</span><br />" +
    '<span id="place-address">' +
    place.formattedAddress +
    "</span>" +
    "</div>";

  updateInfoWindow(content, place.location);
  marker.position = place.location;
});

דוגמה לקוד המלא

קבלת תוצאות של קידוד גיאוגרפי עבור המקום שנבחר

כדי לקבל תוצאות לגבי הקידוד הגיאוגרפי של המקום שנבחר, צריך להשתמש ב-google.maps.Geocoder כדי לקבל את המיקום, כפי שמוצג בקטע הקוד הבא:

const map = new google.maps.Map(document.getElementById('map'), {
  center: {lat: 50.064192, lng: -130.605469},
  zoom: 3,
});

const marker = new google.maps.Marker({map});
const autocomplete = new google.maps.places.PlaceAutocompleteElement();
const geocoder = new google.maps.Geocoder();

autocomplete.addListener('gmp-placeselect', async ({prediction: place}) => {
  const results = await geocoder.geocode({place.id});
  marker.setPlace({
    placeId: place.id,
    location: results[0].geometry.location,
  });
});

מפות לדוגמה

קטע זה מכיל את הקוד המלא עבור המפות לדוגמה המוצגות בדף זה.

רכיב של השלמה אוטומטית

בדוגמה הזו מתווסף לדף אינטרנט ווידג'ט של השלמה אוטומטית, ומציג את התוצאות של כל מקום שנבחר.

TypeScript

async function initMap(): Promise<void> {
    // Request needed libraries.
    //@ts-ignore
    const [{ Map }] = await Promise.all([
        google.maps.importLibrary("places"),
    ]);
    // Create the input HTML element, and append it.
    //@ts-ignore
    const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();
    //@ts-ignore
    document.body.appendChild(placeAutocomplete);

    // Inject HTML UI.
    const selectedPlaceTitle = document.createElement('p');
    selectedPlaceTitle.textContent = '';
    document.body.appendChild(selectedPlaceTitle);

    const selectedPlaceInfo = document.createElement('pre');
    selectedPlaceInfo.textContent = '';
    document.body.appendChild(selectedPlaceInfo);

    // Add the gmp-placeselect listener, and display the results.
    //@ts-ignore
    placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => {
        await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'] });

        selectedPlaceTitle.textContent = 'Selected Place:';
        selectedPlaceInfo.textContent = JSON.stringify(
            place.toJSON(), /* replacer */ null, /* space */ 2);
    });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  //@ts-ignore
  const [{ Map }] = await Promise.all([google.maps.importLibrary("places")]);
  // Create the input HTML element, and append it.
  //@ts-ignore
  const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();

  //@ts-ignore
  document.body.appendChild(placeAutocomplete);

  // Inject HTML UI.
  const selectedPlaceTitle = document.createElement("p");

  selectedPlaceTitle.textContent = "";
  document.body.appendChild(selectedPlaceTitle);

  const selectedPlaceInfo = document.createElement("pre");

  selectedPlaceInfo.textContent = "";
  document.body.appendChild(selectedPlaceInfo);
  // Add the gmp-placeselect listener, and display the results.
  //@ts-ignore
  placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => {
    await place.fetchFields({
      fields: ["displayName", "formattedAddress", "location"],
    });
    selectedPlaceTitle.textContent = "Selected Place:";
    selectedPlaceInfo.textContent = JSON.stringify(
      place.toJSON(),
      /* replacer */ null,
      /* space */ 2,
    );
  });
}

initMap();

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

p {
  font-family: Roboto, sans-serif;
  font-weight: bold;
}

HTML

<html>
  <head>
    <title>Place Autocomplete element</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <p style="font-family: roboto, sans-serif">Search for a place here:</p>

    <!-- 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. 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: "beta"});</script>
  </body>
</html>

כדאי לנסות דוגמה

מפה להשלמה אוטומטית

בדוגמה הזו ניתן לראות איך להוסיף ווידג'ט של השלמה אוטומטית למפה של Google.

TypeScript

let map: google.maps.Map;
let marker: google.maps.marker.AdvancedMarkerElement;
let infoWindow: google.maps.InfoWindow;
async function initMap(): Promise<void> {
    // Request needed libraries.
    //@ts-ignore
    const [{ Map }, { AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary("marker"),
        google.maps.importLibrary("places")
      ]);

    // Initialize the map.
    map = new google.maps.Map(document.getElementById('map') as HTMLElement, {
        center: { lat: 40.749933, lng: -73.98633 },
        zoom: 13,
        mapId: '4504f8b37365c3d0',
        mapTypeControl: false,
    });
    //@ts-ignore
    const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();
    //@ts-ignore
    placeAutocomplete.id = 'place-autocomplete-input';

    const card = document.getElementById('place-autocomplete-card') as HTMLElement;
    //@ts-ignore
    card.appendChild(placeAutocomplete);
    map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

    // Create the marker and infowindow
    marker = new google.maps.marker.AdvancedMarkerElement({
        map,
    });

    infoWindow = new google.maps.InfoWindow({});

    // Add the gmp-placeselect listener, and display the results on the map.
    //@ts-ignore
    placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => {
        await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'] });

        // If the place has a geometry, then present it on a map.
        if (place.viewport) {
            map.fitBounds(place.viewport);
        } else {
            map.setCenter(place.location);
            map.setZoom(17);
        }

        let content = '<div id="infowindow-content">' +
        '<span id="place-displayname" class="title">' + place.displayName + '</span><br />' +
        '<span id="place-address">' + place.formattedAddress + '</span>' +
        '</div>';

        updateInfoWindow(content, place.location);
        marker.position = place.location;
    });
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
    infoWindow.setContent(content);
    infoWindow.setPosition(center);
    infoWindow.open({
        map,
        anchor: marker,
        shouldFocus: false,
    });
}

initMap();

JavaScript

let map;
let marker;
let infoWindow;

async function initMap() {
  // Request needed libraries.
  //@ts-ignore
  const [{ Map }, { AdvancedMarkerElement }] = await Promise.all([
    google.maps.importLibrary("marker"),
    google.maps.importLibrary("places"),
  ]);

  // Initialize the map.
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.749933, lng: -73.98633 },
    zoom: 13,
    mapId: "4504f8b37365c3d0",
    mapTypeControl: false,
  });

  //@ts-ignore
  const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement();

  //@ts-ignore
  placeAutocomplete.id = "place-autocomplete-input";

  const card = document.getElementById("place-autocomplete-card");

  //@ts-ignore
  card.appendChild(placeAutocomplete);
  map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);
  // Create the marker and infowindow
  marker = new google.maps.marker.AdvancedMarkerElement({
    map,
  });
  infoWindow = new google.maps.InfoWindow({});
  // Add the gmp-placeselect listener, and display the results on the map.
  //@ts-ignore
  placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => {
    await place.fetchFields({
      fields: ["displayName", "formattedAddress", "location"],
    });
    // If the place has a geometry, then present it on a map.
    if (place.viewport) {
      map.fitBounds(place.viewport);
    } else {
      map.setCenter(place.location);
      map.setZoom(17);
    }

    let content =
      '<div id="infowindow-content">' +
      '<span id="place-displayname" class="title">' +
      place.displayName +
      "</span><br />" +
      '<span id="place-address">' +
      place.formattedAddress +
      "</span>" +
      "</div>";

    updateInfoWindow(content, place.location);
    marker.position = place.location;
  });
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
  infoWindow.setContent(content);
  infoWindow.setPosition(center);
  infoWindow.open({
    map,
    anchor: marker,
    shouldFocus: false,
  });
}

initMap();

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-autocomplete-card {
  background-color: #fff;
  border-radius: 5px;
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
  margin: 10px;
  padding: 5px;
  font-family: Roboto, sans-serif;
  font-size: large;
  font-weight: bold;
}

gmp-place-autocomplete {
  width: 300px;
}

#infowindow-content .title {
  font-weight: bold;
}

#map #infowindow-content {
  display: inline;
}

HTML

<html>
  <head>
    <title>Place Autocomplete map</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div class="place-autocomplete-card" id="place-autocomplete-card">
      <p>Search for a place here:</p>
    </div>
    <div id="map"></div>

    <!-- 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. 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: "beta"});</script>
  </body>
</html>

כדאי לנסות דוגמה

שימוש ברכיב של בוחר המקומות

הערה: הדוגמה הזו מתבססת על ספריית קוד פתוח. אפשר לעיין בקובץ README לקבלת תמיכה ומשוב שקשורים לספרייה.

הרכיב של בוחר המקומות הוא קלט טקסט שמאפשר למשתמשי קצה לחפש כתובת או מקום ספציפיים באמצעות השלמה אוטומטית. הספרייה הזו היא חלק מ-Extended Component Library (ספריית הרכיבים המורחבת) של רכיבי אינטרנט שעוזרים למפתחים ליצור מהר יותר מפות טובות יותר ותכונות מיקום.

מגדיר המקום של בוחר המקומות

אפשר להשתמש בתצורה כדי ליצור קוד להטמעה לרכיב מותאם אישית של בוחר המקומות, ואז לייצא אותו לשימוש במסגרות פופולריות כמו React ו-Agular או ללא framework.

מתחילים

כדי להתחיל, צריך לטעון את ספריית הרכיבים המורחבים עם npm.

לקבלת הביצועים הטובים ביותר, יש להשתמש במנהל חבילות ולייבא רק את הרכיבים הדרושים לך. החבילה הזו רשומה ב-npm בתור @googlemaps/extended-component-library. התקנת האפליקציה באמצעות:

  npm i @googlemaps/extended-component-library;

לאחר מכן ייבאו את הרכיבים שבהם אתם משתמשים באפליקציה.

  import '@googlemaps/extended-component-library/place_picker.js';

אחרי שטוענים את ספריית ה-npm, צריך לקבל מפתח API במסוף Cloud.

  <gmpx-api-loader key="YOUR_API_KEY" solution-channel="GMP_DOCS_placepicker_v1"></gmpx-api-loader>

להשתמש בתג הרכיב של בוחר המקומות.

  <gmpx-place-picker placeholder="Enter a place" id="place-picker" style="width: 100%">
  </gmpx-place-picker>

מידע נוסף זמין ב- GitHub או ב- npm. כדי לראות את הרכיבים שבקוד לדוגמה, עיינו בדף examples ב-GitHub.