Skip to content

Commit a0274af

Browse files
committed
Updated Google Maps API and improved the example
1 parent 31df517 commit a0274af

File tree

1 file changed

+186
-136
lines changed

1 file changed

+186
-136
lines changed

views/api/google-maps.pug

Lines changed: 186 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
extends ../layout
22

33
block content
4-
style.
5-
#map {
6-
width: 100%;
7-
height: 500px;
8-
}
9-
104
.pb-2.mt-2.mb-4.border-bottom
115
h2
12-
i.fab.fa-google.fa-sm.iconpadding
13-
| Google Maps API
6+
i.fas.fa-map.fa-sm.iconpadding
7+
| Google Maps JavaScript API
148

159
.btn-group.d-flex(role='group')
1610
a.btn.btn-primary.w-100(href='https://developers.google.com/maps/documentation/javascript/tutorial', target='_blank')
@@ -20,139 +14,195 @@ block content
2014
i.fas.fa-laptop.fa-sm.iconpadding
2115
| API Console
2216

23-
h3 Markers Example
17+
br
18+
p This example uses custom markers with Font Awesome icons, a custom map control (Center Map), and restricted navigation boundaries.
2419

25-
#map
20+
.row
21+
.col-md-12
22+
#map(style='height: 500px')
2623

24+
script(src='https://polyfill.io/v3/polyfill.min.js?features=default')
25+
script(src=`https://maps.googleapis.com/maps/api/js?key=${google_map_api_key}&libraries=marker&loading=async`)
2726
script.
28-
var map;
29-
var superchargers = [
30-
{
31-
location: 'Fremont',
32-
latitude: 37.49267,
33-
longitude: -121.94409,
34-
},
35-
{
36-
location: 'Folsom',
37-
latitude: 38.64392,
38-
longitude: -121.18621,
39-
},
40-
{
41-
location: 'Gilroy',
42-
latitude: 37.02615,
43-
longitude: -121.56487,
44-
},
45-
{
46-
location: 'Harris Ranch',
47-
latitude: 36.25316,
48-
longitude: -120.23853,
49-
},
50-
{
51-
location: 'Mt. Shasta',
52-
latitude: 41.30981,
53-
longitude: -122.31766,
54-
},
55-
{
56-
location: 'Roseville',
57-
latitude: 38.77344,
58-
longitude: -121.26928,
59-
},
60-
{
61-
location: 'Truckee',
62-
latitude: 39.3272,
63-
longitude: -120.20643,
64-
},
65-
{
66-
location: 'Vacaville',
67-
latitude: 38.3672,
68-
longitude: -121.95601,
69-
},
70-
{
71-
location: 'Atascadero',
72-
latitude: 35.4864,
73-
longitude: -120.66558,
74-
},
75-
{
76-
location: 'Barstow',
77-
latitude: 34.8912,
78-
longitude: -116.9991,
79-
},
80-
{
81-
location: 'Buellton',
82-
latitude: 34.61545,
83-
longitude: -120.18856,
84-
},
85-
{
86-
location: 'Cabazon',
87-
latitude: 33.92967,
88-
longitude: -116.81649,
89-
},
90-
{
91-
location: 'Culver City',
92-
latitude: 33.98465,
93-
longitude: -118.39505,
94-
},
95-
{
96-
location: 'El Centro',
97-
latitude: 32.762,
98-
longitude: -115.53197,
99-
},
100-
{
101-
location: 'Indio',
102-
latitude: 33.74272,
103-
longitude: -116.21316,
104-
},
105-
{
106-
location: 'Los Angeles',
107-
latitude: 33.92142,
108-
longitude: -118.32982,
109-
},
110-
{
111-
location: 'Needles',
112-
latitude: 34.85083,
113-
longitude: -114.62414,
114-
},
115-
116-
{
117-
location: 'Oxnard',
118-
latitude: 34.24075,
119-
longitude: -119.17699,
120-
},
121-
{
122-
location: 'Rancho Cucamonga',
123-
latitude: 34.11348,
124-
longitude: -117.53257,
125-
},
126-
{
127-
location: 'San Juan Capistrano',
128-
latitude: 33.49835,
129-
longitude: -117.66287,
130-
},
131-
{
132-
location: 'Tejon Ranch',
133-
latitude: 34.98661,
134-
longitude: -118.9463,
135-
},
136-
];
137-
138-
function initMap() {
139-
map = new google.maps.Map(document.getElementById('map'), {
140-
center: { lat: 36.0907578, lng: -119.5948303 },
141-
zoom: 7,
142-
});
27+
let map;
28+
let mapLoaded = false;
29+
30+
class CustomMarker {
31+
constructor(position, icon, title) {
32+
const markerElement = document.createElement('div');
33+
markerElement.className = 'custom-marker';
34+
35+
const container = document.createElement('div');
36+
container.style.position = 'relative';
37+
container.style.cursor = 'pointer';
38+
container.style.textAlign = 'center';
39+
40+
// Create pin shape with pseudo-element
41+
const pin = document.createElement('div');
42+
pin.style.background = 'rgb(231, 167, 149)';
43+
pin.style.width = '30px';
44+
pin.style.height = '40px';
45+
pin.style.borderRadius = '50% 50% 50% 0';
46+
pin.style.transform = 'rotate(-45deg)';
47+
pin.style.boxShadow = '0 2px 6px rgba(0, 0, 0, 0.73)';
48+
pin.style.margin = '0 auto';
49+
50+
// Container for the icon
51+
const iconContainer = document.createElement('div');
52+
iconContainer.style.position = 'absolute';
53+
iconContainer.style.top = '12px';
54+
iconContainer.style.left = '0';
55+
iconContainer.style.right = '0';
56+
57+
const iconElement = document.createElement('i');
58+
iconElement.className = `fas ${icon}`;
59+
iconElement.style.color = 'rgb(104, 32, 32)';
60+
iconElement.style.fontSize = '14px';
61+
62+
// Add text label below the pin
63+
const label = document.createElement('div');
64+
label.style.marginTop = '0px'; // Space between pin and text
65+
label.style.color = 'rgb(78, 25, 25)';
66+
label.style.fontSize = '14px';
67+
label.style.fontWeight = 'bold';
68+
label.style.whiteSpace = 'nowrap';
69+
label.style.textShadow =
70+
'-1px -1px 0 #fff,' + // Top-left
71+
'1px -1px 0 #fff,' + // Top-right
72+
'-1px 1px 0 #fff,' + // Bottom-left
73+
'1px 1px 0 #fff'; // Bottom-right
74+
label.textContent = title;
14375

144-
superchargers.forEach(function (sc) {
145-
var marker = new google.maps.Marker({
146-
position: new google.maps.LatLng(sc.latitude, sc.longitude),
147-
icon: {
148-
url: 'data:image/png;base64,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',
149-
scaledSize: new google.maps.Size(23, 33),
76+
iconContainer.appendChild(iconElement);
77+
container.appendChild(pin);
78+
container.appendChild(iconContainer);
79+
container.appendChild(label);
80+
markerElement.appendChild(container);
81+
82+
return new google.maps.marker.AdvancedMarkerElement({
83+
position,
84+
content: markerElement,
85+
title,
86+
});
87+
}
88+
}
89+
90+
async function initMap() {
91+
if (mapLoaded) return;
92+
93+
try {
94+
map = new google.maps.Map(document.getElementById('map'), {
95+
center: { lat: 37.7749, lng: -122.4194 },
96+
zoom: 13,
97+
maxZoom: 15,
98+
minZoom: 10,
99+
mapId: 'MapID001',
100+
mapTypeId: 'roadmap',
101+
gestureHandling: 'cooperative',
102+
restriction: {
103+
latLngBounds: {
104+
north: 37.85,
105+
south: 37.7,
106+
east: -122.35,
107+
west: -122.52,
108+
},
109+
strictBounds: true,
110+
},
111+
mapTypeControl: true,
112+
mapTypeControlOptions: {
113+
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
114+
position: google.maps.ControlPosition.TOP_RIGHT,
115+
},
116+
zoomControl: true,
117+
zoomControlOptions: {
118+
position: google.maps.ControlPosition.RIGHT_CENTER,
119+
},
120+
scaleControl: true,
121+
streetViewControl: true,
122+
streetViewControlOptions: {
123+
position: google.maps.ControlPosition.RIGHT_TOP,
150124
},
151-
map: map,
152-
title: sc.location,
153-
animation: google.maps.Animation.DROP,
125+
fullscreenControl: true,
154126
});
155-
});
127+
128+
const locations = [
129+
{
130+
position: { lat: 37.7749, lng: -122.4194 },
131+
title: 'San Francisco',
132+
content: 'The cultural, commercial, and financial center of Northern California',
133+
icon: 'fa-city',
134+
},
135+
{
136+
position: { lat: 37.7858, lng: -122.4064 },
137+
title: 'Financial District',
138+
content: "San Francisco's business and financial hub",
139+
icon: 'fa-landmark',
140+
},
141+
{
142+
position: { lat: 37.8019, lng: -122.4189 },
143+
title: "Fisherman's Wharf",
144+
content: 'Famous waterfront neighborhood with seafood restaurants',
145+
icon: 'fa-fish',
146+
},
147+
];
148+
149+
const infoWindow = new google.maps.InfoWindow();
150+
151+
// Wait for the marker library to load
152+
await google.maps.importLibrary('marker');
153+
154+
locations.forEach((location) => {
155+
const marker = new CustomMarker(location.position, location.icon, location.title);
156+
157+
marker.map = map;
158+
159+
marker.addEventListener('gmp-click', () => {
160+
infoWindow.setContent(`
161+
<div style="padding: 10px;">
162+
<h3><i class="fas ${location.icon}"></i> ${location.title}</h3>
163+
<p>${location.content}</p>
164+
</div>
165+
`);
166+
infoWindow.open({
167+
anchor: marker,
168+
map,
169+
});
170+
});
171+
});
172+
173+
const centerControl = document.createElement('div');
174+
centerControl.style.backgroundColor = '#fff';
175+
centerControl.style.border = '2px solid #fff';
176+
centerControl.style.borderRadius = '3px';
177+
centerControl.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';
178+
centerControl.style.cursor = 'pointer';
179+
centerControl.style.marginTop = '10px';
180+
centerControl.style.marginRight = '10px';
181+
centerControl.style.padding = '8px';
182+
centerControl.style.textAlign = 'center';
183+
centerControl.innerHTML = 'Center Map';
184+
centerControl.addEventListener('click', () => {
185+
map.setCenter({ lat: 37.7749, lng: -122.4194 });
186+
map.setZoom(13);
187+
});
188+
189+
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(centerControl);
190+
mapLoaded = true;
191+
} catch (error) {
192+
console.error('Error initializing map:', error);
193+
}
156194
}
157195

158-
script(async, defer, src=`https://maps.googleapis.com/maps/api/js?key=${google_map_api_key}&callback=initMap`)
196+
// Intersection Observer to load map only when visible
197+
const observer = new IntersectionObserver((entries) => {
198+
entries.forEach((entry) => {
199+
if (entry.isIntersecting) {
200+
initMap();
201+
observer.disconnect();
202+
}
203+
});
204+
});
205+
206+
window.addEventListener('load', () => {
207+
observer.observe(document.getElementById('map'));
208+
});

0 commit comments

Comments
 (0)