Implementation notes
Update: 03/31/2023 - Updated focus states for accessibility.
1. Create a 🟨 Locations collection with all desired fields. Include Latitude & Longitude fields as plain text (not numbers).
2. Create a 🟨 Locations collection list on a static page. Apply the Location Item class to the collection items for later creating the locations array.
3. Create a hidden embed inside the collection item with any dynamic data you'd like to reference in the javascript. Latitude & Longitude coordinates are required for placing the location's pin & the slug for linking the collection to the pin's info window.
<div class="data---slug w-dyn-bind-empty">{{slug}}</div>
<div class="data---latitude w-dyn-bind-empty">{{latitude}}</div>
<div class="data---longitude w-dyn-bind-empty">{{longitude}}</div>
3.Create a hidden div inside the collection item named Data - Info Window & include all of the content you'd like in the map pin's info window.
4.Create an embed with the following javascript to open the pin's info window on click from the 🟨 Locations collection item. Then include & style any other data you'd like in the locations list.
<a href="javascript:google.maps.event.trigger(gmarkers['{{slug}}'],'click');" class="text-decoration---none"><div class="medium">{{name}}</div></a>
5. Include the Google Maps API script at the end of your page's body.
<script async defer src="https://maps.googleapis.com/maps/api/js?key[your-API-key]&callback=initMap" type="text/javascript"></script>
6. Include the map javascript between script tags after the Google Maps API script at the end of your page's body.
// This script is adapted from Anna Sabatini's dynamic Google Maps project
// https://discourse.webflow.com/t/tutorial-adding-several-markers-on-one-google-map-from-dynamic-collection/114410
// Run code when page loads
window.addEventListener('load', function () {
// Create a locations array
var locations = []
// Add .location-wrapper class to the location Collection Item
var dynPlaces = document.querySelectorAll('.w-dyn-item.location-item');
// Define variables for the map info window
dynPlaces.forEach( function(elem) {
// Create places array
var place = [];
// Define variables for each place
var dataTitle = elem.querySelector('.data---slug').innerText; // Define slug for targeting the information window
var dataLat = Number(elem.querySelector('.data---latitude').innerText); // Define latitude point for pin
var dataLong = Number(elem.querySelector('.data---longitude').innerText); // Define longitude point for pin
var infoWindowContent = elem.querySelector('.data---info-window').innerHTML; // Define content wrapper for the information window
place.push(dataTitle, infoWindowContent, dataLat, dataLong); // Add variables to each place
locations.push(place); // Add each place to the locations array
});
// Map settings
var map = new google.maps.Map(document.getElementById('map'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false,
mapTypeControl: false,
fullscreenControl: false,
scrollwheel: false,
// Json map styling via https://mapstyle.withgoogle.com
styles: [
{
"elementType": "geometry",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"elementType": "labels.icon",
"stylers": [
{
"visibility": "off"
}
]
},
{
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#616161"
}
]
},
{
"elementType": "labels.text.stroke",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"featureType": "administrative.land_parcel",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#bdbdbd"
}
]
},
{
"featureType": "administrative.province",
"elementType": "geometry.stroke",
"stylers": [
{
"color": "#bababa"
},
{
"visibility": "on"
},
{
"weight": 1.5
}
]
},
{
"featureType": "poi",
"stylers": [
{
"color": "#bababa"
},
{
"visibility": "on"
}
]
},
{
"featureType": "poi",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#757575"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.stroke",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "poi.park",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
},
{
"featureType": "road",
"stylers": [
{
"visibility": "simplified"
}
]
},
{
"featureType": "road",
"elementType": "geometry",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "road.arterial",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#757575"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry",
"stylers": [
{
"color": "#dadada"
}
]
},
{
"featureType": "road.highway",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#616161"
}
]
},
{
"featureType": "road.local",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
},
{
"featureType": "transit.line",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "transit.station",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#c9c9c9"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
}
]
});
// Create info windows
var infowindow = new google.maps.InfoWindow();
// Style markers (reference svgMarker as icon in createMarker function to use)
/*
const svgMarker = {
path: "M3.18236 3.94954C1.59126 5.64764 0.594653 8.12129 0.633351 10.448C0.71416 15.3102 2.90579 17.1508 6.41061 23.8426C7.67311 26.7873 8.99079 29.9032 10.244 35.0637C10.4182 35.8249 10.588 36.532 10.6666 36.5933C10.7451 36.6546 10.915 35.945 11.0892 35.1838C12.3424 30.0232 13.6601 26.9099 14.9226 23.9652C18.4274 17.2733 20.619 15.4327 20.6998 10.5705C20.7385 8.24379 19.7395 5.76766 18.1484 4.06956C16.3308 2.12977 13.5893 0.694173 10.6666 0.634142C7.74386 0.574072 4.99993 2.00974 3.18236 3.94954Z",
fillColor: "#1169FE",
fillOpacity: 1,
strokeWeight: 1.26462,
strokeColor: "#004FD6",
rotation: 0,
scale: 1,
anchor: new google.maps.Point(15, 30),
};
*/
// Create markers
function createMarker(latlng, html) {
var marker = new google.maps.Marker({
position: latlng,
map: map,
icon: "https://cdn.prod.website-files.com/631fe6ec99d4fc7b8a51759c/6324065e9ce860443217c6f7_Google_Maps_pin%201.svg"
});
// Define info window for each marker
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(html);
infowindow.open(map, marker);
});
return marker;
}
gmarkers = [];
for (var i = 0; i < locations.length; i++) {
gmarkers[locations[i][0]] =
createMarker(new google.maps.LatLng(locations[i][2], locations[i][3]), // passing lat and long
locations[i][1]); // passing Info-window information
}
// Create map bounds and center map
var bounds = new google.maps.LatLngBounds();
var northwest = new google.maps.LatLng(33.7859225, -84.4166867); // Northwest bound
var southeast = new google.maps.LatLng(33.744205, -84.273109); // Southeast bound
bounds.extend(northwest);
bounds.extend(southeast);
map.fitBounds(bounds);
map.setCenter(bounds.getCenter());
}, false);
6.Create a div with the ID #map for the map to appear in. Position it as needed.
7. Customize the map styling with Google's Styling Wizard. Replace the json in the styles section of the javascript.
8. Treat yourself to a night on the town. You are done.