Skip to content

Commit efa4559

Browse files
authored
Disable StreetView and FullScreen UI controls
1 parent 8420142 commit efa4559

File tree

1 file changed

+216
-57
lines changed
  • samples/ai-powered-summaries-basic

1 file changed

+216
-57
lines changed
Lines changed: 216 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,242 @@
1-
/**
1+
/*
22
* @license
33
* Copyright 2025 Google LLC. All Rights Reserved.
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
// [START maps_ai_powered_summaries_basic]
7+
// [START maps_ai_powered_summaries]
8+
// Define DOM elements.
89
const mapElement = document.querySelector('gmp-map') as google.maps.MapElement;
9-
let innerMap;
10-
let infoWindow;
11-
12-
async function initMap() {
13-
const { Map, InfoWindow } = (await google.maps.importLibrary(
14-
'maps'
15-
)) as google.maps.MapsLibrary;
10+
const placeAutocomplete = document.querySelector(
11+
'gmp-place-autocomplete'
12+
) as google.maps.places.PlaceAutocompleteElement;
13+
const summaryPanel = document.getElementById('summary-panel') as HTMLDivElement;
14+
const placeName = document.getElementById('place-name') as HTMLElement;
15+
const placeAddress = document.getElementById('place-address') as HTMLElement;
16+
const tabContainer = document.getElementById('tab-container') as HTMLDivElement;
17+
const summaryContent = document.getElementById(
18+
'summary-content'
19+
) as HTMLDivElement;
20+
const aiDisclosure = document.getElementById('ai-disclosure') as HTMLDivElement;
1621

17-
innerMap = mapElement.innerMap;
18-
infoWindow = new InfoWindow();
19-
getPlaceDetails();
20-
}
22+
let innerMap;
23+
let marker: google.maps.marker.AdvancedMarkerElement;
2124

22-
async function getPlaceDetails() {
25+
async function initMap(): Promise<void> {
2326
// Request needed libraries.
24-
const [ {AdvancedMarkerElement}, { Place } ] = await Promise.all([
25-
google.maps.importLibrary('marker') as Promise<google.maps.MarkerLibrary>,
26-
google.maps.importLibrary('places') as Promise<google.maps.PlacesLibrary>,
27+
const [] = await Promise.all([
28+
google.maps.importLibrary('marker'),
29+
google.maps.importLibrary('places'),
2730
]);
2831

29-
// [START maps_ai_powered_summaries_basic_placeid]
30-
// Use place ID to create a new Place instance.
31-
const place = new Place({
32-
id: 'ChIJzzc-aWUM3IARPOQr9sA6vfY', // San Diego Botanic Garden
32+
innerMap = mapElement.innerMap;
33+
innerMap.setOptions({
34+
mapTypeControl: false,
35+
streetViewControl: false,
36+
fullscreenControl: false,
3337
});
34-
// [END maps_ai_powered_summaries_basic_placeid]
35-
36-
// Call fetchFields, passing the needed data fields.
37-
// [START maps_ai_powered_summaries_basic_fetchfields]
38-
await place.fetchFields({
39-
fields: [
40-
'displayName',
41-
'formattedAddress',
42-
'location',
43-
'generativeSummary',
44-
],
38+
39+
// Bind autocomplete bounds to map bounds.
40+
google.maps.event.addListener(innerMap, 'bounds_changed', async () => {
41+
placeAutocomplete.locationRestriction = innerMap.getBounds();
4542
});
46-
// [END maps_ai_powered_summaries_basic_fetchfields]
4743

48-
// Add an Advanced Marker
49-
const marker = new AdvancedMarkerElement({
44+
// Create the marker.
45+
marker = new google.maps.marker.AdvancedMarkerElement({
5046
map: innerMap,
51-
position: place.location,
52-
title: place.displayName,
5347
});
5448

55-
// Create a content container.
56-
const content = document.createElement('div');
57-
// Populate the container with data.
58-
const address = document.createElement('div');
59-
const summary = document.createElement('div');
60-
const lineBreak = document.createElement('br');
49+
// Handle selection of an autocomplete result.
50+
// prettier-ignore
51+
// @ts-ignore
52+
placeAutocomplete.addEventListener('gmp-select', async ({ placePrediction }) => {
53+
const place = placePrediction.toPlace();
54+
55+
// Fetch all summary fields.
56+
// [START maps_ai_powered_summaries_fetchfields]
57+
await place.fetchFields({
58+
fields: [
59+
'displayName',
60+
'formattedAddress',
61+
'location',
62+
'generativeSummary',
63+
'neighborhoodSummary',
64+
'reviewSummary',
65+
'evChargeAmenitySummary',
66+
],
67+
});
68+
// [END maps_ai_powered_summaries_fetchfields]
69+
70+
// Update the map viewport and position the marker.
71+
if (place.viewport) {
72+
innerMap.fitBounds(place.viewport);
73+
} else {
74+
innerMap.setCenter(place.location);
75+
innerMap.setZoom(17);
76+
}
77+
marker.position = place.location;
78+
79+
// Update the panel UI.
80+
updateSummaryPanel(place);
81+
}
82+
);
83+
}
84+
85+
function updateSummaryPanel(place: google.maps.places.Place) {
86+
// Reset UI
87+
summaryPanel.classList.remove('hidden');
88+
tabContainer.innerHTML = ''; // innerHTML is OK here since we're clearing known child elements.
89+
summaryContent.textContent = '';
90+
aiDisclosure.textContent = '';
91+
92+
placeName.textContent = place.displayName || '';
93+
placeAddress.textContent = place.formattedAddress || '';
94+
95+
let firstTabActivated = false;
96+
97+
/**
98+
* Safe Helper: Accepts either a text string or a DOM Node (like a div or DocumentFragment).
99+
*/
100+
const createTab = (
101+
label: string,
102+
content: string | Node,
103+
disclosure: string
104+
) => {
105+
const btn = document.createElement('button');
106+
btn.className = 'tab-button';
107+
btn.textContent = label;
108+
109+
btn.onclick = () => {
110+
// Do nothing if the tab is already active.
111+
if (btn.classList.contains('active')) {
112+
return;
113+
}
61114

62-
// Retrieve the summary text and disclosure text.
115+
// Manage the active class state.
116+
document
117+
.querySelectorAll('.tab-button')
118+
.forEach((b) => b.classList.remove('active'));
119+
btn.classList.add('active');
120+
121+
if (typeof content === 'string') {
122+
summaryContent.textContent = content;
123+
} else {
124+
summaryContent.replaceChildren(content.cloneNode(true));
125+
}
126+
127+
// Set the disclosure text.
128+
aiDisclosure.textContent = disclosure || 'AI-generated content.';
129+
};
130+
131+
tabContainer.appendChild(btn);
132+
133+
// Auto-select the first available summary.
134+
if (!firstTabActivated) {
135+
btn.click();
136+
firstTabActivated = true;
137+
}
138+
};
139+
140+
// --- 1. Generative Summary (Place) ---
63141
//@ts-ignore
64-
let overviewText = place.generativeSummary.overview ?? 'No summary is available.';
142+
if (place.generativeSummary?.overview) {
143+
createTab(
144+
'Overview',
145+
//@ts-ignore
146+
place.generativeSummary.overview,
147+
//@ts-ignore
148+
place.generativeSummary.disclosureText
149+
);
150+
}
151+
152+
// --- 2. Review Summary ---
65153
//@ts-ignore
66-
let disclosureText = place.generativeSummary.disclosureText ?? '';
154+
if (place.reviewSummary?.text) {
155+
createTab(
156+
'Reviews',
157+
//@ts-ignore
158+
place.reviewSummary.text,
159+
//@ts-ignore
160+
place.reviewSummary.disclosureText
161+
);
162+
}
67163

68-
address.textContent = place.formattedAddress ?? '';
69-
summary.textContent = `${overviewText} [${disclosureText}]`;
70-
content.append(address, lineBreak, summary);;
164+
// --- 3. Neighborhood Summary ---
165+
//@ts-ignore
166+
if (place.neighborhoodSummary?.overview?.content) {
167+
createTab(
168+
'Neighborhood',
169+
//@ts-ignore
170+
place.neighborhoodSummary.overview.content,
171+
//@ts-ignore
172+
place.neighborhoodSummary.disclosureText
173+
);
174+
}
71175

72-
innerMap.setCenter(place.location);
176+
// --- 4. EV Amenity Summary (uses content blocks)) ---
177+
//@ts-ignore
178+
if (place.evChargeAmenitySummary) {
179+
//@ts-ignore
180+
const evSummary = place.evChargeAmenitySummary;
181+
const evContainer = document.createDocumentFragment();
73182

74-
// Display an info window.
75-
infoWindow.setHeaderContent(place.displayName);
76-
infoWindow.setContent(content);
77-
infoWindow.open({
78-
anchor: marker,
79-
});
183+
// Helper to build a safe DOM section for EV categories.
184+
const createSection = (title: string, text: string) => {
185+
const wrapper = document.createElement('div');
186+
wrapper.style.marginBottom = '15px'; // Or use a CSS class
187+
188+
const titleEl = document.createElement('strong');
189+
titleEl.textContent = title;
190+
191+
const textEl = document.createElement('div');
192+
textEl.textContent = text;
193+
194+
wrapper.appendChild(titleEl);
195+
wrapper.appendChild(textEl);
196+
return wrapper;
197+
};
198+
199+
// Check and append each potential section
200+
if (evSummary.overview?.content) {
201+
evContainer.appendChild(
202+
createSection('Overview', evSummary.overview.content)
203+
);
204+
}
205+
if (evSummary.coffee?.content) {
206+
evContainer.appendChild(
207+
createSection('Coffee', evSummary.coffee.content)
208+
);
209+
}
210+
if (evSummary.restaurant?.content) {
211+
evContainer.appendChild(
212+
createSection('Food', evSummary.restaurant.content)
213+
);
214+
}
215+
if (evSummary.store?.content) {
216+
evContainer.appendChild(
217+
createSection('Shopping', evSummary.store.content)
218+
);
219+
}
220+
221+
// Only add the tab if the container has children
222+
if (evContainer.hasChildNodes()) {
223+
createTab(
224+
'EV Amenities',
225+
evContainer, // Passing a Node instead of string
226+
evSummary.disclosureText
227+
);
228+
}
229+
}
230+
231+
// Safely handle the empty state.
232+
if (!firstTabActivated) {
233+
const msg = document.createElement('em');
234+
msg.textContent =
235+
'No AI summaries are available for this specific location.';
236+
summaryContent.replaceChildren(msg);
237+
aiDisclosure.textContent = '';
238+
}
80239
}
81240

82241
initMap();
83-
// [END maps_ai_powered_summaries_basic]
242+
// [END maps_ai_powered_summaries]

0 commit comments

Comments
 (0)