Ricerca nelle vicinanze

Seleziona la piattaforma:Android iOS JavaScript Servizio web
Sviluppatori dello Spazio economico europeo (SEE)

Nearby Search (New) accetta uno o più tipi di luoghi e restituisce un elenco di luoghi corrispondenti. Nell'esempio seguente, puoi scegliere un tipo di luogo e visualizzare i risultati su una mappa. Fai clic sugli indicatori per visualizzare ulteriori dettagli sui luoghi.

Nearby Search (New) restituisce informazioni su un insieme di luoghi in base ai tipi di luoghi specificati, ad esempio restaurant, book_store o bowling_alley. Il servizio risponde con un elenco di luoghi corrispondenti ai tipi di luoghi specificati entro il raggio del locationRestriction specificato.

Per utilizzare Nearby Search (New), devi abilitare "API Places (New)" nel tuo progetto Google Cloud. Per maggiori dettagli, consulta Inizia.

Trova luoghi nelle vicinanze

Chiama searchNearby() per restituire un elenco di luoghi in base ai tipi di luoghi, alla località e al raggio specificati. Specifica i parametri di ricerca utilizzando una richiesta, quindi chiama searchNearby(). I risultati vengono restituiti come un elenco di oggetti Place, da cui puoi ottenere i Place Details. Il seguente snippet mostra un esempio di richiesta e una chiamata a 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);
  • Utilizza il parametro fields (obbligatorio) per specificare un elenco separato da virgole di uno o più campi di dati. I campi richiesti determinano il prezzo della richiesta. Consulta Scegli i campi di dati.
  • Utilizza il parametro locationRestriction (obbligatorio) per specificare un raggio fino a 50.000 metri.
  • Utilizza il parametro includedPrimaryTypes per specificare uno o più tipi di luoghi da cercare.
  • Utilizza il parametro rankPreference per specificare un SearchNearbyRankPreference di POPULARITY o DISTANCE.
  • Consulta l'elenco completo dei parametri.

Esempio

L'esempio seguente utilizza searchNearby() per eseguire query sui luoghi del tipo selezionato all'interno dei limiti della mappa e compila una mappa con indicatori per mostrare i risultati.

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>

Scegli i campi di dati

I campi richiesti determinano il prezzo di ogni richiesta di ricerca. La richiesta viene fatturata una volta, allo SKU più alto tra i campi richiesti. Ad esempio, l'aggiunta di reviews a fields comporta la fatturazione dell'intera richiesta come Nearby Search Enterprise + Atmosphere.

Per mantenere le richieste di ricerca in Nearby Search Pro, richiedi solo i campi mostrati dai risultati di ricerca, ad esempio id, displayName, formattedAddress e location.

Quando un utente seleziona un luogo, chiama fetchFields() su quel luogo per ottenere campi come reviews, nationalPhoneNumber o websiteURI. Ogni chiamata fetchFields() è una richiesta Place Details separata, fatturata in base allo SKU più alto tra i campi richiesti. Il risparmio di denaro con questo approccio dipende dal numero di luoghi aperti dagli utenti.

Campi che attivano ogni SKU

  • I seguenti campi attivano lo SKU Nearby Search Pro:

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

  • I seguenti campi attivano lo SKU Nearby Search Enterprise:

    internationalPhoneNumber
    nationalPhoneNumber
    priceLevel
    rating
    regularOpeningHours
    userRatingCount
    websiteURI

  • I seguenti campi attivano lo SKU Nearby Search 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

Per lo SKU di ogni campo, consulta Campi di dati della classe Place.