Skip to content

Commit e6692e0

Browse files
authored
Updated Places UI Kit Nearby Search (#923)
* Updated Places UI Kit Nearby Search * addressed comments for style and a11y * Addressed comments for imports and element placement * removed extraneous centering in place search event listener
1 parent 0cc3b82 commit e6692e0

File tree

3 files changed

+167
-227
lines changed

3 files changed

+167
-227
lines changed

samples/ui-kit-place-search-nearby/index.html

Lines changed: 56 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,83 +7,76 @@
77
<!doctype html>
88
<html>
99
<head>
10-
<title>Place List Nearby Search with Google Maps</title>
10+
<title>Place Search Nearby with Google Maps</title>
1111
<meta charset="utf-8" />
1212
<link rel="stylesheet" type="text/css" href="style.css" />
13-
<script type="module" src="./index.js"></script>
13+
<script type="module" src="./index.js" defer></script>
14+
<!-- prettier-ignore -->
15+
<script>
16+
(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))})
17+
({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});
18+
</script>
1419
</head>
1520
<body>
1621
<!--[START maps_ui_kit_place_search_nearby_map] -->
17-
<gmp-map center="-37.813,144.963" zoom="10" map-id="DEMO_MAP_ID">
18-
<div class="overlay" slot="control-inline-start-block-start">
22+
23+
<div class="container">
24+
<!-- map-id is required to use advanced markers. See https://developers.google.com/maps/documentation/javascript/map-ids/mapid-over. -->
25+
<gmp-map center="-37.813,144.963" zoom="16" map-id="DEMO_MAP_ID">
26+
</gmp-map>
27+
<div class="ui-panel">
1928
<div class="controls">
20-
<select name="types" class="type-select">
21-
<option value="">Select a place type</option>
22-
<option value="cafe">Cafe</option>
23-
<option value="restaurant">Restaurant</option>
24-
<option value="electric_vehicle_charging_station">
25-
EV charging station
26-
</option>
27-
</select>
29+
<label for="type-select">
30+
Select a place type:
31+
<select id="type-select" class="type-select">
32+
<option value="restaurant">Restaurant</option>
33+
<option value="cafe" selected>Cafe</option>
34+
<option value="electric_vehicle_charging_station">
35+
EV charging station
36+
</option>
37+
</select>
38+
</label>
2839
</div>
2940
<div class="list-container">
30-
<gmp-place-list
31-
selectable
32-
style="display: none"></gmp-place-list>
41+
<gmp-place-search selectable>
42+
<gmp-place-all-content></gmp-place-all-content>
43+
<gmp-place-nearby-search-request
44+
max-result-count="5"></gmp-place-nearby-search-request>
45+
</gmp-place-search>
3346
</div>
3447
</div>
35-
</gmp-map>
48+
</div>
3649

37-
<gmp-place-details style="display: none">
50+
<!--
51+
The gmp-place-details-compact element is styled inline because it is
52+
conditionally rendered and moved into the info window, which is
53+
part of the map's shadow DOM.
54+
-->
55+
<gmp-place-details-compact
56+
orientation="horizontal"
57+
truncation-preferred
58+
style="
59+
width: 400px;
60+
padding: 0;
61+
margin: 0;
62+
border: none;
63+
background-color: transparent;
64+
color-scheme: light;
65+
">
3866
<gmp-place-details-place-request></gmp-place-details-place-request>
39-
<gmp-place-all-content></gmp-place-all-content>
40-
</gmp-place-details>
67+
<gmp-place-content-config>
68+
<gmp-place-media></gmp-place-media>
69+
<gmp-place-rating></gmp-place-rating>
70+
<gmp-place-price></gmp-place-price>
71+
<gmp-place-accessible-entrance-icon></gmp-place-accessible-entrance-icon>
72+
<gmp-place-open-now-status></gmp-place-open-now-status>
73+
<gmp-place-attribution
74+
light-scheme-color="gray"
75+
dark-scheme-color="white"></gmp-place-attribution>
76+
</gmp-place-content-config>
77+
</gmp-place-details-compact>
4178

4279
<!--[END maps_ui_kit_place_search_nearby_map] -->
43-
<script>
44-
((g) => {
45-
var h,
46-
a,
47-
k,
48-
p = 'The Google Maps JavaScript API',
49-
c = 'google',
50-
l = 'importLibrary',
51-
q = '__ib__',
52-
m = document,
53-
b = window;
54-
b = b[c] || (b[c] = {});
55-
var d = b.maps || (b.maps = {}),
56-
r = new Set(),
57-
e = new URLSearchParams(),
58-
u = () =>
59-
h ||
60-
(h = new Promise(async (f, n) => {
61-
await (a = m.createElement('script'));
62-
e.set('libraries', [...r] + '');
63-
for (k in g)
64-
e.set(
65-
k.replace(
66-
/[A-Z]/g,
67-
(t) => '_' + t[0].toLowerCase()
68-
),
69-
g[k]
70-
);
71-
e.set('callback', c + '.maps.' + q);
72-
a.src =
73-
`https://maps.${c}apis.com/maps/api/js?` + e;
74-
d[q] = f;
75-
a.onerror = () =>
76-
(h = n(Error(p + ' could not load.')));
77-
a.nonce =
78-
m.querySelector('script[nonce]')?.nonce || '';
79-
m.head.append(a);
80-
}));
81-
d[l]
82-
? console.warn(p + ' only loads once. Ignoring:', g)
83-
: (d[l] = (f, ...n) =>
84-
r.add(f) && u().then(() => d[l](f, ...n)));
85-
})({ key: 'AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8', v: 'alpha' });
86-
</script>
8780
</body>
8881
</html>
8982
<!--[END maps_ui_kit_place_search_nearby] -->

samples/ui-kit-place-search-nearby/index.ts

Lines changed: 94 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -6,153 +6,120 @@
66
/* [START maps_ui_kit_place_search_nearby] */
77

88
/* [START maps_ui_kit_place_search_nearby_query_selectors] */
9-
const map = document.querySelector('gmp-map') as any;
10-
const placeList = document.querySelector('gmp-place-list') as any;
11-
const typeSelect = document.querySelector('.type-select') as any;
12-
const placeDetails = document.querySelector('gmp-place-details') as any;
13-
const placeDetailsRequest = document.querySelector(
9+
// Query selectors for various elements in the HTML file.
10+
const map = document.querySelector('gmp-map') as google.maps.MapElement;
11+
const placeSearch = document.querySelector('gmp-place-search') as any;
12+
const placeSearchQuery = document.querySelector(
13+
'gmp-place-nearby-search-request'
14+
) as any;
15+
const placeDetails = document.querySelector('gmp-place-details-compact') as any;
16+
const placeRequest = document.querySelector(
1417
'gmp-place-details-place-request'
1518
) as any;
19+
const typeSelect = document.querySelector('.type-select') as HTMLSelectElement;
1620
/* [END maps_ui_kit_place_search_nearby_query_selectors] */
17-
let markers = {};
18-
let infoWindow;
19-
20-
async function initMap(): Promise<void> {
21-
await google.maps.importLibrary('places');
22-
const { LatLngBounds } = (await google.maps.importLibrary(
23-
'core'
24-
)) as google.maps.CoreLibrary;
25-
const { InfoWindow } = (await google.maps.importLibrary(
26-
'maps'
27-
)) as google.maps.MapsLibrary;
28-
const { spherical } = (await google.maps.importLibrary(
29-
'geometry'
30-
)) as google.maps.GeometryLibrary;
31-
32-
infoWindow = new InfoWindow();
33-
let marker;
34-
35-
function getContainingCircle(bounds) {
36-
const diameter = spherical.computeDistanceBetween(
37-
bounds.getNorthEast(),
38-
bounds.getSouthWest()
39-
);
40-
const calculatedRadius = diameter / 2;
41-
const cappedRadius = Math.min(calculatedRadius, 50000); // Radius cannot be more than 50000.
42-
return { center: bounds.getCenter(), radius: cappedRadius };
43-
}
4421

45-
findCurrentLocation();
22+
// Global variables for the map, markers, and info window.
23+
const markers: Map<string, google.maps.marker.AdvancedMarkerElement> =
24+
new Map();
25+
let infoWindow: google.maps.InfoWindow;
26+
27+
// The init function is called when the page loads.
28+
async function init(): Promise<void> {
29+
// Import the necessary libraries from the Google Maps API.
30+
const [{ InfoWindow }, { Place }] = await Promise.all([
31+
google.maps.importLibrary('maps') as Promise<google.maps.MapsLibrary>,
32+
google.maps.importLibrary(
33+
'places'
34+
) as Promise<google.maps.PlacesLibrary>,
35+
]);
36+
37+
// Create a new info window and set its content to the place details element.
38+
placeDetails.remove(); // Hide the place details element because it is not needed until the info window opens
39+
infoWindow = new InfoWindow({
40+
content: placeDetails,
41+
ariaLabel: 'Place Details',
42+
});
4643

44+
// Set the map options.
4745
map.innerMap.setOptions({
48-
mapTypeControl: false,
4946
clickableIcons: false,
47+
mapTypeControl: false,
48+
streetViewControl: false,
5049
});
5150

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

61-
typeSelect.addEventListener('change', (event) => {
62-
// First remove all existing markers.
63-
for (marker in markers) {
64-
markers[marker].map = null;
65-
}
66-
markers = {};
67-
68-
if (typeSelect.value) {
69-
placeList.style.display = 'block';
70-
placeList
71-
.configureFromSearchNearbyRequest({
72-
locationRestriction: getContainingCircle(
73-
map.innerMap.getBounds()
74-
),
75-
includedPrimaryTypes: [typeSelect.value],
76-
})
77-
.then(addMarkers);
78-
// Handle user selection in Place Details.
79-
placeList.addEventListener('gmp-placeselect', ({ place }) => {
80-
markers[place.id].click();
81-
});
82-
}
55+
placeSearch.addEventListener('gmp-select', (event: Event) => {
56+
const { place } = event as any;
57+
markers.get(place.id)?.click();
58+
});
59+
placeSearch.addEventListener('gmp-load', () => {
60+
addMarkers();
8361
});
84-
/* [END maps_ui_kit_place_search_nearby_event] */
62+
63+
searchPlaces();
64+
}
65+
/* [END maps_ui_kit_place_search_nearby_event] */
66+
// The searchPlaces function is called when the user changes the type select or when the page loads.
67+
async function searchPlaces() {
68+
// Close the info window and clear the markers.
69+
infoWindow.close();
70+
for (const marker of markers.values()) {
71+
marker.remove();
72+
}
73+
markers.clear();
74+
75+
// Set the place search query and add an event listener to the place search element.
76+
if (typeSelect.value) {
77+
const center = map.center!;
78+
placeSearchQuery.locationRestriction = {
79+
center,
80+
radius: 50000, // 50km radius
81+
};
82+
placeSearchQuery.locationBias = {
83+
center,
84+
};
85+
placeSearchQuery.includedTypes = [typeSelect.value];
86+
}
8587
}
8688

89+
// The addMarkers function is called when the place search element loads.
8790
async function addMarkers() {
88-
const { AdvancedMarkerElement } = (await google.maps.importLibrary(
89-
'marker'
90-
)) as google.maps.MarkerLibrary;
91-
const { LatLngBounds } = (await google.maps.importLibrary(
92-
'core'
93-
)) as google.maps.CoreLibrary;
94-
91+
// Import the necessary libraries from the Google Maps API.
92+
const [{ AdvancedMarkerElement }, { LatLngBounds }] = await Promise.all([
93+
google.maps.importLibrary(
94+
'marker'
95+
) as Promise<google.maps.MarkerLibrary>,
96+
google.maps.importLibrary('core') as Promise<google.maps.CoreLibrary>,
97+
]);
9598
const bounds = new LatLngBounds();
9699

97-
if (placeList.places.length > 0) {
98-
placeList.places.forEach((place) => {
99-
let marker = new AdvancedMarkerElement({
100-
map: map.innerMap,
101-
position: place.location,
102-
});
103-
104-
markers[place.id] = marker;
105-
bounds.extend(place.location);
106-
107-
/* [START maps_ui_kit_place_search_nearby_click_event] */
108-
marker.addListener('gmp-click', (event) => {
109-
if (infoWindow.isOpen) {
110-
infoWindow.close();
111-
}
112-
113-
placeDetailsRequest.place = place.id;
114-
placeDetails.style.display = 'block';
115-
placeDetails.style.width = '350px';
116-
infoWindow.setOptions({
117-
content: placeDetails,
118-
});
119-
infoWindow.open({
120-
anchor: marker,
121-
map: map.innerMap,
122-
});
123-
});
124-
/* [END maps_ui_kit_place_search_nearby_click_event] */
125-
126-
map.innerMap.setCenter(bounds.getCenter());
127-
map.innerMap.fitBounds(bounds);
128-
});
100+
if (placeSearch.places.length === 0) {
101+
return;
129102
}
130-
}
131103

132-
async function findCurrentLocation() {
133-
const { LatLng } = (await google.maps.importLibrary(
134-
'core'
135-
)) as google.maps.CoreLibrary;
136-
if (navigator.geolocation) {
137-
navigator.geolocation.getCurrentPosition(
138-
(position) => {
139-
const pos = new LatLng(
140-
position.coords.latitude,
141-
position.coords.longitude
142-
);
143-
map.innerMap.panTo(pos);
144-
map.innerMap.setZoom(14);
145-
},
146-
() => {
147-
console.log('The Geolocation service failed.');
148-
map.innerMap.setZoom(14);
149-
}
150-
);
151-
} else {
152-
console.log("Your browser doesn't support geolocation");
153-
map.innerMap.setZoom(14);
104+
for (const place of placeSearch.places) {
105+
const marker = new AdvancedMarkerElement({
106+
map: map.innerMap,
107+
position: place.location,
108+
collisionBehavior:
109+
google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL,
110+
});
111+
112+
markers.set(place.id, marker);
113+
bounds.extend(place.location);
114+
115+
marker.addListener('click', () => {
116+
placeRequest.place = place;
117+
infoWindow.open(map.innerMap, marker);
118+
});
154119
}
120+
121+
map.innerMap.fitBounds(bounds);
155122
}
156123

157-
initMap();
124+
init();
158125
/* [END maps_ui_kit_place_search_nearby] */

0 commit comments

Comments
 (0)