PlaceSearchElement를 사용한 장소 검색

목표

Google 지도와 PlaceSearchElement를 통합하여 사용자가 주변 검색 또는 텍스트 검색을 사용하여 장소를 찾을 수 있도록 하고 관심 지점을 탐색하는 기능을 개선하는 방법을 알아봅니다. Place Details Compact Element를 사용하여 애플리케이션에 표시된 장소에 관한 세부정보를 더 제공합니다.

을 진행하세요.

PlaceSearchElement란 무엇인가요?

PlaceSearchElement는 Maps JavaScript API의 장소 UI 키트의 일부입니다. 애플리케이션 내의 목록 형식으로 장소 검색 결과를 직접 렌더링하는 HTML 요소입니다. 이 요소는 주변 지역 검색 또는 텍스트 검색을 사용하여 찾은 장소를 표시하는 프로세스를 간소화하여 장소 검색을 위한 원활한 사용자 환경을 제공합니다. 사용자가 목록에서 장소를 선택하면 정보 창 및 장소 세부정보 요소를 사용하여 지도에 세부정보를 표시할 수 있습니다.

장소 검색 시각화

다음 이미지는 작동 중인 PlaceSearchElement의 예를 보여줍니다. 왼쪽에는 식당 목록 (PlaceSearchElement)이 표시됩니다. 식당을 선택하면 지도에 Info Window에 세부정보가 표시되고 지도가 식당의 위치를 중심으로 이동합니다.

이미지

장소 검색 사용 사례

PlaceSearchElement를 통합하면 다양한 업계의 여러 애플리케이션을 개선할 수 있습니다.

  • 여행 및 관광: 관광객이 특정 지역에서 관광 명소, 호텔 또는 특정 유형의 요리를 검색할 수 있도록 합니다.
  • 부동산: 잠재적 구매자 또는 임차인이 주변 학교, 슈퍼마켓 또는 대중교통 옵션을 찾을 수 있도록 합니다.
  • 물류 및 서비스: 운전자가 EV 충전소, 주유소 또는 특정 서비스 센터를 찾는 데 도움을 줍니다.

솔루션 워크플로: 장소 검색 구현

이 섹션에서는 PlaceSearchElement를 통합하여 지도에서 장소를 검색하는 방법을 안내하며 장소 UI 키트와 상호작용하기 위한 코드 스니펫을 포함합니다. 지도를 초기화하고 주변 검색과 텍스트 검색을 모두 구현하는 방법을 알아봅니다. 마지막으로 사용자가 지도에서 핀을 클릭할 때 Place Details Element를 사용하여 장소 세부정보를 더 표시합니다.

기본 요건

다음 문서를 숙지하는 것이 좋습니다.

  • PlaceSearchElement - 주변 지역 검색 또는 텍스트 검색을 사용하여 장소를 노출하는 데 사용됩니다.
  • 장소 세부정보 요소 - 개별 장소의 세부정보를 표시하는 데 사용됩니다.
  • Maps JavaScript API - 페이지에 지도를 표시하고 장소 UI 키트를 가져오는 데 사용됩니다.

프로젝트에서 Maps JavaScript API장소 UI 키트 를 사용 설정합니다.

시작하기 전에 Maps JavaScript API를 로드하고 필요한 라이브러리 를 가져왔는지 확인합니다. 이 문서에서는 HTML, CSS, JavaScript를 비롯한 웹 개발에 대한 실무 지식이 있다고 가정합니다.

페이지에 지도 추가

첫 번째 단계는 페이지에 지도를 추가하는 것입니다. 이 지도는 PlaceSearchElement 결과를 선택 가능한 핀으로 표시하는 데 사용됩니다.

페이지에 지도를 추가하는 방법에는 두 가지가 있습니다.

  1. gmp-map HTML 웹 구성요소 사용
  2. JavaScript 사용

이 페이지의 코드 스니펫은 JavaScript 지도를 사용하여 생성되었습니다.

지도는 호텔과 같이 사용자가 검색할 위치를 중심으로 이동하거나 지도를 중앙에 배치하기 위해 사용자의 현재 위치를 요청하도록 초기화할 수 있습니다. 이 문서에서는 검색을 고정하기 위해 고정된 위치를 사용합니다.

호텔과 같은 고정된 위치 근처의 장소를 시각화하는 경우 지도에 마커를 배치하여 이 장소를 나타냅니다. 예를 들면 다음과 같습니다.

이미지

지도는 샌프란시스코를 중심으로 이동하며 주변에서 검색하는 장소를 나타내는 파란색 핀이 있습니다. 핀 색상은 PinElement를 사용하여 맞춤설정되었습니다. 지도 유형 컨트롤이 UI에서 숨겨져 있습니다.

PlaceSearchElement 설정

이제 HTML 및 CSS를 설정하여 PlaceSearchElement를 표시합니다. 이 예에서는 요소가 지도의 왼쪽에 떠 있지만 애플리케이션에 맞게 다양한 레이아웃을 시도해 볼 수 있습니다.

PlaceSearchElement는 선언적 접근 방식을 사용합니다. 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를 사용하여 중첩된 요청 요소에 대한 참조를 가져오고 속성을 설정합니다. 이전 단계의 마커 위치를 중심점으로 사용하여 locationRestriction으로 사용할 Circle을 초기화합니다. 그런 다음 요청 요소에서 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'];

이 단계에서 애플리케이션이 어떻게 표시될 수 있는지 보여주는 예는 다음과 같습니다.

이미지

PlaceSearchElement는 두 가지 검색 옵션을 허용합니다.

  • <gmp-place-nearby-search-request> - 장소 유형을 사용하여 장소 주변 지역 검색의 검색 결과를 렌더링합니다.
  • <gmp-place-text-search-request> - '샌프란시스코의 스시'와 같은 자유 형식 텍스트 입력을 사용하여 장소 텍스트 검색의 검색 결과를 렌더링합니다.

이러한 요소는 <gmp-place-search> 내에 중첩된 요소입니다. 그런 다음 JavaScript를 사용하여 중첩된 요청 요소에서 속성을 설정하여 검색을 트리거합니다.

이 섹션에서는 두 가지 방법을 모두 구현하는 방법을 설명합니다.

이미지

사용자가 주변 검색을 실행할 수 있도록 하려면 먼저 장소 유형을 선택할 수 있는 UI 요소가 필요합니다. 장소 유형 선택으로 채워진 드롭다운 목록과 같이 애플리케이션에 가장 적합한 선택 방법을 선택합니다.

사용 사례와 관련된 유형의 하위 집합을 선택하는 것이 좋습니다. 예를 들어 관광객에게 호텔 주변의 장소를 보여주는 애플리케이션을 개발하는 경우 bakery, coffee_shop, museum, restaurant, tourist_attraction을 선택할 수 있습니다.

HTML에는 <gmp-place-nearby-search-request>가 중첩된 <gmp-place-search> 요소가 포함되어야 합니다.

<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도 결과 수를 제한하도록 설정됩니다.

이미지

텍스트 검색을 사용 설정하려면 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는 반환되는 결과 수를 제한합니다.

장소 핀 및 세부정보 표시

이제 애플리케이션에서 장소 검색을 실행하고 요소를 채울 수 있습니다. 다음 단계에서는 다음을 통해 기능을 개선합니다.

  • PlaceSearchElement에 채워진 각 장소에 대한 핀을 지도에 표시합니다.
  • 사용자가 핀 또는 PlaceSearchElement 내의 장소를 클릭하여 특정 장소에 관한 세부정보를 더 표시할 수 있도록 합니다.

이 단계의 원리는 애플리케이션에서 주변 검색을 사용하는지 텍스트 검색을 사용하는지에 관계없이 동일합니다.

먼저 JavaScript 코드에 전역 변수를 추가하여 장소 마커를 저장합니다. 이렇게 하면 검색이 변경될 때 마커를 삭제하고 클릭 이벤트를 처리할 수 있습니다.

let markers = {};

지도에 마커를 추가하는 함수를 만듭니다. 이 함수는 새 검색 결과가 로드될 때마다 호출됩니다. 이 함수는 다음 작업을 실행합니다.

  • 지도에서 기존 장소 마커를 삭제합니다.
  • PlaceSearchElement의 결과를 반복하고 각 결과에 마커를 추가합니다.
  • 새 마커가 모두 표시되도록 지도의 경계를 조정합니다.

검색 결과를 사용할 수 있는 시점을 수신 대기하려면 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);
    }
}

이 단계가 완료되면 애플리케이션은 다음과 같이 표시되며 PlaceSearchElement에서 반환된 각 장소에 대한 마커를 표시할 수 있습니다.

이미지

이제 지도에 마커가 있으므로 마지막 단계는 마커 및 요소 클릭 이벤트를 처리하여 Place Details Element에서 제공하는 장소 세부정보가 포함된 Info Window를 표시하는 것입니다. 이 예에서는 장소 세부정보 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는 모든 요소 콘텐츠를 렌더링하기 위해 전달됩니다. 렌더링할 콘텐츠를 선택하려면 장소 세부정보 Compact Element 문서를 참고하세요.

JavaScript에서 전역 변수를 만들어 장소 세부정보 Compact Element에 대한 참조를 보유하고 초기화 코드에서 이를 채웁니다(예:).

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

addMarkers 함수 내에서 각 마커에 gmp-click 이벤트 리스너를 추가하고 현재 마커의 장소 ID를 전달하여 장소 세부정보를 표시하도록 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 Details Compact Element를 표시할 수 있도록 하려면 configureFromSearchNearbyRequest 호출 후 JavaScript 코드에 다음을 추가합니다.

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

이 단계가 완료되면 애플리케이션에서 주변 지역 검색 또는 텍스트 검색을 사용하여 장소 목록 요소를 채울 수 있습니다. 결과로 지도에 핀이 표시되며 핀 또는 장소 목록 요소의 장소를 클릭하면 Place Details Compact Element에서 제공하는 장소 세부정보가 포함된 Info Window가 표시됩니다.

애플리케이션은 다음과 같이 표시됩니다.

이미지

결론

Place Details Compact Element와 결합된 PlaceSearchElement는 Google Maps Platform 애플리케이션에 다양한 장소 세부정보 검색 기능을 추가하는 간소화된 방법을 제공합니다.

지금 장소 UI 키트를 사용해 보세요. 사용자가 주변 검색과 텍스트 검색을 모두 사용하여 장소를 찾고 탐색하며 다양한 장소 세부정보를 표시하여 장소 검색 사용 사례와의 상호작용을 개선할 수 있습니다.

참여자

Henrik Valve | DevX 엔지니어