API تکمیل خودکار مکان به شما امکان میدهد پیشبینیهای مکان را به صورت برنامهنویسیشده دریافت کنید تا تجربیات تکمیل خودکار سفارشیشدهای با درجه کنترل دقیقتری نسبت به ویجت تکمیل خودکار ایجاد کنید. در این راهنما یاد خواهید گرفت که چگونه از API تکمیل خودکار مکان برای ایجاد درخواستهای تکمیل خودکار بر اساس پرسوجوهای کاربر استفاده کنید.
مثال زیر یک ادغام سادهشدهی type-ahead را نشان میدهد. عبارت جستجوی خود، مانند "pizza" یا "poke" را وارد کنید، سپس برای انتخاب نتیجهی مورد نظر خود کلیک کنید.
درخواستهای تکمیل خودکار
یک درخواست تکمیل خودکار، یک رشته ورودی پرسوجو را دریافت کرده و لیستی از پیشبینیهای مکان را برمیگرداند. برای ایجاد یک درخواست تکمیل خودکار، تابع fetchAutocompleteSuggestions() را فراخوانی کرده و یک درخواست با ویژگیهای مورد نیاز ارسال کنید. ویژگی input شامل رشتهای برای جستجو است؛ در یک برنامه معمولی، این مقدار با تایپ پرسوجو توسط کاربر بهروزرسانی میشود. درخواست باید شامل یک sessionToken باشد که برای اهداف صدور صورتحساب استفاده میشود.
قطعه کد زیر ایجاد یک بدنه درخواست و اضافه کردن یک توکن نشست و سپس فراخوانی تابع fetchAutocompleteSuggestions() برای دریافت لیستی از 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;
محدود کردن پیشبینیهای تکمیل خودکار
به طور پیشفرض، قابلیت تکمیل خودکار مکان، تمام انواع مکانها را با در نظر گرفتن پیشبینیهای نزدیک به مکان کاربر ارائه میدهد و تمام فیلدهای داده موجود برای مکان انتخاب شده کاربر را دریافت میکند. گزینههای تکمیل خودکار مکان را طوری تنظیم کنید که پیشبینیهای مرتبطتری را با محدود کردن یا بایاس کردن نتایج ارائه دهند.
محدود کردن نتایج باعث میشود ویجت تکمیل خودکار، هر نتیجهای را که خارج از ناحیه محدودیت است، نادیده بگیرد. یک روش معمول، محدود کردن نتایج به مرزهای نقشه است. بایاس کردن نتایج باعث میشود ویجت تکمیل خودکار نتایج را در ناحیه مشخص شده نشان دهد، اما برخی از تطابقها ممکن است خارج از آن ناحیه باشند.
از ویژگی origin برای تعیین نقطه مبدا که از آن فاصله ژئودزیک تا مقصد محاسبه میشود، استفاده کنید. اگر این مقدار حذف شود، فاصله بازگردانده نمیشود.
از ویژگی includedPrimaryTypes برای مشخص کردن حداکثر پنج نوع مکان استفاده کنید. اگر هیچ نوعی مشخص نشود، مکانهایی از همه نوعها بازگردانده میشوند.
دریافت جزئیات مکان
برای بازگرداندن یک شیء Place از نتیجه پیشبینی مکان، ابتدا toPlace() را فراخوانی کنید، سپس fetchFields() را روی شیء Place حاصل فراخوانی کنید (شناسه جلسه از پیشبینی مکان به طور خودکار درج میشود). فراخوانی fetchFields() جلسه تکمیل خودکار را پایان میدهد.
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}`;
توکنهای جلسه
توکنهای جلسه، مراحل پرسوجو و انتخاب یک جستجوی تکمیل خودکار کاربر را برای اهداف صورتحساب، در یک جلسه مجزا گروهبندی میکنند. جلسه زمانی شروع میشود که کاربر شروع به تایپ کردن میکند. جلسه زمانی پایان مییابد که کاربر مکانی را انتخاب کند و فراخوانی جزئیات مکان انجام شود.
برای ایجاد یک توکن جلسه جدید و افزودن آن به یک درخواست، یک نمونه از AutocompleteSessionToken ایجاد کنید، سپس ویژگی sessionToken درخواست را برای استفاده از توکنها، همانطور که در قطعه کد زیر نشان داده شده است، تنظیم کنید:
// Create a session token. const token = new AutocompleteSessionToken(); // Add the token to the request. // @ts-ignore request.sessionToken = token;
یک session زمانی خاتمه مییابد که fetchFields() فراخوانی شود. پس از ایجاد نمونه Place ، نیازی نیست توکن session را به fetchFields() ارسال کنید زیرا این کار به صورت خودکار انجام میشود.
await place.fetchFields({ fields: ["displayName", "formattedAddress"], });
با ایجاد یک نمونه جدید از AutocompleteSessionToken یک توکن جلسه برای جلسه بعدی ایجاد کنید.
توصیههای توکن جلسه:
- از توکنهای جلسه برای همه فراخوانیهای تکمیل خودکار مکان استفاده کنید.
- برای هر جلسه یک توکن جدید ایجاد کنید.
- برای هر جلسه جدید، یک توکن جلسه منحصر به فرد ارسال کنید. استفاده از یک توکن برای بیش از یک جلسه منجر به این میشود که برای هر درخواست، هزینه جداگانه محاسبه شود.
شما میتوانید به صورت اختیاری توکن جلسه تکمیل خودکار را از یک درخواست حذف کنید. اگر توکن جلسه حذف شود، برای هر درخواست جداگانه صورتحساب صادر میشود و SKU تکمیل خودکار به ازای هر درخواست فعال میشود. اگر از یک توکن جلسه دوباره استفاده کنید، آن جلسه نامعتبر تلقی میشود و هزینه درخواستها طوری محاسبه میشود که انگار هیچ توکن جلسهای ارائه نشده است.
مثال
همانطور که کاربر یک عبارت جستجو را تایپ میکند، هر چند بار فشردن کلید (نه به ازای هر کاراکتر) یک درخواست تکمیل خودکار فراخوانی میشود و فهرستی از نتایج ممکن بازگردانده میشود. هنگامی که کاربر از فهرست نتایج، انتخابی انجام میدهد، آن انتخاب به عنوان یک درخواست محسوب میشود و تمام درخواستهای انجام شده در طول جستجو، دستهبندی شده و به عنوان یک درخواست واحد محاسبه میشوند. اگر کاربر یک مکان را انتخاب کند، عبارت جستجو بدون هیچ هزینهای در دسترس قرار میگیرد و فقط هزینه درخواست داده مکان محاسبه میشود. اگر کاربر ظرف چند دقیقه از شروع جلسه، انتخابی انجام ندهد، فقط هزینه عبارت جستجو محاسبه میشود.
از منظر یک برنامه، جریان رویدادها به این صورت است:
- کاربر شروع به تایپ کردن یک عبارت جستجو برای «پاریس، فرانسه» میکند.
- پس از تشخیص ورودی کاربر، برنامه یک توکن جلسه جدید با نام "توکن A" ایجاد میکند.
- همزمان با تایپ کاربر، API هر چند کاراکتر یک درخواست تکمیل خودکار ارسال میکند و لیست جدیدی از نتایج احتمالی را برای هر کدام نمایش میدهد:
«پی»
"پار"
«پاریس،»
"پاریس، پدر" - وقتی کاربر انتخابی انجام میدهد:
- تمام درخواستهای حاصل از پرسوجو گروهبندی شده و به عنوان یک درخواست واحد به جلسهای که با "توکن A" نمایش داده میشود، اضافه میشوند.
- انتخاب کاربر به عنوان یک درخواست جزئیات مکان محاسبه میشود و به جلسهای که با "توکن A" نمایش داده میشود، اضافه میگردد.
- جلسه به پایان میرسد و برنامه «توکن A» را کنار میگذارد.
کد مثال کامل
این بخش شامل مثالهای کاملی است که نحوه استفاده از API تکمیل خودکار دادهها (Place Autocomplete Data API) را نشان میدهد.پیشبینیهای تکمیل خودکار را قرار دهید
مثال زیر فراخوانی تابع fetchAutocompleteSuggestions() را برای ورودی "Tadi" نشان میدهد، سپس تابع toPlace() را برای اولین نتیجه پیشبینی فراخوانی میکند و در ادامه تابع fetchFields() را برای دریافت جزئیات مکان فراخوانی میکند.
تایپ اسکریپت
async function init() { 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 + '":') ); const resultsElement = document.getElementById("results") as HTMLElement; for (let suggestion of suggestions) { const placePrediction = suggestion.placePrediction; // Create a new list element. const listItem = document.createElement("li"); 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();
جاوا اسکریپت
async function init() { 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 + '":')); const resultsElement = document.getElementById("results"); for (let suggestion of suggestions) { const placePrediction = suggestion.placePrediction; // Create a new list element. const listItem = document.createElement("li"); 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();
سیاساس
/* * 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>
<head>
<title>Place Autocomplete Data API Predictions</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>
<div id="title"></div>
<ul id="results"></ul>
<p><span id="prediction"></span></p>
<img
class="powered-by-google"
src="./powered_by_google_on_white.png"
alt="Powered by Google"
/>
</body>
</html>نمونه را امتحان کنید
تکمیل خودکار تایپ را با جلسات انجام دهید
این مثال مفاهیم زیر را نشان میدهد:
- فراخوانی تابع
fetchAutocompleteSuggestions()بر اساس پرسوجوهای کاربر و نمایش فهرستی از مکانهای پیشبینیشده در پاسخ. - استفاده از توکنهای جلسه برای گروهبندی یک پرسوجوی کاربر با درخواست نهایی جزئیات مکان.
- بازیابی جزئیات مکان برای مکان انتخاب شده و نمایش یک نشانگر.
- استفاده از کنترل اسلاتینگ برای تودرتو کردن عناصر رابط کاربری در عنصر
gmp-map.
تایپ اسکریپت
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();
جاوا اسکریپت
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();
سیاساس
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ gmp-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>
<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>