Step 1 - Creating the collections
The name, latitude (plain text), & longitude (plain text) fields are all required. Any other information intended to display either in the location cards or in the location info window will also need to be included. This particular project also includes a second collection for location categories, which are displayed as icons here.
Step 2 - Building the UI
The bulk of the UI is made up of the cards in the sidebar, which display the basic information about each location. Critically, the link to trigger the map info window (Location Link inside of the Map Link embed) is javascript, so it has to be created in an embed. This means there are 3 options for situation the link: custom code all the content of the card so that it can be wrapped in the custom link element, embed a clickable link element inside the card, or embed a link element outside of the card & position it absolutely on top of the card. For this project, we've chosen the third so that the entire card is clickable, but the content can still be edited in javascript.
<!-- Link to open corresponding info window -->
<a href="javascript:google.maps.event.trigger(gmarkers['{{slug}}'],'click');" class="location-link position-absolute---full"></a>
The Map window needs a #map ID for the javascript to inject the Google Map into. And the location card Collection Item needs the class Location Item in order to be targeted by the javascript.
Step 3 - Create hidden data
An embed needs to live hidden inside the location card Collection Item which will contain the slug & latitude/longitude variables referenced in the javascript.
<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>
The content intended to display in the Info Window will also need to live inside a Data - Info Window div nested inside the hidden div.
Step 4 - Include the Google Maps API javascript
Paste the following code 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>
Step 5 - Include the custom javascript
Paste the following code after the Google Maps API javascript.
<script>
// 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
window.addEventListener('load', function () {
var locations = [];
var dynPlaces = document.querySelectorAll('.w-dyn-item.location-item');
dynPlaces.forEach(function (elem) {
var place = [];
var dataTitle = elem.querySelector('.data---slug').innerText;
var dataLat = Number(elem.querySelector('.data---latitude').innerText);
var dataLong = Number(elem.querySelector('.data---longitude').innerText);
var infoWindowContent = elem.querySelector('.data---info-window').innerHTML;
place.push(dataTitle, infoWindowContent, dataLat, dataLong);
locations.push(place);
});
var map = new google.maps.Map(document.getElementById('map'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false,
mapTypeControl: false,
fullscreenControl: false,
scrollwheel: false,
styles: [
// Add your provided styles here
{
"elementType": "geometry",
"stylers": [
{
"color": "#faf4e8"
}
]
},
{
"elementType": "labels.icon",
"stylers": [
{
"visibility": "off"
}
]
},
{
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#2e2a2a"
}
]
},
{
"elementType": "labels.text.stroke",
"stylers": [
{
"color": "#faf4e8"
}
]
},
{
"featureType": "administrative.land_parcel",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#a0938c"
}
]
},
{
"featureType": "administrative.province",
"elementType": "geometry.stroke",
"stylers": [
{
"color": "#7e7371"
},
{
"visibility": "on"
},
{
"weight": 1.5
}
]
},
{
"featureType": "poi",
"stylers": [
{
"color": "#7e7371"
},
{
"visibility": "on"
}
]
},
{
"featureType": "poi",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#faede1"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#504949"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.stroke",
"stylers": [
{
"color": "#faf4e8"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#f2e0ce"
}
]
},
{
"featureType": "poi.park",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#706665"
}
]
},
{
"featureType": "road",
"stylers": [
{
"visibility": "simplified"
}
]
},
{
"featureType": "road",
"elementType": "geometry",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "road.arterial",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#504949"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry",
"stylers": [
{
"color": "#eddbc9"
}
]
},
{
"featureType": "road.highway",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#2e2a2a"
}
]
},
{
"featureType": "road.local",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#706665"
}
]
},
{
"featureType": "transit.line",
"elementType": "geometry",
"stylers": [
{
"color": "#f2e0ce"
}
]
},
{
"featureType": "transit.station",
"elementType": "geometry",
"stylers": [
{
"color": "#faede1"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#e6d4c3"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#706665"
}
]
}
]
});
var infowindow = new google.maps.InfoWindow();
function createMarker(latlng, html) {
var marker = new google.maps.Marker({
position: latlng,
map: map,
icon: "https://cdn.prod.website-files.com/65aeaafb5fffb1901c9957c3/65b6a61b255d3d0c963339f0_Google_Maps_pin.svg"
});
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]),
locations[i][1]);
}
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < locations.length; i++) {
bounds.extend(new google.maps.LatLng(locations[i][2], locations[i][3]));
}
map.fitBounds(bounds);
map.setCenter(bounds.getCenter());
}, false);
</script>
Step 6 - Customize the map
Optionally, you can update the map styling with Google's Styling Wizard. Replace the json in the styles section of the javascript. Alternatively, you can simply update the hexadecimal values in the script.