Display multiple locations with Google Maps API, driven dynamically by Webflow's CMS

Tag name

Credits:

This script is adapted from Anna Sabatini's dynamic Google Maps project


The Setup

Create a container for your Map

Add a div to display the actual map. Give it an ID of ‘map’


Set up your location collection fields

Create a collection and configure your fields. Add all the fields you’ll need, and make sure to include these required fields

  • Lat
  • Long
  • Etc etc


Create a Custom Marker

Design and export your custom marker. Use a simple SVG for best results, or a PNG. Upload to your Webflow Assets and grab the Asset URL.
(If your use case requires, you can also create a custom pin for each location by using a collection field and dynamically referencing it in the code.)


Style your info window


Get your Google Maps API key

Get your API key, and restrict usage to your main and staging domains.


Configure Map Styles

Use the map styler to configure the look, feel and features of your map.

Associate the map style with your Map API project, and copy the map style ID — we’ll reference this in the code later:


The magic code


Add API key between script tags

First, make sure the script has been added to your page.


<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" type="text/javascript"></script>


We’d like to only run the page after the page loads

We need our CMS items to load before we execute the code to avoid errors. We can use the event listener function here to wrap our code:


window.addEventListener('load', function () {
	// insert code here
  };

Create some variables

We’ll start creating some variables to reference in our script.


1. Let’s create variable to hold our locations in an array:


<script>
window.addEventListener('load', function () {
	
  // Create a locations array
  var locations = []
  
  };
</script>


2. Next, we need to get each item of our location list by referencing the class we added to the collection item wrapper and adding to a variable called ‘dynPlaces’. Now that we’ve found each location item on the page (‘dynPlaces’ variable), we’ll add in all the dynamic data from the CMS for each item so that we can use it. For each element in the dynPlaces list, we’ll create a ‘place’ variable, and reference some of the CMS data fields we created including the Title, Latitude, Longitude, and Info Window content. Finally, we’ll push the place data into the locations array we created earlier.
Now, we have we can reference Locations as a list > Each location as an item > and display each item’s unique data.


<script>
window.addEventListener('load', function () {
	
  // Create a locations array
  var locations = []
  
  // Add .locations_item class to the location Collection Item so that we can grab the items here        
  var dynPlaces = document.querySelectorAll('.w-dyn-item.locations_item');    
  
  // Define variables for the map info window        
  dynPlaces.forEach( function(elem) {		
  	
    // Create place 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 dataLat = Number(elem.querySelector('.data---lattitude').innerText);
    
    // Define longitude point for pin
    var dataLong = Number(elem.querySelector('.data---longitude').innerText);
    
    // Define content wrapper for the information window
    var infoWindowContent = elem.querySelector('.locations_data-info-window').innerHTML;
    
    // Push these data variables into the place array
    place.push(dataTitle, infoWindowContent, dataLat, dataLong);
    
    // Add each place to the locations array
    locations.push(place);          
    });
 };
</script>


Configure Map

Make sure you take a look at the Google API docs to see the configuration options available, and adjust to your needs.
First, we’ll create a ‘map’ variable, and use the API guide to create a new map and place it into the map container we created by referencing the container ID, in this case the ID is simply ‘map’. Use the container ID you created, any name is fine as long as what you use the code below matches the ID you added in the designer.
Paste the MAP ID from your google maps profile.


<script>
	// Map settings
	var map = new google.maps.Map(document.getElementById('map'), {
  	mapId: ‘YOUR_MAP_ID’,      
    streetViewControl: false,      
    mapTypeControl: false,      
    fullscreenControl: false,      
    scrollwheel: false,     
    });
</script>


Create Info Windows

Create a variable and tell the api to create info windows:


<script>

	// Create info windows    
	var infowindow = new google.maps.InfoWindow();

</script>

Configure the Marker function

Add a function to create the dynamic markers. In the function, we’ll create a variable, reference data and the map, and add the custom marker icon URL we created here:


<script>

	// Create markers
  function createMarker(latlng, html) {
  	var marker = new google.maps.Marker({
    	position: latlng,
   		map: map,
      icon: “YOUR_ICON_URL”
    });

</script>


Configure Info Windows open/close for each marker

When a user clicks on a marker, we’d like to show the info window. For this, we’ll engage add an event listener to get then content and display open the info window.


<script>

	// Define info window for each marker
  google.maps.event.addListener(marker, 'click', function() {
  	infowindow.setContent(html);
    infowindow.open(map, marker);
    });
   return marker;
   }

</script>



Create the markers and info windows for each location and add it to the map

Now that the marker and info windows have been configured and saved in variables, we’ll create one for each location in our CMS collection and add it to the map.


gmarkers = [];

   for (var i = 0; i < locations.length; i++) {

     gmarkers[locations[i][0]] =

      // passing lat and long

       createMarker(new google.maps.LatLng(locations[i][2], locations[i][3]),

       // passing Info-window information

       locations[i][1]);

   }


Set map bounds

Set the zoom level and map bounds for your use case (reference google maps Api docs here)

// Create map bounds and center map

       var bounds = new google.maps.LatLngBounds();

       // Northwest bound

       var northwest = new google.maps.LatLng(55.738514, 12.462881);

       // Southeast bound

       var southeast = new google.maps.LatLng(55.627170, 12.660888);

       bounds.extend(northwest);

   bounds.extend(southeast);

   map.fitBounds(bounds);

   map.setCenter(bounds.getCenter());

   

 }, false);




And that should do the trick!


Adding a new CMS item will create a new map pin, list item, and info window.

Clicking a collection list item should now highlight and centre it on the map.

Clicking a marker on the map should center it and open the info window.


Good luck!


Working Example:

Clonable:


Full script:


<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" type="text/javascript">

</script>


<script>

   // Run code when page loads

     window.addEventListener('load', function () {


// Create a locations array

       var locations = []


// Add .locations_item class to the location Collection Item

       var dynPlaces = document.querySelectorAll('.w-dyn-item.locations_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('.locations_data-info-window').innerHTML; // Define content wrapper for the information window


           // Add variables to each place

             place.push(dataTitle, infoWindowContent, dataLat, dataLong);

           // Add each place to the locations array

             locations.push(place);  

           });


// Map settings

       var map = new google.maps.Map(document.getElementById('map'), {

         mapId: ‘YOUR_MAP_ID’,

         streetViewControl: false,

         mapTypeControl: false,

         fullscreenControl: false,

         scrollwheel: false,

       });


       // Create info windows

       var infowindow = new google.maps.InfoWindow();


// Create markers

       function createMarker(latlng, html) {

             var marker = new google.maps.Marker({

               position: latlng,

               map: map,

               icon: “YOUR_ICON_URL”

             });


// 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]] =

      // passing lat and long

       createMarker(new google.maps.LatLng(locations[i][2], locations[i][3]),

       // passing Info-window information

       locations[i][1]);

   }

   

   // Create map bounds and center map

   var bounds = new google.maps.LatLngBounds();

   // Northwest bound

   var northwest = new google.maps.LatLng(55.738514, 12.462881);

   // Southeast bound

   var southeast = new google.maps.LatLng(55.627170, 12.660888);

   bounds.extend(northwest);

   bounds.extend(southeast);

   map.fitBounds(bounds);

   map.setCenter(bounds.getCenter());

   

 }, false);


</script>

Unlock your website business

Let's kickstart this exciting journey with an obligation-free initial consultation. Click below to contact, or send an email to jkrdesignsa@gmail.com