Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 56 additions & 63 deletions samples/ui-kit-place-search-nearby/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,83 +7,76 @@
<!doctype html>
<html>
<head>
<title>Place List Nearby Search with Google Maps</title>
<title>Place Search Nearby with Google Maps</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="module" src="./index.js"></script>
<script type="module" src="./index.js" defer></script>
<!-- prettier-ignore -->
<script>
(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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});
</script>
</head>
<body>
<!--[START maps_ui_kit_place_search_nearby_map] -->
<gmp-map center="-37.813,144.963" zoom="10" map-id="DEMO_MAP_ID">
<div class="overlay" slot="control-inline-start-block-start">

<div class="container">
<!-- map-id is required to use advanced markers. See https://developers.google.com/maps/documentation/javascript/map-ids/mapid-over. -->
<gmp-map center="-37.813,144.963" zoom="16" map-id="DEMO_MAP_ID">
</gmp-map>
<div class="ui-panel">
<div class="controls">
<select name="types" class="type-select">
<option value="">Select a place type</option>
<option value="cafe">Cafe</option>
<option value="restaurant">Restaurant</option>
<option value="electric_vehicle_charging_station">
EV charging station
</option>
</select>
<label for="type-select">
Select a place type:
<select id="type-select" class="type-select">
<option value="restaurant">Restaurant</option>
<option value="cafe" selected>Cafe</option>
<option value="electric_vehicle_charging_station">
EV charging station
</option>
</select>
</label>
</div>
<div class="list-container">
<gmp-place-list
selectable
style="display: none"></gmp-place-list>
<gmp-place-search selectable>
<gmp-place-all-content></gmp-place-all-content>
<gmp-place-nearby-search-request
max-result-count="5"></gmp-place-nearby-search-request>
</gmp-place-search>
</div>
</div>
</gmp-map>
</div>

<gmp-place-details style="display: none">
<!--
The gmp-place-details-compact element is styled inline because it is
conditionally rendered and moved into the info window, which is
part of the map's shadow DOM.
-->
<gmp-place-details-compact
orientation="horizontal"
truncation-preferred
style="
width: 400px;
padding: 0;
margin: 0;
border: none;
background-color: transparent;
color-scheme: light;
">
<gmp-place-details-place-request></gmp-place-details-place-request>
<gmp-place-all-content></gmp-place-all-content>
</gmp-place-details>
<gmp-place-content-config>
<gmp-place-media></gmp-place-media>
<gmp-place-rating></gmp-place-rating>
<gmp-place-price></gmp-place-price>
<gmp-place-accessible-entrance-icon></gmp-place-accessible-entrance-icon>
<gmp-place-open-now-status></gmp-place-open-now-status>
<gmp-place-attribution
light-scheme-color="gray"
dark-scheme-color="white"></gmp-place-attribution>
</gmp-place-content-config>
</gmp-place-details-compact>

<!--[END maps_ui_kit_place_search_nearby_map] -->
<script>
((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: 'AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8', v: 'alpha' });
</script>
</body>
</html>
<!--[END maps_ui_kit_place_search_nearby] -->
221 changes: 94 additions & 127 deletions samples/ui-kit-place-search-nearby/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,153 +6,120 @@
/* [START maps_ui_kit_place_search_nearby] */

/* [START maps_ui_kit_place_search_nearby_query_selectors] */
const map = document.querySelector('gmp-map') as any;
const placeList = document.querySelector('gmp-place-list') as any;
const typeSelect = document.querySelector('.type-select') as any;
const placeDetails = document.querySelector('gmp-place-details') as any;
const placeDetailsRequest = document.querySelector(
// Query selectors for various elements in the HTML file.
const map = document.querySelector('gmp-map') as google.maps.MapElement;
const placeSearch = document.querySelector('gmp-place-search') as any;
const placeSearchQuery = document.querySelector(
'gmp-place-nearby-search-request'
) as any;
const placeDetails = document.querySelector('gmp-place-details-compact') as any;
const placeRequest = document.querySelector(
'gmp-place-details-place-request'
) as any;
const typeSelect = document.querySelector('.type-select') as HTMLSelectElement;
/* [END maps_ui_kit_place_search_nearby_query_selectors] */
let markers = {};
let infoWindow;

async function initMap(): Promise<void> {
await google.maps.importLibrary('places');
const { LatLngBounds } = (await google.maps.importLibrary(
'core'
)) as google.maps.CoreLibrary;
const { InfoWindow } = (await google.maps.importLibrary(
'maps'
)) as google.maps.MapsLibrary;
const { spherical } = (await google.maps.importLibrary(
'geometry'
)) as google.maps.GeometryLibrary;

infoWindow = new InfoWindow();
let marker;

function getContainingCircle(bounds) {
const diameter = spherical.computeDistanceBetween(
bounds.getNorthEast(),
bounds.getSouthWest()
);
const calculatedRadius = diameter / 2;
const cappedRadius = Math.min(calculatedRadius, 50000); // Radius cannot be more than 50000.
return { center: bounds.getCenter(), radius: cappedRadius };
}

findCurrentLocation();
// Global variables for the map, markers, and info window.
const markers: Map<string, google.maps.marker.AdvancedMarkerElement> =
new Map();
let infoWindow: google.maps.InfoWindow;

// The init function is called when the page loads.
async function init(): Promise<void> {
// Import the necessary libraries from the Google Maps API.
const [{ InfoWindow }, { Place }] = await Promise.all([
google.maps.importLibrary('maps') as Promise<google.maps.MapsLibrary>,
google.maps.importLibrary(
'places'
) as Promise<google.maps.PlacesLibrary>,
]);

// Create a new info window and set its content to the place details element.
placeDetails.remove(); // Hide the place details element because it is not needed until the info window opens
infoWindow = new InfoWindow({
content: placeDetails,
ariaLabel: 'Place Details',
});

// Set the map options.
map.innerMap.setOptions({
mapTypeControl: false,
clickableIcons: false,
mapTypeControl: false,
streetViewControl: false,
});

/* [START maps_ui_kit_place_search_nearby_event] */
placeDetails.addEventListener('gmp-load', (event) => {
// Center the info window on the map.
map.innerMap.fitBounds(placeDetails.place.viewport, {
top: 500,
left: 400,
});
});
// Add event listeners to the type select and place search elements.
typeSelect.addEventListener('change', () => searchPlaces());

typeSelect.addEventListener('change', (event) => {
// First remove all existing markers.
for (marker in markers) {
markers[marker].map = null;
}
markers = {};

if (typeSelect.value) {
placeList.style.display = 'block';
placeList
.configureFromSearchNearbyRequest({
locationRestriction: getContainingCircle(
map.innerMap.getBounds()
),
includedPrimaryTypes: [typeSelect.value],
})
.then(addMarkers);
// Handle user selection in Place Details.
placeList.addEventListener('gmp-placeselect', ({ place }) => {
markers[place.id].click();
});
}
placeSearch.addEventListener('gmp-select', (event: Event) => {
const { place } = event as any;
markers.get(place.id)?.click();
});
placeSearch.addEventListener('gmp-load', () => {
addMarkers();
});
/* [END maps_ui_kit_place_search_nearby_event] */

searchPlaces();
}
/* [END maps_ui_kit_place_search_nearby_event] */
// The searchPlaces function is called when the user changes the type select or when the page loads.
async function searchPlaces() {
// Close the info window and clear the markers.
infoWindow.close();
for (const marker of markers.values()) {
marker.remove();
}
markers.clear();

// Set the place search query and add an event listener to the place search element.
if (typeSelect.value) {
const center = map.center!;
placeSearchQuery.locationRestriction = {
center,
radius: 50000, // 50km radius
};
placeSearchQuery.locationBias = {
center,
};
placeSearchQuery.includedTypes = [typeSelect.value];
}
}

// The addMarkers function is called when the place search element loads.
async function addMarkers() {
const { AdvancedMarkerElement } = (await google.maps.importLibrary(
'marker'
)) as google.maps.MarkerLibrary;
const { LatLngBounds } = (await google.maps.importLibrary(
'core'
)) as google.maps.CoreLibrary;

// Import the necessary libraries from the Google Maps API.
const [{ AdvancedMarkerElement }, { LatLngBounds }] = await Promise.all([
google.maps.importLibrary(
'marker'
) as Promise<google.maps.MarkerLibrary>,
google.maps.importLibrary('core') as Promise<google.maps.CoreLibrary>,
]);
const bounds = new LatLngBounds();

if (placeList.places.length > 0) {
placeList.places.forEach((place) => {
let marker = new AdvancedMarkerElement({
map: map.innerMap,
position: place.location,
});

markers[place.id] = marker;
bounds.extend(place.location);

/* [START maps_ui_kit_place_search_nearby_click_event] */
marker.addListener('gmp-click', (event) => {
if (infoWindow.isOpen) {
infoWindow.close();
}

placeDetailsRequest.place = place.id;
placeDetails.style.display = 'block';
placeDetails.style.width = '350px';
infoWindow.setOptions({
content: placeDetails,
});
infoWindow.open({
anchor: marker,
map: map.innerMap,
});
});
/* [END maps_ui_kit_place_search_nearby_click_event] */

map.innerMap.setCenter(bounds.getCenter());
map.innerMap.fitBounds(bounds);
});
if (placeSearch.places.length === 0) {
return;
}
}

async function findCurrentLocation() {
const { LatLng } = (await google.maps.importLibrary(
'core'
)) as google.maps.CoreLibrary;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const pos = new LatLng(
position.coords.latitude,
position.coords.longitude
);
map.innerMap.panTo(pos);
map.innerMap.setZoom(14);
},
() => {
console.log('The Geolocation service failed.');
map.innerMap.setZoom(14);
}
);
} else {
console.log("Your browser doesn't support geolocation");
map.innerMap.setZoom(14);
for (const place of placeSearch.places) {
const marker = new AdvancedMarkerElement({
map: map.innerMap,
position: place.location,
collisionBehavior:
google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL,
});

markers.set(place.id, marker);
bounds.extend(place.location);

marker.addListener('click', () => {
placeRequest.place = place;
infoWindow.open(map.innerMap, marker);
});
}

map.innerMap.fitBounds(bounds);
}

initMap();
init();
/* [END maps_ui_kit_place_search_nearby] */
Loading