Skip to content

Commit d8f9484

Browse files
Add demo for UI Kit Place Search Text with Details Compact (#607)
Co-authored-by: William French <[email protected]>
1 parent 3ae6ede commit d8f9484

File tree

6 files changed

+381
-0
lines changed

6 files changed

+381
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Google Maps JavaScript Sample
2+
3+
This sample is generated from @googlemaps/js-samples located at
4+
https://github.com/googlemaps-samples/js-api-samples.
5+
6+
## Setup
7+
8+
### Before starting run:
9+
10+
`$npm i`
11+
12+
### Run an example on a local web server
13+
14+
First `cd` to the folder for the sample to run, then:
15+
16+
`$npm start`
17+
18+
### Build an individual example
19+
20+
From `samples/`:
21+
22+
`$npm run build --workspace=sample-name/`
23+
24+
### Build all of the examples.
25+
26+
From `samples/`:
27+
`$npm run build-all`
28+
29+
## Feedback
30+
31+
For feedback related to this sample, please open a new issue on
32+
[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues).
33+
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* @license
3+
* Copyright 2025 Google LLC. All Rights Reserved.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
/* [START maps_ui_kit_place_search_text_compact] */
7+
const mapContainer = document.getElementById("map-container") as any;
8+
const placeSearch = document.querySelector("gmp-place-search") as any;
9+
const placeSearchQuery = document.querySelector("gmp-place-text-search-request") as any;
10+
const queryInput = document.querySelector(".query-input") as any;
11+
const searchButton = document.querySelector(".search-button") as any;
12+
const detailsContainer = document.getElementById("details-container") as any;
13+
const placeDetails = document.querySelector("gmp-place-details-compact") as any;
14+
const placeRequest = document.querySelector("gmp-place-details-place-request") as any;
15+
const warningMsg = document.querySelector(".warning") as any;
16+
let markers = {};
17+
let previousSearchQuery = '';
18+
let gMap;
19+
let placeDetailsPopup;
20+
21+
let AdvancedMarkerElement;
22+
let LatLngBounds;
23+
let LatLng;
24+
25+
async function init() {
26+
//@ts-ignore
27+
const {Map} = await google.maps.importLibrary("maps");
28+
await google.maps.importLibrary("places");
29+
//@ts-ignore
30+
({AdvancedMarkerElement} = await google.maps.importLibrary("marker"));
31+
//@ts-ignore
32+
({LatLngBounds, LatLng} = await google.maps.importLibrary("core"));
33+
34+
let mapOptions = {
35+
center: {lat: 37.422, lng: -122.085},
36+
zoom: 2,
37+
mapTypeControl: false,
38+
clickableIcons: false,
39+
mapId: '2439f449ff38ce55'
40+
};
41+
42+
gMap = new Map(mapContainer, mapOptions);
43+
44+
placeDetailsPopup = new AdvancedMarkerElement({
45+
map: null,
46+
content: placeDetails,
47+
zIndex: 100
48+
});
49+
50+
findCurrentLocation();
51+
52+
gMap.addListener('click', (e) => {
53+
hidePlaceDetailsPopup();
54+
});
55+
56+
searchButton.addEventListener("click", searchPlaces);
57+
queryInput.addEventListener("keydown", (event) => {
58+
if (event.key == 'Enter') {
59+
event.preventDefault();
60+
searchPlaces();
61+
}
62+
});
63+
64+
placeSearch.addEventListener("gmp-select", ({ place }) => {
65+
if (markers[place.id]) {
66+
markers[place.id].click();
67+
}
68+
});
69+
}
70+
71+
function searchPlaces(){
72+
if (queryInput.value.trim() === previousSearchQuery) {
73+
return;
74+
}
75+
previousSearchQuery = queryInput.value.trim();
76+
warningMsg.style.display = 'none';
77+
placeDetailsPopup.map = null;
78+
79+
for(const markerId in markers){
80+
if (Object.prototype.hasOwnProperty.call(markers, markerId)) {
81+
markers[markerId].map = null;
82+
}
83+
}
84+
markers = {};
85+
if (queryInput.value) {
86+
mapContainer.style.height = '75vh';
87+
placeSearch.style.display = 'block';
88+
placeSearchQuery.textQuery = queryInput.value;
89+
placeSearchQuery.locationBias = gMap.getBounds();
90+
placeSearch.addEventListener('gmp-load', addMarkers, { once: true });
91+
}
92+
}
93+
94+
async function addMarkers(){
95+
const bounds = new LatLngBounds();
96+
97+
if(placeSearch.places.length > 0){
98+
placeSearch.places.forEach((place) => {
99+
let marker = new AdvancedMarkerElement({
100+
map: gMap,
101+
position: place.location
102+
});
103+
104+
marker.metadata = {id: place.id};
105+
markers[place.id] = marker;
106+
bounds.extend(place.location);
107+
108+
marker.addListener('click',(event) => {
109+
placeRequest.place = place;
110+
placeDetails.style.display = 'block';
111+
112+
placeDetailsPopup.position = place.location;
113+
placeDetailsPopup.map = gMap;
114+
115+
gMap.fitBounds(place.viewport, {top: 200, left: 100});
116+
117+
});
118+
gMap.setCenter(bounds.getCenter());
119+
gMap.fitBounds(bounds);
120+
});
121+
} else {
122+
warningMsg.style.display = "block";
123+
}
124+
}
125+
126+
async function findCurrentLocation(){
127+
//@ts-ignore
128+
const { LatLng } = await google.maps.importLibrary("core");
129+
if (navigator.geolocation) {
130+
navigator.geolocation.getCurrentPosition(
131+
(position) => {
132+
const pos = new LatLng(position.coords.latitude,position.coords.longitude);
133+
gMap.panTo(pos);
134+
gMap.setZoom(16);
135+
},
136+
() => {
137+
console.log('The Geolocation service failed.');
138+
gMap.setZoom(16);
139+
//@ts-ignore
140+
},
141+
);
142+
} else {
143+
console.log("Your browser doesn't support geolocation");
144+
gMap.setZoom(16);
145+
}
146+
147+
}
148+
149+
function hidePlaceDetailsPopup() {
150+
if (placeDetailsPopup.map) {
151+
placeDetailsPopup.map = null;
152+
placeDetails.style.display = 'none';
153+
}
154+
}
155+
156+
init();
157+
/* [END maps_ui_kit_place_search_text_compact] */
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!--
2+
@license
3+
Copyright 2025 Google LLC. All Rights Reserved.
4+
SPDX-License-Identifier: Apache-2.0
5+
-->
6+
<!--[START maps_ui_kit_place_search_text_compact] -->
7+
<!DOCTYPE html>
8+
<html>
9+
<head>
10+
<title>Places UI Kit: Place (text) search with Place Details Compact</title>
11+
<meta charset="utf-8">
12+
<link rel="stylesheet" type="text/css" href="style.css">
13+
</head>
14+
<body>
15+
<div id="map-container"></div>
16+
<div class="controls">
17+
<input type="text" class="query-input" />
18+
<button class="search-button">Search</button>
19+
</div>
20+
<div class="list-container">
21+
<gmp-place-search orientation="horizontal" selectable>
22+
<gmp-place-all-content> </gmp-place-all-content>
23+
<gmp-place-text-search-request></gmp-place-text-search-request>
24+
</gmp-place-search>
25+
<p class="warning">Looked for it, didn't find it. Let's try something else.</p>
26+
</div>
27+
28+
<div id="details-container">
29+
<gmp-place-details-compact orientation="horizontal">
30+
<gmp-place-details-place-request></gmp-place-details-place-request>
31+
<gmp-place-all-content></gmp-place-all-content>
32+
</gmp-place-details-compact>
33+
</div>
34+
35+
<script>
36+
(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))})({
37+
key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8",
38+
v: "alpha"
39+
});
40+
</script>
41+
<script type="text/JavaScript" src="app.js"></script>
42+
</body>
43+
</html>
44+
<!--[END maps_ui_kit_place_search_text_compact] -->
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "@js-api-samples/ui-kit-place-search-text-compact",
3+
"version": "1.0.0",
4+
"scripts": {
5+
"build": "tsc && bash ../jsfiddle.sh ui-kit-place-search-text-compact && bash ../app.sh ui-kit-place-search-text-compact && bash ../docs.sh ui-kit-place-search-text-compact && npm run build:vite --workspace=. && bash ../dist.sh ui-kit-place-search-text-compact",
6+
"test": "tsc && npm run build:vite --workspace=.",
7+
"start": "tsc && vite build --base './' && vite",
8+
"build:vite": "vite build --base './'",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
13+
}
14+
}
15+
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* @license
3+
* Copyright 2025 Google LLC. All Rights Reserved.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
/* [START maps_ui_kit_place_search_text_compact] */
7+
8+
html,
9+
body {
10+
height: 100%;
11+
margin: 0;
12+
}
13+
14+
body {
15+
display: flex;
16+
flex-direction: column;
17+
font-family: Arial, Helvetica, sans-serif;
18+
}
19+
20+
h1 {
21+
font-size: 16px;
22+
text-align: center;
23+
}
24+
25+
#map-container {
26+
box-sizing: border-box;
27+
width: 100%;
28+
height: 100vh;
29+
}
30+
31+
.warning {
32+
color: red;
33+
position: absolute;
34+
top: 50px;
35+
display: none;
36+
}
37+
38+
.controls {
39+
display: flex;
40+
gap: 10px;
41+
padding: 20px;
42+
margin-top: 20px;
43+
height: 32px;
44+
background-color: #f3f3f3;
45+
border-radius: 20px;
46+
position: absolute;
47+
top: 10px;
48+
left: 50%;
49+
margin-left: -260px;
50+
}
51+
52+
.search-button {
53+
background-color: #4b4b4b;
54+
color: #fff;
55+
border: 1px solid #ccc;
56+
border-radius: 5px;
57+
width: 80px;
58+
}
59+
60+
.query-input {
61+
border: 1px solid #ccc;
62+
border-radius: 5px;
63+
flex-grow: 1;
64+
padding: 10px;
65+
width: 400px;
66+
}
67+
68+
.list-container {
69+
display: flex;
70+
justify-content: center;
71+
position: relative;
72+
}
73+
74+
gmp-place-search {
75+
width: 100%;
76+
margin: 10px;
77+
min-height: 414px;
78+
display: none;
79+
border: none;
80+
}
81+
82+
gmp-place-details-compact {
83+
width: 350px;
84+
max-height: 800px;
85+
margin-right: 20px;
86+
display: none;
87+
border: none;
88+
}
89+
90+
gmp-place-details-compact::after {
91+
content: '';
92+
position: absolute;
93+
bottom: -13px;
94+
left: 50%;
95+
transform: translateX(-50%);
96+
width: 20px;
97+
height: 20px;
98+
background-color: white;
99+
box-shadow: 2px 2px 5px 0px rgba(0,0,0,0.2);
100+
z-index: 1;
101+
clip-path: polygon(0% 0%, 100% 0%, 50% 100%);
102+
transform-origin: center center;
103+
}
104+
105+
@media (prefers-color-scheme: dark) {
106+
/* Style for Dark mode */
107+
gmp-place-details-compact::after {
108+
background-color: #131314;
109+
}
110+
}
111+
112+
.vAygCK-api-load-alpha-banner {
113+
display: none;
114+
}
115+
/* [END maps_ui_kit_place_search_text_compact] */
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"module": "esnext",
4+
"target": "esnext",
5+
"strict": true,
6+
"noImplicitAny": false,
7+
"lib": [
8+
"es2015",
9+
"esnext",
10+
"es6",
11+
"dom",
12+
"dom.iterable"
13+
],
14+
"moduleResolution": "Node",
15+
"jsx": "preserve"
16+
}
17+
}

0 commit comments

Comments
 (0)