使用 Place Search 元素和 Maps JavaScript API 探索地點

目標

瞭解如何整合地點搜尋元素與 Google 地圖,協助使用者透過附近搜尋或文字搜尋功能尋找地點,提升探索景點的能力。使用 Place Details Compact 元素,提供應用程式中顯示地點的詳細資訊。

什麼是 Place Search 元素?

地點搜尋元素是 Maps JavaScript API 中 Places UI Kit 的一部分。這個 HTML 元素會直接在應用程式中,以清單格式顯示地點搜尋結果。這個元素可簡化顯示使用「附近搜尋」或「文字搜尋」找到的地點的程序,提供流暢的地點探索使用者體驗。使用者從清單中選取地點時,您可以在地圖上顯示詳細資料,通常會使用資訊視窗和 Place Details 元素。

以視覺化方式呈現地點探索

下圖顯示 Place Search 元素的實際運作情形。左側會顯示餐廳清單 (地點搜尋元素)。選取餐廳後,地圖上的資訊視窗會顯示餐廳詳細資料,地圖也會以餐廳位置為中心。

圖片

地點探索功能的使用案例

整合地點搜尋元素可提升各行各業的各種應用程式:

  • 旅遊和觀光:讓遊客搜尋特定區域的景點、飯店或特定料理。
  • 房地產:讓潛在買家或租屋者尋找附近的學校、超市或大眾運輸選項。
  • 物流和服務:協助駕駛人尋找電動車充電站、加油站或特定服務中心。

解決方案工作流程:導入地點探索功能

本節將逐步說明如何整合地點搜尋元素,以便在地圖上探索地點,包括與 Places UI Kit 互動的程式碼片段。我們將說明如何初始化地圖,以及實作「附近搜尋」和「文字搜尋」功能。最後,我們會使用「地點詳細資料」元素,在使用者點選地圖上的圖釘時,顯示特定地點的詳細資料。

必要條件

建議您先熟悉下列說明文件:

在專案中啟用 Maps JavaScript APIPlaces UI Kit

開始前,請確認您已載入 Maps JavaScript API,並匯入必要程式庫。本文也假設您具備網頁開發工作知識,包括 HTML、CSS 和 JavaScript。

在頁面中新增地圖

第一步是在網頁中加入地圖。這張地圖會以可選取的圖釘顯示地點搜尋元素結果。

在網頁中加入地圖的方式有兩種:

  1. 使用 gmp-map HTML 網頁元件
  2. 使用 JavaScript

本頁的程式碼片段是使用 JavaScript 地圖產生。

地圖可以以使用者要搜尋的地點 (例如飯店) 為中心,也可以初始化為要求使用者提供目前位置,然後以該位置為中心。為方便說明,本文將使用固定位置做為搜尋錨點。

如果想顯示固定位置 (例如飯店) 附近的地點,請在地圖上放置標記來代表這個地點。例如:

圖片

地圖中心位於舊金山,藍色圖釘代表我們在附近搜尋的地點。圖釘顏色已使用 PinElement 自訂。「地圖類型」控制項已從使用者介面隱藏。

設定 Place Search 元素

現在,我們可以設定 HTML 和 CSS,顯示地點搜尋元素。在本範例中,我們將元素浮動至地圖左側,但建議您嘗試不同的版面配置,以符合應用程式需求。

地點搜尋元素採用宣告式方法。您不必完全在 JavaScript 中設定,只要在主要 <gmp-place-search> 元件內,將要求元素 (例如 <gmp-place-nearby-search-request>) 巢狀化,即可直接在 HTML 中定義搜尋類型。

在 HTML 程式碼中,初始化 <gmp-place-search> 元素。使用 selectable 屬性,即可啟用結果的點擊事件。在其中新增 <gmp-place-nearby-search-request>,指定這個元素將用於鄰近搜尋。

<gmp-place-search selectable>
  <gmp-place-nearby-search-request>
  </gmp-place-nearby-search-request>
</gmp-place-search>

如要執行初始搜尋並顯示結果,我們將使用 JavaScript 取得巢狀要求元素的參照,並設定其屬性。初始化 Circle 做為 locationRestriction,並使用上一個步驟的標記位置做為中心點。接著,在要求元素上設定 locationRestrictionincludedPrimaryTypes 屬性,觸發搜尋。

程式碼片段如下:

// Get references to the Place Search and its nested request element
const placeSearchElement = document.querySelector("gmp-place-search");
const placeSearchRequestElement = document.querySelector("gmp-place-nearby-search-request");

// Define the location restriction for the search
const circleRestriction = new Circle({
    center: marker.position,
    radius: 500
});

// Set the properties on the request element to perform an initial search for restaurants.
placeSearchRequestElement.locationRestriction = circleRestriction;
placeSearchRequestElement.includedPrimaryTypes = ['restaurant'];

應用程式在這個階段的可能樣貌如下:

圖片

地點搜尋元素提供兩種搜尋選項:

這些是 <gmp-place-search> 內的巢狀元素。然後使用 JavaScript 在該巢狀要求元素上設定屬性,觸發搜尋。

本節將說明如何實作這兩種方法。

圖片

如要允許使用者執行附近搜尋,您必須先提供 UI 元素,供使用者選取地點類型。選擇最適合應用程式的選取方法,例如填入一系列地點類型的下拉式清單。

建議您選擇與用途相關的類型子集。 舉例來說,如果您要開發應用程式,向觀光客顯示飯店附近的景點,可以選擇:bakerycoffee_shopmuseumrestauranttourist_attraction

HTML 應包含 <gmp-place-search> 元素,且其中巢狀內含 <gmp-place-nearby-search-request>

<gmp-place-search selectable>
  <gmp-place-nearby-search-request>
  </gmp-place-nearby-search-request>
</gmp-place-search>

接著,在地點類型選取器上,為 change 事件建立 JavaScript 監聽器。這個監聽器會呼叫函式,更新 <gmp-place-nearby-search-request> 元素的屬性,自動觸發新的搜尋並更新清單。

// Get a reference to the nested request element
const placeSearchRequestElement = document.querySelector('gmp-place-nearby-search-request');

// Function to update the place search based on the selected type
function updatePlaceList() {
    const selectedType = placeTypeSelect.value;
    if (!selectedType) {
        // If no type is selected, don't perform a search.
        // You could optionally hide the list or clear previous results here.
        placeSearchElement.style.display = 'none';
        return;
    }
    placeSearchElement.style.display = 'block';

    // Set properties on the request element to trigger a new search
    placeSearchRequestElement.locationRestriction = searchCircle;
    placeSearchRequestElement.maxResultCount = 8;
    placeSearchRequestElement.includedPrimaryTypes = [selectedType];
}

locationRestriction 使用的 searchCircle 與設定步驟相同。includedPrimaryTypes 屬性會設為使用者選取的值。您也可以設定選用的 maxResultCount,限制結果數量。

圖片

如要啟用文字搜尋功能,必須變更 HTML 設定。您會巢狀嵌入 <gmp-place-text-search-request> 元素,而不是附近的搜尋要求。

<gmp-place-search selectable>
  <gmp-place-text-search-request>
  </gmp-place-text-search-request>
</gmp-place-search>

在 UI 中新增文字輸入內容和搜尋按鈕。為按鈕的 click 事件建立 JavaScript 監聽器。事件處理常式會接收使用者輸入內容,並更新 <gmp-place-text-search-request> 元素的屬性來執行搜尋。

// Get a reference to the text search request element
const placeTextSearchRequestElement = document.querySelector('gmp-place-text-search-request');
const textSearchInput = document.getElementById('textSearchInput');
const textSearchButton = document.getElementById('textSearchButton');

textSearchButton.addEventListener('click', performTextSearch);

function performTextSearch() {
    const query = textSearchInput.value.trim();
    if (!query) {
        console.log("Search query is empty.");
        return;
    }
    // Set properties on the request element to trigger a new search
    placeTextSearchRequestElement.textQuery = query;
    placeTextSearchRequestElement.locationBias = map.getBounds();
    placeTextSearchRequestElement.maxResultCount = 8;
}

在這裡,我們使用使用者的輸入內容設定 textQuery 屬性。我們也提供locationBias,使用目前的地图边界,告知 API 优先选择该区域内的结果,但不会严格限制结果。選用的 maxResultCount 會限制傳回的結果數。

顯示地點圖釘和詳細資料

現在應用程式可以執行地點搜尋,並填入元素。在下一個步驟中,我們會透過下列方式強化其功能:

  • 在地圖上顯示地點搜尋元素中填入的每個地點的圖釘。
  • 允許使用者點選圖釘或「地點搜尋」元素中的地點,以顯示該特定地點的詳細資料。

無論應用程式是使用鄰近搜尋或文字搜尋,這個步驟的原則都相同。

首先,請在 JavaScript 程式碼中加入全域變數,儲存地點標記。 這樣一來,您就能在搜尋內容變更時移除這些項目,並處理點擊事件。

let markers = {};

建立函式,在地圖中加入標記。每當載入新的搜尋結果時,系統就會呼叫這個函式。這項功能可:

  • 從地圖中移除所有現有的地點標記。
  • 逐一查看地點搜尋元素傳回的結果,並為每個結果新增標記。
  • 調整地圖的邊界,確保所有新標記都顯示在地圖上。

如要監聽搜尋結果何時可用,請將 gmp-load 事件監聽器新增至 <gmp-place-search> 元素。搜尋完成並顯示結果後,系統會觸發這個事件。

我們會在搜尋函式中新增事件監聽器 (例如 updatePlaceList),並使用 { once: true } 選項,確保只針對目前搜尋的結果觸發。

// In your search function, after setting the request properties:
placeSearchElement.addEventListener('gmp-load', addMarkers, { once: true });

addMarkers 函式如下所示:

async function addMarkers() {
    const { LatLngBounds } = await google.maps.importLibrary("core");
    const bounds = new LatLngBounds();

    if (placeSearchElement.places.length > 0) {
        // Remove existing markers
        for (const m in markers) {
            markers[m].map = null;
        }
        markers = {};

        // Loop through each place from the search results
        // and add a marker for each one.
        for (const place of placeSearchElement.places) {
            const marker = new google.maps.marker.AdvancedMarkerElement({
                map: map,
                position: place.location,
            });

            markers[place.id] = marker;
            bounds.extend(place.location);
            marker.collisionBehavior = google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL;

            // Add a click listener for each marker.
            marker.addListener('gmp-click', (event) => {
                // The main logic for showing details will go here.
            });
        }
        // Position the map to display all markers.
        map.setCenter(bounds.getCenter());
        map.fitBounds(bounds);
    }
}

完成這個步驟後,應用程式會如下所示,並可顯示地點搜尋元素傳回的每個地點標記:

圖片

地圖上現在有標記,最後一個步驟是處理標記和元素點擊事件,顯示含有地點詳細資料的資訊視窗,這些資料由 Place Details Element 提供。在本範例中,我們將使用「Place Details Compact Element」

在程式碼中加入地點詳細資料精簡元素 HTML,例如:

<gmp-place-details-compact orientation="vertical" style="display: none;">
    <gmp-place-all-content></gmp-place-all-content>
    <gmp-place-attribution light-scheme-color="gray" dark-scheme-color="white"></gmp-place-attribution>
</gmp-place-details-compact>

style設為 display: none,系統只會在必要時顯示。 gmp-place-all-content 會傳遞至所有元素內容的算繪作業。如要選擇要顯示的內容,請參閱「地點詳細資料精簡元素」說明文件。

在 JavaScript 中建立全域變數,以保留 Place Details Compact 元素參照,並在初始化程式碼中填入此變數,例如:

let placeDetailsElement;
...
placeDetailsElement = document.querySelector('gmp-place-details-compact');

addMarkers 函式中,為每個標記新增 gmp-click 事件監聽器,並傳遞目前標記的地點 ID,設定地點詳細資料精簡元素來顯示地點詳細資料。

完成後,系統會開啟「資訊視窗」,顯示錨定在標記上的地點詳細資料精簡元素。

最後,地圖會定位在所選地點的可視區域,讓使用者看到該地點。

async function addMarkers() {
          ...
            marker.addListener('gmp-click', (event) => {
                //Set up Place Details Compact Widget
                placeDetailsElement.style.display = "block";
                // Remove any existing place request element
                const existingPlaceRequest = placeDetailsElement.querySelector('gmp-place-details-place-request');
                if (existingPlaceRequest) {
                    existingPlaceRequest.remove();
                }
                // Create and configure the new place request element
                const placeRequestElement = new google.maps.places.PlaceDetailsPlaceRequestElement({ place: place.id });
                // Prepend the new place request element to the main widget
                placeDetailsElement.prepend(placeRequestElement);
                if (infoWindow.isOpen) {
                    infoWindow.close();
                }
                infoWindow.setOptions({
                    content: placeDetailsElement
                });
                infoWindow.open({
                    anchor: marker,
                    map: map
                });
                // Position the map to show the selected place
                placeDetailsElement.addEventListener('gmp-load', () => {
                    map.fitBounds(place.viewport, { top: 500, left: 400 });
                });
            });
          ...
        });
    }
}

如要讓使用者點選地點清單元素中的地點,顯示地點詳細資料精簡元素,請在呼叫 configureFromSearchNearbyRequest 後,將下列內容新增至 JavaScript 程式碼。

placeSearchElement.addEventListener("gmp-select", ({ place }) => {
    if (markers[place.id]) {
        markers[place.id].click();
    }
});

完成這個步驟後,應用程式就能使用「附近搜尋」或「文字搜尋」填入地點清單元素。這項作業的結果會在地圖上顯示圖釘,按一下圖釘或「地點清單」元素中的地點,就會顯示「資訊視窗」,其中包含「地點詳細資料精簡」元素提供的地點詳細資料。

應用程式會如下所示:

圖片

結論

結合地點搜尋元素和地點詳細資料精簡元素,可簡化在 Google 地圖平台應用程式中新增豐富地點探索功能的方式。

立即試用 Places UI Kit,讓使用者透過附近地點搜尋和文字搜尋功能尋找及探索地點,並顯示豐富的地點詳細資料,提升使用者與地點探索應用情境的互動。

貢獻者

Henrik Valve | DevX 工程師