|
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('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 |
14 | 20 | /* [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(); |
38 | 21 |
|
| 22 | +// Global variables for the map, markers, and info window. |
| 23 | +const markers: Map<string, google.maps.marker.AdvancedMarkerElement> = new Map() |
| 24 | +let infoWindow: google.maps.InfoWindow |
| 25 | +let AdvancedMarkerElement: typeof google.maps.marker.AdvancedMarkerElement |
| 26 | +let LatLngBounds: typeof google.maps.LatLngBounds |
| 27 | + |
| 28 | +// The init function is called when the page loads. |
| 29 | +async function init(): Promise<void> { |
| 30 | + // Import the necessary libraries from the Google Maps API. |
| 31 | + const [{ InfoWindow }, { Place }, markerLib, coreLib] = await Promise.all([ |
| 32 | + google.maps.importLibrary('maps') as Promise<google.maps.MapsLibrary>, |
| 33 | + google.maps.importLibrary( |
| 34 | + 'places' |
| 35 | + ) as Promise<google.maps.PlacesLibrary>, |
| 36 | + google.maps.importLibrary( |
| 37 | + 'marker' |
| 38 | + ) as Promise<google.maps.MarkerLibrary>, |
| 39 | + google.maps.importLibrary('core') as Promise<google.maps.CoreLibrary>, |
| 40 | + ]) |
| 41 | + |
| 42 | + AdvancedMarkerElement = markerLib.AdvancedMarkerElement |
| 43 | + LatLngBounds = coreLib.LatLngBounds |
| 44 | + |
| 45 | + // Create a new info window and set its content to the place details element. |
| 46 | + infoWindow = new InfoWindow({ |
| 47 | + content: placeDetails, |
| 48 | + ariaLabel: 'Place Details', |
| 49 | + headerDisabled: true, |
| 50 | + pixelOffset: new google.maps.Size(0, -40), |
| 51 | + }) |
| 52 | + |
| 53 | + // Set the map options. |
39 | 54 | map.innerMap.setOptions({ |
40 | | - mapTypeControl: false, |
41 | 55 | clickableIcons: false, |
42 | | - }); |
| 56 | + mapTypeControl: false, |
| 57 | + streetViewControl: false, |
| 58 | + }) |
43 | 59 |
|
| 60 | + // Add a click listener to the map to hide the info window when the map is clicked. |
| 61 | + map.innerMap.addListener('click', () => infoWindow.close()) |
44 | 62 | /* [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; |
| 63 | + // Add event listeners to the type select and place search elements. |
| 64 | + typeSelect.addEventListener('change', searchPlaces) |
| 65 | + |
| 66 | + placeSearch.addEventListener('gmp-select', (event: Event) => { |
| 67 | + const { place } = event as any |
| 68 | + if (markers.has(place.id)) { |
| 69 | + markers.get(place.id)!.click() |
54 | 70 | } |
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 | | - }); |
| 71 | + if (place.location) { |
| 72 | + map.innerMap.setCenter(place.location) |
69 | 73 | } |
70 | | - }); |
71 | | - /* [END maps_ui_kit_place_search_nearby_event] */ |
| 74 | + }) |
| 75 | + placeSearch.addEventListener( |
| 76 | + 'gmp-load', |
| 77 | + () => { |
| 78 | + searchPlaces() |
| 79 | + }, |
| 80 | + { once: true } |
| 81 | + ) |
72 | 82 | } |
73 | | - |
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(); |
79 | | - |
80 | | - if(placeList.places.length > 0){ |
81 | | - placeList.places.forEach((place) => { |
82 | | - let marker = new AdvancedMarkerElement({ |
83 | | - map: map.innerMap, |
84 | | - position: place.location |
85 | | - }); |
86 | | - |
87 | | - markers[place.id] = marker; |
88 | | - bounds.extend(place.location); |
89 | | - |
90 | | - /* [START maps_ui_kit_place_search_nearby_click_event] */ |
91 | | - marker.addListener('gmp-click', (event) => { |
92 | | - if(infoWindow.isOpen){ |
93 | | - infoWindow.close(); |
94 | | - } |
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 | | - }); |
107 | | - /* [END maps_ui_kit_place_search_nearby_click_event] */ |
108 | | - |
109 | | - map.innerMap.setCenter(bounds.getCenter()); |
110 | | - map.innerMap.fitBounds(bounds); |
111 | | - }); |
| 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 | + // Close the info window and clear the markers. |
| 87 | + infoWindow.close() |
| 88 | + for (const marker of markers.values()) { |
| 89 | + marker.map = null |
| 90 | + } |
| 91 | + markers.clear() |
| 92 | + |
| 93 | + // Set the place search query and add an event listener to the place search element. |
| 94 | + if (typeSelect.value) { |
| 95 | + const center = map.innerMap.getCenter()! |
| 96 | + placeSearchQuery.maxResultCount = 5 |
| 97 | + placeSearchQuery.locationRestriction = { |
| 98 | + center: { lat: center.lat(), lng: center.lng() }, |
| 99 | + radius: 50000, // 50km radius |
| 100 | + } |
| 101 | + placeSearchQuery.locationBias = { |
| 102 | + center: { lat: center.lat(), lng: center.lng() }, |
| 103 | + } |
| 104 | + placeSearchQuery.includedTypes = [typeSelect.value] |
| 105 | + placeSearch.addEventListener('gmp-load', addMarkers, { once: true }) |
112 | 106 | } |
113 | 107 | } |
114 | 108 |
|
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 | | - } |
| 109 | +// The addMarkers function is called when the place search element loads. |
| 110 | +async function addMarkers() { |
| 111 | + const bounds = new LatLngBounds() |
| 112 | + |
| 113 | + if (placeSearch.places.length === 0) { |
| 114 | + return |
| 115 | + } |
133 | 116 |
|
| 117 | + placeSearch.places.forEach((place) => { |
| 118 | + const marker = new AdvancedMarkerElement({ |
| 119 | + map: map.innerMap, |
| 120 | + position: place.location, |
| 121 | + collisionBehavior: |
| 122 | + google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL, |
| 123 | + }) |
| 124 | + |
| 125 | + markers.set(place.id, marker) |
| 126 | + bounds.extend(place.location) |
| 127 | + |
| 128 | + marker.addListener('click', () => { |
| 129 | + if (place.location) { |
| 130 | + map.innerMap.setCenter(place.location) |
| 131 | + } |
| 132 | + placeRequest.place = place |
| 133 | + infoWindow.setPosition(place.location) |
| 134 | + infoWindow.open(map.innerMap) |
| 135 | + }) |
| 136 | + }) |
| 137 | + |
| 138 | + map.innerMap.fitBounds(bounds) |
134 | 139 | } |
135 | 140 |
|
136 | | -initMap(); |
| 141 | +init() |
137 | 142 | /* [END maps_ui_kit_place_search_nearby] */ |
0 commit comments