プレイス検索要素と Maps JavaScript API を使用して場所を検索する

目標

Google マップに Place Search Element を統合して、ユーザーが Nearby Search または Text Search を使用して場所を見つけられるようにする方法を学び、ユーザーが観光スポットを探索する機能を強化します。Place Details Compact Element を使用して、アプリケーションに表示される場所の詳細情報を提供します。

Place Search Element とは

Place Search Element は、Maps JavaScript API の Places UI キットの一部です。これは、アプリケーション内のリスト形式で場所検索の結果を直接レンダリングする HTML 要素です。この要素を使用すると、Nearby Search またはテキスト検索で見つかった場所を簡単に表示できるため、場所の発見をシームレスにユーザーに提供できます。ユーザーがリストから場所を選択すると、多くの場合、Info Window と Place Details Element を使用して、地図上にその場所の詳細を表示できます。

プレイスの発見を可視化する

次の図は、Place Search Element の動作例を示しています。左側には、レストランのリストが表示されます(Place Search Element)。レストランを選択すると、地図上の Info Window に詳細が表示され、地図の中心がその場所に移動します。

イメージ

場所の発見のユースケース

Place Search Element を統合すると、さまざまな業界のさまざまなアプリケーションを強化できます。

  • 旅行と観光: 旅行者が特定の地域の観光スポット、ホテル、特定の種類の料理を検索できるようにします。
  • 不動産: 購入者または賃借人が近くの学校、スーパーマーケット、公共交通機関のオプションを見つけられるようにします。
  • 物流とサービス: ドライバーが EV 充電スタンド、ガソリン スタンド、特定のサービス センターを見つけられるようにします。

ソリューションのワークフロー: 場所の発見の実装

このセクションでは、地図上の場所を検出するための Place Search Element の統合手順について説明します。Places UI キットを操作するためのコード スニペットも含まれています。地図の初期化と、Nearby Search と テキスト検索 の両方の機能の実装について説明します。最後に、Place Details Element を使用して、地図上のピンをクリックしたときに特定の場所の詳細を表示します。

前提条件

次のドキュメントをよく理解しておくことをおすすめします。

  • Place Search Element - Nearby Search または テキスト検索 を使用して場所を公開するために使用します。
  • Place Details Element - 個々の場所の詳細を表示するために使用します。
  • Maps JavaScript API - ページに地図を表示し、Places UI キットをインポートするために使用します。

プロジェクトで Maps JavaScript APIPlaces UI Kit を有効にします。

開始する前に、Maps JavaScript API を読み込み、必要な ライブラリ をインポートしていることを確認してください。このドキュメントでは、HTML、CSS、JavaScript など、ウェブ開発に関する実用的な知識があることを前提としています。

ページに地図を追加する

まず、ページに地図を追加します。この地図は、Place Search Element の結果を選択可能なピンとして表示するために使用されます。

ページに地図を追加するには、次の 2 つの方法があります。

  1. gmp-map HTML ウェブ コンポーネントを使用する。
  2. JavaScript を使用する。

このページのコード スニペットは、JavaScript マップを使用して生成されました。

地図は、ユーザーが検索する場所(ホテルなど)を中心にするか、地図の中心にユーザーの現在地を表示するように初期化できます。このドキュメントでは、検索の基準となる固定の場所を使用します。

ホテルなどの固定された場所の近くの場所を可視化する場合は、地図上にマーカーを配置してその場所を表します。次に例を示します。

イメージ

地図の中心はサンフランシスコで、近くを検索する場所を表す青いピンが表示されています。ピンの色は PinElementを使用してカスタマイズされています。 地図タイプ コントロールは UI から非表示になっています 。

Place Search Element を設定する

これで、Place Search Element を表示するように HTML と CSS を設定できます。この例では、要素を地図の左側にフローティングしますが、アプリケーションに合わせてさまざまなレイアウトを試すことをおすすめします。

Place Search Element は宣言型アプローチを使用します。JavaScript で完全に構成するのではなく、メインの <gmp-place-search> コンポーネント内にリクエスト要素(<gmp-place-nearby-search-request> など)をネストして、HTML で検索タイプを直接定義します。

HTML コード内で <gmp-place-search> 要素を初期化します。selectable 属性を使用して、結果に対するクリック イベントを有効にします。その中に <gmp-place-nearby-search-request>を追加して、この要素を Nearby Search に使用することを指定します。

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

最初の検索を実行して結果を表示するには、JavaScript を使用してネストされたリクエスト要素への参照を取得し、そのプロパティを設定します。前のステップのマーカーの位置を中心点として使用して、locationRestriction として使用する Circle を初期化します。次に、リクエスト要素の locationRestriction プロパティと includedPrimaryTypes プロパティを設定して、検索をトリガーします。

これのコード スニペットは次のとおりです。

// 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'];

この段階でのアプリケーションの外観の例を次に示します。

イメージ

Place Search Element では、次の 2 つの検索オプションを使用できます。

  • <gmp-place-nearby-search-request> - Place Types を使用して、Places Nearby Search の検索結果をレンダリングします。
  • <gmp-place-text-search-request> - 「サンフランシスコの寿司」などのフリーテキスト 入力を使用して、プレイス テキスト検索 の検索結果を表示します。

これらは <gmp-place-search> 内のネストされた要素です。次に、JavaScript を使用して、ネストされたリクエスト要素のプロパティを設定して検索をトリガーします。

このセクションでは、両方の方法の実装について説明します。

イメージ

ユーザーが Nearby Search を実行できるようにするには、まず Place Type を選択するための 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];
}

設定ステップと同じ searchCirclelocationRestriction に使用されます。includedPrimaryTypes プロパティは、ユーザーの選択の値に設定されます。オプションの maxResultCount も設定して、結果の数を制限します。

イメージ

Text Search を有効にするには、HTML 構成を変更する必要があります。Nearby Search リクエストの代わりに、<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 は、返される結果の数を制限します。

場所のピンと詳細を表示する

これで、アプリケーションは場所検索を実行して要素を入力できます。次のステップでは、次の方法で機能を強化します。

  • Place Search Element に入力された各場所のピンを地図上に表示します。
  • ユーザーがピンまたは Place Search Element 内の場所をクリックして、その場所の詳細を表示できるようにします。

このステップの原則は、アプリケーションが Nearby Search と Text Search のどちらを使用している場合でも同じです。

まず、場所マーカーを保存するグローバル変数を JavaScript コードに追加します。これにより、検索が変更されたときにマーカーを削除し、クリック イベントを処理できます。

let markers = {};

地図にマーカーを追加する関数を作成します。この関数は、新しい検索結果が読み込まれるたびに呼び出されます。次の処理を行います。

  • 地図から既存の場所マーカーを削除します。
  • Place Search Element の結果をループ処理し、それぞれにマーカーを追加します。
  • 新しいマーカーがすべて表示されるように、地図の境界を調整します。

検索結果が利用可能になったときにリッスンするには、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 Search Element によって返された各プレイスのマーカーを表示できます。

イメージ

地図上にマーカーが表示されたので、最後のステップでは、マーカーと 要素のクリック イベントを処理して、Place Details Element によって提供される場所の詳細を含む Info Window を表示します。この 例では、Place Details Compact 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>

styledisplay: none に設定されています。必要になるまで表示されません。gmp-place-all-content が渡されて、すべての要素コンテンツがレンダリングされます。レンダリングする コンテンツを選択するには、Place Details Compact Element のドキュメントをご覧ください。

JavaScript でグローバル変数を作成して Place Details Compact Element への参照を保持し、初期化コードで入力します。次に例を示します。

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

addMarkers 関数内で、各マーカーに gmp-click イベント リスナーを追加し、現在のマーカーのプレイス ID を渡して場所の詳細を表示するように Place Details Compact Element を構成します。

完了すると、Info Window が開き、マーカーに固定された Place Details Compact Element が表示されます。

最後に、地図が選択した場所のビューポートに配置され、表示されます。

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

ユーザーが Place List Element 内の場所をクリックして Place Details Compact Element を表示できるようにするには、configureFromSearchNearbyRequest の呼び出し後に次のコードを JavaScript コードに追加します。

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

このステップが完了すると、アプリケーションは Nearby Search または テキスト検索 を使用して Place List Element にデータを入力できるようになります。これにより、地図上にピンが表示され、ピンまたは Place List Element 内の場所をクリックすると、Place Details Compact Element によって提供される場所の詳細を含む情報ウィンドウが表示されます。

アプリケーションは次のようになります。

イメージ

まとめ

Place Search Element と Place Details Compact Element を組み合わせることで、Google Maps Platform アプリケーションに豊富な場所発見機能を追加できます。

今すぐ Places UI キット をお試しください。 Nearby Search と テキスト検索 の両方を使用して場所を見つけて探索し、豊富な Place Details を表示することで、 場所発見のユースケースでのユーザーの操作性を高めることができます。

コントリビューター

Henrik Valve | DevX エンジニア