Skip to content

Commit 1d26ef7

Browse files
committed
Update Places UI Kit Nearby Search
1 parent b4af120 commit 1d26ef7

File tree

3 files changed

+246
-179
lines changed

3 files changed

+246
-179
lines changed

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

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,67 @@
77
<!DOCTYPE html>
88
<html>
99
<head>
10-
<title>Place List Nearby Search with Google Maps</title>
11-
<meta charset="utf-8">
12-
<link rel="stylesheet" type="text/css" href="style.css">
13-
<script type="module" src="./index.js"></script>
10+
<title>Place Search Nearby with Google Maps</title>
11+
<meta charset="utf-8" />
12+
<link rel="stylesheet" type="text/css" href="style.css" />
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", internalUsageAttributionIds: "gmp_mcp_codeassist_v0.1_github"});
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+
<div class="container">
23+
<gmp-map center="-37.813,144.963" zoom="16" map-id="DEMO_MAP_ID" disable-default-ui></gmp-map>
24+
<div class="ui-panel">
1925
<div class="controls">
20-
<select name="types" class="type-select">
21-
<option value="">Select a place type</option>
22-
<option value="cafe">Cafe</option>
26+
<label for="type-select">Select a place type:</label>
27+
<select id="type-select" class="type-select">
28+
<option value="cafe" selected>Cafe</option>
2329
<option value="restaurant">Restaurant</option>
24-
<option value="electric_vehicle_charging_station">
25-
EV charging station
26-
</option>
30+
<option value="electric_vehicle_charging_station"
31+
>EV charging station</option
32+
>
2733
</select>
2834
</div>
2935
<div class="list-container">
30-
<gmp-place-list selectable style="display: none;"></gmp-place-list>
36+
<gmp-place-search orientation="vertical" selectable>
37+
<gmp-place-all-content></gmp-place-all-content>
38+
<gmp-place-nearby-search-request
39+
location-restriction="[email protected], 144.963">
40+
</gmp-place-nearby-search-request>
41+
</gmp-place-search>
3142
</div>
3243
</div>
33-
</gmp-map>
44+
</div>
3445

35-
<gmp-place-details style="display: none;">
36-
<gmp-place-details-place-request></gmp-place-details-place-request>
37-
<gmp-place-all-content></gmp-place-all-content>
38-
</gmp-place-details>
46+
<div id="details-container">
47+
<gmp-place-details-compact orientation="horizontal"
48+
truncation-preferred
49+
style="width: 400px;
50+
padding: 0;
51+
margin: 0;
52+
border: none;
53+
background-color: transparent;
54+
color-scheme: light;">
55+
<gmp-place-details-place-request
56+
place="places/ChIJ3S-JXmauEmsRUcIaWtf4MzE"></gmp-place-details-place-request>
57+
<gmp-place-content-config>
58+
<gmp-place-media></gmp-place-media>
59+
<gmp-place-rating></gmp-place-rating>
60+
<gmp-place-price></gmp-place-price>
61+
<gmp-place-accessible-entrance-icon></gmp-place-accessible-entrance-icon>
62+
<gmp-place-open-now-status></gmp-place-open-now-status>
63+
<gmp-place-attribution
64+
light-scheme-color="gray"
65+
dark-scheme-color="white"></gmp-place-attribution>
66+
</gmp-place-content-config>
67+
</gmp-place-details-compact>
68+
</div>
3969

4070
<!--[END maps_ui_kit_place_search_nearby_map] -->
41-
<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))})
42-
({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "alpha"});</script>
4371
</body>
4472
</html>
45-
<!--[END maps_ui_kit_place_search_nearby] -->
73+
<!--[END maps_ui_kit_place_search_nearby] -->

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

Lines changed: 140 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -6,132 +6,166 @@
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('gmp-place-details-place-request') as any;
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(
17+
'gmp-place-details-place-request'
18+
) as any
19+
const typeSelect = document.querySelector('.type-select') as HTMLSelectElement
1420
/* [END maps_ui_kit_place_search_nearby_query_selectors] */
15-
let markers = {};
16-
let infoWindow;
17-
18-
async function initMap(): Promise<void> {
19-
await google.maps.importLibrary('places');
20-
const { LatLngBounds } = await google.maps.importLibrary('core') as google.maps.CoreLibrary;
21-
const { InfoWindow } = await google.maps.importLibrary('maps') as google.maps.MapsLibrary;
22-
const { spherical } = await google.maps.importLibrary('geometry') as google.maps.GeometryLibrary;
23-
24-
infoWindow = new InfoWindow;
25-
let marker;
26-
27-
function getContainingCircle(bounds) {
28-
const diameter = spherical.computeDistanceBetween(
29-
bounds.getNorthEast(),
30-
bounds.getSouthWest()
31-
);
32-
const calculatedRadius = diameter / 2;
33-
const cappedRadius = Math.min(calculatedRadius, 50000); // Radius cannot be more than 50000.
34-
return { center: bounds.getCenter(), radius: cappedRadius };
35-
}
36-
37-
findCurrentLocation();
3821

22+
// Global variables for the map, markers, and info window.
23+
const markers: Map<string, google.maps.marker.AdvancedMarkerElement> = new Map()
24+
let infoWindow
25+
26+
let AdvancedMarkerElement: typeof google.maps.marker.AdvancedMarkerElement
27+
let LatLngBounds: typeof google.maps.LatLngBounds
28+
29+
// The init function is called when the page loads.
30+
async function init(): Promise<void> {
31+
// Import the necessary libraries from the Google Maps API.
32+
const { InfoWindow } = (await google.maps.importLibrary(
33+
'maps'
34+
)) as google.maps.MapsLibrary
35+
await google.maps.importLibrary('places')
36+
const markerLib = (await google.maps.importLibrary(
37+
'marker'
38+
)) as google.maps.MarkerLibrary
39+
const coreLib = (await google.maps.importLibrary(
40+
'core'
41+
)) as google.maps.CoreLibrary
42+
43+
AdvancedMarkerElement = markerLib.AdvancedMarkerElement
44+
LatLngBounds = coreLib.LatLngBounds
45+
46+
// Create a new info window and set its content to the place details element.
47+
infoWindow = new InfoWindow({
48+
content: placeDetails,
49+
ariaLabel: 'Place Details',
50+
headerDisabled: true,
51+
pixelOffset: { width: 0, height: -40 } as google.maps.Size,
52+
})
53+
54+
// Set the map options.
3955
map.innerMap.setOptions({
40-
mapTypeControl: false,
4156
clickableIcons: false,
42-
});
57+
mapTypeControl: false,
58+
streetViewControl: false,
59+
})
4360

61+
// Add a click listener to the map to hide the info window when the map is clicked.
62+
map.innerMap.addListener('click', () => {
63+
hideInfoWindow()
64+
})
4465
/* [START maps_ui_kit_place_search_nearby_event] */
45-
placeDetails.addEventListener('gmp-load', (event) => {
46-
// Center the info window on the map.
47-
map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 });
48-
});
49-
50-
typeSelect.addEventListener('change', (event) => {
51-
// First remove all existing markers.
52-
for(marker in markers){
53-
markers[marker].map = null;
66+
// Add event listeners to the type select and place search elements.
67+
typeSelect.addEventListener('change', searchPlaces)
68+
69+
placeSearch.addEventListener('gmp-select', (event: Event) => {
70+
const { place } = event as any
71+
if (markers.has(place.id)) {
72+
markers.get(place.id)!.click()
5473
}
55-
markers = {};
56-
57-
if (typeSelect.value) {
58-
placeList.style.display = 'block';
59-
placeList.configureFromSearchNearbyRequest({
60-
locationRestriction: getContainingCircle(
61-
map.innerMap.getBounds()
62-
),
63-
includedPrimaryTypes: [typeSelect.value],
64-
}).then(addMarkers);
65-
// Handle user selection in Place Details.
66-
placeList.addEventListener('gmp-placeselect', ({ place }) => {
67-
markers[place.id].click();
68-
});
74+
})
75+
placeSearch.addEventListener(
76+
'gmp-load',
77+
() => {
78+
searchPlaces()
79+
},
80+
{ once: true }
81+
)
82+
}
83+
/* [END maps_ui_kit_place_search_nearby_event] */
84+
// The searchPlaces function is called when the user changes the type select or when the page loads.
85+
function searchPlaces() {
86+
// Get the map bounds and center.
87+
const bounds = map.innerMap.getBounds()!
88+
const cent = map.innerMap.getCenter()!
89+
const ne = bounds.getNorthEast()
90+
const sw = bounds.getSouthWest()
91+
// Calculate the diameter of the map bounds and cap the radius at 50000.
92+
const diameter = google.maps.geometry.spherical.computeDistanceBetween(
93+
ne,
94+
sw
95+
)
96+
const cappedRadius = Math.min(diameter / 2, 50000) // Radius cannot be more than 50000.
97+
98+
// Close the info window and clear the markers.
99+
infoWindow.close()
100+
101+
for (const marker of markers.values()) {
102+
marker.map = null
103+
}
104+
markers.clear()
105+
106+
// Set the place search query and add an event listener to the place search element.
107+
if (typeSelect.value) {
108+
// map.style.height = '75vh';
109+
placeSearch.style.visibility = 'visible'
110+
placeSearchQuery.maxResultCount = 10
111+
placeSearchQuery.locationRestriction = {
112+
center: { lat: cent.lat(), lng: cent.lng() },
113+
radius: cappedRadius,
69114
}
70-
});
71-
/* [END maps_ui_kit_place_search_nearby_event] */
115+
placeSearchQuery.includedTypes = [typeSelect.value]
116+
placeSearch.addEventListener('gmp-load', () => addMarkers(), {
117+
once: true,
118+
})
119+
}
72120
}
73121

74-
async function addMarkers(){
75-
const { AdvancedMarkerElement } = await google.maps.importLibrary('marker') as google.maps.MarkerLibrary;
76-
const { LatLngBounds } = await google.maps.importLibrary('core') as google.maps.CoreLibrary;
77-
78-
const bounds = new LatLngBounds();
122+
// The addMarkers function is called when the place search element loads.
123+
async function addMarkers() {
124+
// Create a new LatLngBounds object and make the place search element visible.
125+
const bounds = new LatLngBounds()
126+
placeSearch.style.visibility = 'visible'
79127

80-
if(placeList.places.length > 0){
81-
placeList.places.forEach((place) => {
82-
let marker = new AdvancedMarkerElement({
128+
// Iterate over the places and create a marker for each place.
129+
if (placeSearch.places.length > 0) {
130+
placeSearch.places.forEach((place) => {
131+
const marker = new AdvancedMarkerElement({
83132
map: map.innerMap,
84-
position: place.location
85-
});
133+
position: place.location,
134+
collisionBehavior:
135+
google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL,
136+
})
86137

87-
markers[place.id] = marker;
88-
bounds.extend(place.location);
138+
// Add the marker to the markers map and extend the bounds.
139+
markers.set(place.id, marker)
140+
bounds.extend(place.location)
89141

90142
/* [START maps_ui_kit_place_search_nearby_click_event] */
91-
marker.addListener('gmp-click', (event) => {
92-
if(infoWindow.isOpen){
93-
infoWindow.close();
143+
// Add a click listener to the marker to show the info window.
144+
marker.addListener('click', () => {
145+
if (place.viewport) {
146+
map.innerMap.fitBounds(place.viewport)
147+
} else {
148+
map.innerMap.panTo(place.location)
149+
map.innerMap.setZoom(18)
94150
}
95-
96-
placeDetailsRequest.place = place.id;
97-
placeDetails.style.display = 'block';
98-
placeDetails.style.width = '350px';
99-
infoWindow.setOptions({
100-
content: placeDetails,
101-
});
102-
infoWindow.open({
103-
anchor: marker,
104-
map: map.innerMap
105-
});
106-
});
151+
placeRequest.place = place
152+
infoWindow.setPosition(place.location)
153+
placeDetails.style.visibility = 'visible' // Ensure place details are visible
154+
infoWindow.open(map.innerMap)
155+
})
107156
/* [END maps_ui_kit_place_search_nearby_click_event] */
108-
109-
map.innerMap.setCenter(bounds.getCenter());
110-
map.innerMap.fitBounds(bounds);
111-
});
157+
})
158+
// Set the map center and fit the bounds.
159+
map.innerMap.setCenter(bounds.getCenter())
160+
map.innerMap.fitBounds(bounds)
112161
}
113162
}
114163

115-
async function findCurrentLocation(){
116-
const { LatLng } = await google.maps.importLibrary('core') as google.maps.CoreLibrary;
117-
if (navigator.geolocation) {
118-
navigator.geolocation.getCurrentPosition(
119-
(position) => {
120-
const pos = new LatLng(position.coords.latitude,position.coords.longitude);
121-
map.innerMap.panTo(pos);
122-
map.innerMap.setZoom(14);
123-
},
124-
() => {
125-
console.log('The Geolocation service failed.');
126-
map.innerMap.setZoom(14);
127-
},
128-
);
129-
} else {
130-
console.log('Your browser doesn\'t support geolocation');
131-
map.innerMap.setZoom(14);
132-
}
133-
164+
// The hideInfoWindow function is called when the user clicks on the map.
165+
function hideInfoWindow() {
166+
infoWindow.close()
167+
placeDetails.style.visibility = 'hidden'
134168
}
135169

136-
initMap();
170+
init()
137171
/* [END maps_ui_kit_place_search_nearby] */

0 commit comments

Comments
 (0)