Wyszukiwanie w pobliżu

Deweloperzy z Europejskiego Obszaru Gospodarczego (EOG)

Wyszukiwanie w pobliżu (nowe) przyjmuje co najmniej 1 typ miejsca i zwraca listę pasujących miejsc. W poniższym przykładzie możesz wybrać typ miejsca i zobaczyć wyniki na mapie. Kliknij znaczniki, aby zobaczyć więcej informacji o miejscach.

Wyszukiwanie w pobliżu (nowe) zwraca informacje o zbiorze miejsc na podstawie określonych przez Ciebie typów miejsc, np. restaurant, book_store lub bowling_alley. Usługa odpowiada listą miejsc pasujących do określonych typów miejsc w promieniu określonego locationRestriction.

Aby korzystać z wyszukiwania w pobliżu (nowego), musisz włączyć „Places API (New)” w projekcie Google Cloud. Więcej informacji znajdziesz w artykule Pierwsze kroki.

Znajdź miejsca w pobliżu

Wywołaj searchNearby(), aby zwrócić listę miejsc na podstawie określonych typów miejsc, lokalizacji i promienia. Określ parametry wyszukiwania za pomocą żądania, a następnie wywołaj searchNearby(). Wyniki są zwracane jako lista obiektów Place, z których możesz uzyskać informacje o miejscu. Poniższy fragment kodu pokazuje przykład żądania i wywołania metody searchNearby():

TypeScript

// Get bounds and radius to constrain search.
center = mapElement.center!;
const ne = innerMap.getBounds()!.getNorthEast();
const sw = innerMap.getBounds()!.getSouthWest();
const diameter = spherical.computeDistanceBetween(ne, sw);
const radius = Math.min(diameter / 2, 50000); // Radius cannot be more than 50000.

const request = {
    // required parameters
    fields: [
        'displayName',
        'location',
        'formattedAddress',
        'googleMapsURI',
    ],
    locationRestriction: {
        center,
        radius,
    },
    // optional parameters
    includedPrimaryTypes: [typeSelect.value],
    maxResultCount: 5,
    rankPreference: SearchNearbyRankPreference.POPULARITY,
};

const { places } = await Place.searchNearby(request);

JavaScript

// Get bounds and radius to constrain search.
center = mapElement.center;
const ne = innerMap.getBounds().getNorthEast();
const sw = innerMap.getBounds().getSouthWest();
const diameter = spherical.computeDistanceBetween(ne, sw);
const radius = Math.min(diameter / 2, 50000); // Radius cannot be more than 50000.

const request = {
    // required parameters
    fields: [
        'displayName',
        'location',
        'formattedAddress',
        'googleMapsURI',
    ],
    locationRestriction: {
        center,
        radius,
    },
    // optional parameters
    includedPrimaryTypes: [typeSelect.value],
    maxResultCount: 5,
    rankPreference: SearchNearbyRankPreference.POPULARITY,
};

const { places } = await Place.searchNearby(request);
  • Użyj parametru fields (wymagany), aby określić listę rozdzieloną przecinkami zawierającą co najmniej 1 pole danych. Pola, o które prosisz, określają cenę żądania. Zobacz Wybieranie pól danych.
  • Użyj parametru locationRestriction (wymagany), aby określić promień do 50 000 metrów.
  • Użyj parametru includedPrimaryTypes, aby określić co najmniej 1 typ miejsca do wyszukania.
  • Użyj parametru rankPreference, aby określić SearchNearbyRankPreference o wartości POPULARITY lub DISTANCE.
  • Zobacz pełną listę parametrów

Przykład

W tym przykładzie użyto searchNearby() do wyszukiwania miejsc wybranego typu w granicach mapy i wypełnienia mapy znacznikami, aby wyświetlić wyniki.

TypeScript

const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;
let center: google.maps.LatLngLiteral | google.maps.LatLng;
let typeSelect: HTMLSelectElement;
let infoWindow: google.maps.InfoWindow;

async function init() {
    const [{ InfoWindow }, { event }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('core'),
    ]);

    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });

    typeSelect = document.querySelector('.type-select')!;

    typeSelect.addEventListener('change', () => {
        void nearbySearch();
    });

    infoWindow = new InfoWindow();

    // Kick off an initial search once map has loaded.
    event.addListenerOnce(innerMap, 'idle', () => {
        void nearbySearch();
    });
}

async function nearbySearch() {
    const [
        { Place, SearchNearbyRankPreference },
        { AdvancedMarkerElement },
        { spherical },
    ] = await Promise.all([
        google.maps.importLibrary('places'),
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('geometry'),
    ]);
    // Get bounds and radius to constrain search.
    center = mapElement.center!;
    const ne = innerMap.getBounds()!.getNorthEast();
    const sw = innerMap.getBounds()!.getSouthWest();
    const diameter = spherical.computeDistanceBetween(ne, sw);
    const radius = Math.min(diameter / 2, 50000); // Radius cannot be more than 50000.

    const request = {
        // required parameters
        fields: [
            'displayName',
            'location',
            'formattedAddress',
            'googleMapsURI',
        ],
        locationRestriction: {
            center,
            radius,
        },
        // optional parameters
        includedPrimaryTypes: [typeSelect.value],
        maxResultCount: 5,
        rankPreference: SearchNearbyRankPreference.POPULARITY,
    };

    const { places } = await Place.searchNearby(request);

    if (places.length) {
        const { LatLngBounds } = await google.maps.importLibrary('core');
        const bounds = new LatLngBounds();

        // First remove all existing markers.
        for (const marker of mapElement.querySelectorAll('gmp-advanced-marker'))
            marker.remove();

        // Loop through and get all the results.
        places.forEach((place) => {
            if (!place.location) return;
            bounds.extend(place.location);

            const marker = new AdvancedMarkerElement({
                map: innerMap,
                position: place.location,
                title: place.displayName,
                gmpClickable: true,
            });

            // Build the content of the InfoWindow safely using DOM elements.
            const content = document.createElement('div');
            const address = document.createElement('div');
            address.textContent = place.formattedAddress || '';
            const placeId = document.createElement('div');
            placeId.textContent = place.id;
            content.append(address, placeId);

            if (place.googleMapsURI) {
                const link = document.createElement('a');
                link.href = place.googleMapsURI;
                link.target = '_blank';
                link.textContent = 'View Details on Google Maps';
                content.appendChild(link);
            }

            marker.addEventListener('gmp-click', () => {
                innerMap.panTo(place.location!);
                updateInfoWindow(place.displayName!, content, marker);
            });
        });

        innerMap.fitBounds(bounds, 100);
    } else {
        console.log('No results');
    }
}

function updateInfoWindow(
    title: string | Element | null,
    content: string | Element | null,
    anchor: google.maps.marker.AdvancedMarkerElement
) {
    infoWindow.setContent(content);
    infoWindow.setHeaderContent(title);
    infoWindow.open({
        anchor,
    });
}

void init();

JavaScript

const mapElement = document.querySelector('gmp-map');
let innerMap;
let center;
let typeSelect;
let infoWindow;

async function init() {
    const [{ InfoWindow }, { event }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('core'),
    ]);

    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });

    typeSelect = document.querySelector('.type-select');

    typeSelect.addEventListener('change', () => {
        void nearbySearch();
    });

    infoWindow = new InfoWindow();

    // Kick off an initial search once map has loaded.
    event.addListenerOnce(innerMap, 'idle', () => {
        void nearbySearch();
    });
}

async function nearbySearch() {
    const [
        { Place, SearchNearbyRankPreference },
        { AdvancedMarkerElement },
        { spherical },
    ] = await Promise.all([
        google.maps.importLibrary('places'),
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('geometry'),
    ]);
    // Get bounds and radius to constrain search.
    center = mapElement.center;
    const ne = innerMap.getBounds().getNorthEast();
    const sw = innerMap.getBounds().getSouthWest();
    const diameter = spherical.computeDistanceBetween(ne, sw);
    const radius = Math.min(diameter / 2, 50000); // Radius cannot be more than 50000.

    const request = {
        // required parameters
        fields: [
            'displayName',
            'location',
            'formattedAddress',
            'googleMapsURI',
        ],
        locationRestriction: {
            center,
            radius,
        },
        // optional parameters
        includedPrimaryTypes: [typeSelect.value],
        maxResultCount: 5,
        rankPreference: SearchNearbyRankPreference.POPULARITY,
    };

    const { places } = await Place.searchNearby(request);

    if (places.length) {
        const { LatLngBounds } = await google.maps.importLibrary('core');
        const bounds = new LatLngBounds();

        // First remove all existing markers.
        for (const marker of mapElement.querySelectorAll('gmp-advanced-marker'))
            marker.remove();

        // Loop through and get all the results.
        places.forEach((place) => {
            if (!place.location) return;
            bounds.extend(place.location);

            const marker = new AdvancedMarkerElement({
                map: innerMap,
                position: place.location,
                title: place.displayName,
                gmpClickable: true,
            });

            // Build the content of the InfoWindow safely using DOM elements.
            const content = document.createElement('div');
            const address = document.createElement('div');
            address.textContent = place.formattedAddress || '';
            const placeId = document.createElement('div');
            placeId.textContent = place.id;
            content.append(address, placeId);

            if (place.googleMapsURI) {
                const link = document.createElement('a');
                link.href = place.googleMapsURI;
                link.target = '_blank';
                link.textContent = 'View Details on Google Maps';
                content.appendChild(link);
            }

            marker.addEventListener('gmp-click', () => {
                innerMap.panTo(place.location);
                updateInfoWindow(place.displayName, content, marker);
            });
        });

        innerMap.fitBounds(bounds, 100);
    } else {
        console.log('No results');
    }
}

function updateInfoWindow(title, content, anchor) {
    infoWindow.setContent(content);
    infoWindow.setHeaderContent(title);
    infoWindow.open({
        anchor,
    });
}

void init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
gmp-map {
    height: 100%;
}

#map-container {
    display: flex;
    flex-direction: row;
    height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

.type-select {
    width: 400px;
    height: 32px;
    border: 1px solid #000;
    border-radius: 10px;
    flex-grow: 1;
    padding: 0 10px;
    margin-left: 10px;
    margin-top: 10px;
}

HTML

<html>
    <head>
        <title>Nearby Search</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (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: "GOOGLE_MAPS_API_KEY" 
            });
        </script>
    </head>

    <body>
        <gmp-map center="45.438646,12.327573" zoom="14" map-id="DEMO_MAP_ID"
            ><!-- Map id is required for Advanced Markers. -->
            <gmp-advanced-marker></gmp-advanced-marker>
            <div id="controls" slot="control-inline-start-block-start">
                <select name="types" class="type-select">
                    <option value="cafe" selected>Cafe</option>
                    <option value="restaurant">Restaurant</option>
                    <option value="museum">Museum</option>
                    <option value="monument">Monument</option>
                    <option value="park">Park</option>
                </select>
            </div>
        </gmp-map>
    </body>
</html>

Wybierz pola danych

Pola, o które prosisz, określają cenę każdego żądania wyszukiwania. Żądanie jest rozliczane raz, według najwyższej ceny SKU wśród żądanych pól. Na przykład dodanie reviews do fields powoduje, że całe żądanie jest rozliczane jako wyszukiwanie w pobliżu w wersji Enterprise + Atmosphere.

Aby zachować żądania wyszukiwania w wyszukiwaniu w pobliżu Pro, poproś tylko o pola, które są wyświetlane w wynikach wyszukiwania, takie jak id, displayName, formattedAddress i location.

Gdy użytkownik wybierze miejsce, wywołaj fetchFields() dla tego miejsca, aby uzyskać pola takie jak reviews, nationalPhoneNumber lub websiteURI. Każde wywołanie fetchFields() jest osobnym żądaniem informacji o miejscu, rozliczanym według najwyższego SKU spośród żądanych pól. To, czy to podejście pozwoli zaoszczędzić pieniądze, zależy od liczby miejsc, które otwierają użytkownicy.

Pola, które aktywują poszczególne kody SKU

  • Te pola aktywują kod SKU Wyszukiwanie w pobliżu (Pro):

    accessibilityOptions
    addressComponents
    adrFormatAddress
    businessStatus
    displayName
    formattedAddress
    googleMapsUri
    iconBackgroundColor
    id
    location
    photos
    plusCode
    svgIconMaskURI
    types
    utcOffsetMinutes
    viewport

  • Te pola aktywują kod SKU wyszukiwania w pobliżu w wersji Enterprise:

    internationalPhoneNumber
    nationalPhoneNumber
    priceLevel
    rating
    regularOpeningHours
    userRatingCount
    websiteURI

  • Te pola aktywują kod SKU Wyszukiwanie w pobliżu Enterprise + Atmosphere:

    allowsDogs
    editorialSummary
    evChargeOptions
    fuelOptions
    hasCurbsidePickup
    hasDelivery
    hasDineIn
    hasLiveMusic
    hasMenuForChildren
    hasOutdoorSeating
    hasRestroom
    hasTakeout
    hasWifi
    isGoodForChildren
    isGoodForGroups
    isGoodForWatchingSports
    isReservable
    parkingOptions
    paymentOptions
    reviews
    servesBeer
    servesBreakfast
    servesBrunch
    servesCocktails
    servesCoffee
    servesDessert
    servesDinner
    servesLunch
    servesVegetarianFood
    servesWine

Informacje o kodzie SKU każdego pola znajdziesz w artykule Pola danych klasy Place.