|
6 | 6 | /* [START maps_ui_kit_place_search_nearby] */ |
7 | 7 |
|
8 | 8 | /* [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( |
14 | 17 | 'gmp-place-details-place-request' |
15 | 18 | ) as any; |
| 19 | +const typeSelect = document.querySelector('.type-select') as HTMLSelectElement; |
16 | 20 | /* [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 | | - } |
44 | 21 |
|
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 | + }); |
46 | 43 |
|
| 44 | + // Set the map options. |
47 | 45 | map.innerMap.setOptions({ |
48 | | - mapTypeControl: false, |
49 | 46 | clickableIcons: false, |
| 47 | + mapTypeControl: false, |
| 48 | + streetViewControl: false, |
50 | 49 | }); |
51 | 50 |
|
52 | 51 | /* [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()); |
60 | 54 |
|
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(); |
83 | 61 | }); |
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 | + } |
85 | 87 | } |
86 | 88 |
|
| 89 | +// The addMarkers function is called when the place search element loads. |
87 | 90 | 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 | + ]); |
95 | 98 | const bounds = new LatLngBounds(); |
96 | 99 |
|
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; |
129 | 102 | } |
130 | | -} |
131 | 103 |
|
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 | + }); |
154 | 119 | } |
| 120 | + |
| 121 | + map.innerMap.fitBounds(bounds); |
155 | 122 | } |
156 | 123 |
|
157 | | -initMap(); |
| 124 | +init(); |
158 | 125 | /* [END maps_ui_kit_place_search_nearby] */ |
0 commit comments