Learning objectives:

At the end of the lesson, learners should be able to:

  • Understand how to use the Google Maps API to create a map on a webpage.
  • Understand how to fetch data from an external API and display it on a map.
  • Understand how to add markers to a map and customize the marker icon based on data.
  • Understand how to cluster markers with the marker clustering library.
  • Understand how to add a legend and a print button to a map using HTML and CSS.

Overview:

In this lesson, we will be creating a map of earthquakes that occurred in Kyrgyzstan over the past decade using the Google Maps JavaScript API and earthquake data from the United States Geological Survey (USGS). We will learn how to request data from an API and plot markers on a map based on the coordinates of each earthquake. Additionally, we will use marker clustering to group nearby earthquakes and create a legend to show the magnitude of each earthquake. By the end of this tutorial, you will have a better understanding of how to work with APIs and create interactive maps using the Google Maps JavaScript API.

Requirements:

  • To follow along with this tutorial, you will need a Google account and an API key for the Google Maps API. You can obtain an API key by following the instructions provided by Google or please visit beginner lesson page.
  • A code editor such as Visual Studio Code, Sublime Text, Notepad++ or your favorite code editor.
  • A web browser such as Google Chrome or Mozilla Firefox
  • Basic knowledge of HTML, CSS, and JavaScript

Step 1: HTML Markup

We will start by creating an HTML file and adding the basic markup for our web application. In the head section, we will include a viewport meta tag and a title for the page. In the body section, we will create a div element with an id of “map” that will hold our map.

<!DOCTYPE html>
<html>
  <head>
    <title>Google Maps API - Intermediate </title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      #map {
        height: 100%;
      }
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #title {
        position: absolute;
        top: 10px;
        left: 50%;
        transform: translateX(-50%);
        background-color: rgba(255, 255, 255, 0.8);
        padding: 10px;
        font-size: 24px;
        font-weight: bold;
        border-radius: 10px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      }
      #legend {
        position: absolute;
        top: 120px;
        right: 10px;
        background-color: rgba(255, 255, 255, 0.8);
        padding: 10px;
        font-size: 16px;
        border-radius: 10px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      }
      #print-button {
        position: absolute;
        top: 50%;
        right: 10px;
        background-color: rgba(255, 255, 255, 0.8);
        border: 1px solid #ccc;
        padding: 10px;
        font-size: 12px;
        line-height: 18px;
        cursor: pointer;
        z-index: 1;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <div id="title">Kyrgyzstan Earthquakes the Last Decade</div>
    <div id="legend">
      <div><span style="background-color:rgba(255, 0, 0, 0.8);">    </span> Magnitude >= 6.0</div>
      <div><span style="background-color:rgba(255, 165, 0, 0.8);">    </span> Magnitude >= 5.0 and < 6.0</div>
      <div><span style="background-color:rgba(255, 255, 0, 0.8);">    </span> Magnitude >= 4.0 and < 5.0</div>
      <div><span style="background-color:rgba(0, 128, 0, 0.8);">    </span> Magnitude >= 2.5 and < 4.0</div>
    </div>
    <script>
      // Your code will go here
    </script>
    <script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>
  </body>
</html>

This is an HTML document that includes a Google Maps implementation. The document sets up the appearance of the map, including a title and legend, using CSS styling. The script section contains the code to initialize and display the map. It also includes a script to load the MarkerClusterer library for grouping markers together. Finally, it loads the Google Maps JavaScript API with an API key to enable access to the map functionality.

Step 2: Initialize the Map

1.First, we declare a function called initMap(). This function will be called when the API script loads, and it will initialize the map.

2.Inside the initMap() function, we create a new Google Maps object, passing it the ID of a div element in the HTML document where we want to display the map.

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 6,
    center: {lat: 41.2044, lng: 74.7661}
  });
}

Here, we set the zoom level of the map to 6 and the center point to the coordinates of a location. You can adjust these values according to your requirements.

3.We create an empty array called markers and an empty array called infowindows to store the markers and info windows for each earthquake, respectively.

var markers = [];
var infowindows = [];

Step 3: Using MarkerClusterer and USGS API to Display Earthquake Data on Map

1.The code then uses the MarkerClusterer library to cluster the markers on the map.

var markerCluster = new MarkerClusterer(map, markers,
  {imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});

The MarkerClusterer takes three arguments: the map object, the array of markers to be clustered, and an options object. In this case, the options object specifies the path to the image files that will be used to create the cluster markers.

2.Next, the code requests earthquake data from the USGS API using the fetch() function:

var url = 'https://earthquake.usgs.gov/fdsnws/event/1/query.geojson?starttime=2013-03-05%2000:00:00&endtime=2023-03-12%2023:59:59&maxlatitude=43.232&minlatitude=39.253&maxlongitude=80.354&minlongitude=69.28&minmagnitude=2.5&orderby=time';
fetch(url)
  .then(function(response) {
    return response.json();
  })
  .then(function(data) {
    // Code to add markers for each earthquake goes here
  });

The URL specifies the query parameters to retrieve earthquake data for a specific time period and geographic region. Once the data is retrieved, it is converted to a JavaScript object using the json() method and passed to a callback function to add markers to the map.

3.The callback function loops through each earthquake in the data and creates a marker and infowindow for it. The marker is customized based on the magnitude of the earthquake:

if (feature.properties.mag >= 6.0) {
  marker.setOptions({
      icon: {
      path: 'M 0,-10 10,0 0,10 -10,0 z',
      fillColor: 'red',
      fillOpacity: 0.8,
      strokeColor: 'black',
      strokeWeight: 1
      }
  });
} else if (feature.properties.mag >= 5.0) {
  marker.setOptions({
      icon: {
      path: 'M 0,-10 10,0 0,10 -10,0 z',
      fillColor: 'orange',
      fillOpacity: 0.8,
      strokeColor: 'black',
      strokeWeight: 1
      }
  });
} else if (feature.properties.mag >= 4.0) {
  marker.setOptions({
      icon: {
      path: 'M 0,-10 10,0 0,10 -10,0 z',
      fillColor: 'yellow',
      fillOpacity: 0.8,
      strokeColor: 'black',
      strokeWeight: 1
      }
  });
} else {
  marker.setOptions({
      icon: {
      path: 'M 0,-10 10,0 0,10 -10,0 z',
      fillColor: 'green',
      fillOpacity: 0.8,
      strokeColor: 'black',
      strokeWeight: 1
      }
  });
}

The code sets the marker’s icon based on the earthquake’s magnitude, with larger magnitudes getting more intense colors.

4.Finally, the code adds the marker and infowindow to the markers and infowindows arrays and adds the markers to the marker clusterer.

            var infowindow = new google.maps.InfoWindow({
              content: '<strong>Magnitude: ' + feature.properties.mag + '</strong><br>' +
                feature.properties.place
            });

            marker.addListener('click', function() {
              infowindows.forEach(function(w) { w.close(); });
              infowindow.open(map, marker);
            });

            markers.push(marker);
            infowindows.push(infowindow);
          });

          // Add the markers to the clusterer
          markerCluster.addMarkers(markers);
        });

Step 4: Implementing a Print Button for the Map View

After all the earthquake markers have been added to the map, the code creates a print button widget and adds it to the map. This button allows the user to print the current view of the map.

        // Create a print widget for the map
        google.maps.event.addListenerOnce(map, 'idle', function() {
        var printButton = document.createElement('button');
        printButton.textContent = 'Print Map';
        printButton.id = 'print-button';
        map.controls[google.maps.ControlPosition.TOP_RIGHT].push(printButton);
        printButton.addEventListener('click', function() {
          window.print();
        });
      });

The google.maps.event.addListenerOnce() function is used to add a one-time listener for the idle event of the map. This event is triggered when the map has finished rendering and is idle. Once the event is triggered, the print button is created and added to the map’s control panel in the top right corner. The button’s click event is then registered with the addEventListener() method. When the user clicks the button, the window.print() method is called, which prints the current view of the map.

Step 5: Final step. Save HTML

Save the HTML file and open it in a web browser to view the map.

Note: that the code also includes comments which explain what each section of code does. These comments are denoted by the // symbol.

<!DOCTYPE html>
<html>
  <head>
    <title>Google Maps API - Intermediate </title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      #map {
        height: 100%;
      }
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #title {
        position: absolute;
        top: 10px;
        left: 50%;
        transform: translateX(-50%);
        background-color: rgba(255, 255, 255, 0.8);
        padding: 10px;
        font-size: 24px;
        font-weight: bold;
        border-radius: 10px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      }
      #legend {
        position: absolute;
        top: 120px;
        right: 10px;
        background-color: rgba(255, 255, 255, 0.8);
        padding: 10px;
        font-size: 16px;
        border-radius: 10px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      }
      #print-button {
        position: absolute;
        top: 50%;
        right: 10px;
        background-color: rgba(255, 255, 255, 0.8);
        border: 1px solid #ccc;
        padding: 10px;
        font-size: 12px;
        line-height: 18px;
        cursor: pointer;
        z-index: 1;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <div id="title">Kyrgyzstan Earthquakes the Last Decade</div>
    <div id="legend">
      <div><span style="background-color:rgba(255, 0, 0, 0.8);">    </span> Magnitude >= 6.0</div>
      <div><span style="background-color:rgba(255, 165, 0, 0.8);">    </span> Magnitude >= 5.0 and < 6.0</div>
      <div><span style="background-color:rgba(255, 255, 0, 0.8);">    </span> Magnitude >= 4.0 and < 5.0</div>
      <div><span style="background-color:rgba(0, 128, 0, 0.8);">    </span> Magnitude >= 2.5 and < 4.0</div>
    </div>
    <script>
      function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 6,
          center: {lat: 41.2044, lng: 74.7661}
        });

        var markers = [];
        var infowindows = [];

        // Cluster the markers with marker clustering library
        var markerCluster = new MarkerClusterer(map, markers,
          {imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
        
        // Request the earthquake data from USGS API and plot on the map
        var url = 'https://earthquake.usgs.gov/fdsnws/event/1/query.geojson?starttime=2013-03-05%2000:00:00&endtime=2023-03-12%2023:59:59&maxlatitude=43.232&minlatitude=39.253&maxlongitude=80.354&minlongitude=69.28&minmagnitude=2.5&orderby=time';
        fetch(url)
      .then(function(response) {
        return response.json();
      })
      .then(function(data) {
        
        // Add markers for each earthquake
        data.features.forEach(function(feature) {
          var coords = feature.geometry.coordinates;
          var latLng = new google.maps.LatLng(coords[1], coords[0]);
          var marker = new google.maps.Marker({
              position: latLng,
              title: 'Magnitude: ' + feature.properties.mag
            });

        // Set the marker shape and color based on the magnitude
        if (feature.properties.mag >= 6.0) {
        marker.setOptions({
            icon: {
            path: 'M 0,-10 10,0 0,10 -10,0 z',
            fillColor: 'red',
            fillOpacity: 0.8,
            strokeColor: 'black',
            strokeWeight: 1
            }
        });
        } else if (feature.properties.mag >= 5.0) {
        marker.setOptions({
            icon: {
            path: 'M 0,-10 10,0 0,10 -10,0 z',
            fillColor: 'orange',
            fillOpacity: 0.8,
            strokeColor: 'black',
            strokeWeight: 1
            }
        });
        } else if (feature.properties.mag >= 4.0) {
        marker.setOptions({
            icon: {
            path: 'M 0,-10 10,0 0,10 -10,0 z',
            fillColor: 'yellow',
            fillOpacity: 0.8,
            strokeColor: 'black',
            strokeWeight: 1
            }
        });
        } else {
        marker.setOptions({
            icon: {
            path: 'M 0,-10 10,0 0,10 -10,0 z',
            fillColor: 'green',
            fillOpacity: 0.8,
            strokeColor: 'black',
            strokeWeight: 1
            }
        });
        }
          var infowindow = new google.maps.InfoWindow({
            content: '<strong>Magnitude: ' + feature.properties.mag + '</strong><br>' +
              feature.properties.place
          });

          marker.addListener('click', function() {
            infowindows.forEach(function(w) { w.close(); });
            infowindow.open(map, marker);
          });

          markers.push(marker);
          infowindows.push(infowindow);
          });

          // Add the markers to the clusterer
          markerCluster.addMarkers(markers);
        });
          
        // Create a print widget for the map
        google.maps.event.addListenerOnce(map, 'idle', function() {
        var printButton = document.createElement('button');
        printButton.textContent = 'Print Map';
        printButton.id = 'print-button';
        map.controls[google.maps.ControlPosition.TOP_RIGHT].push(printButton);
        printButton.addEventListener('click', function() {
          window.print();
        });
      });
    }
  </script>
  <script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js"></script>
  <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
</body>
</html>

Conclusion:

In this tutorial, we learned how to use the Google Maps JavaScript API to create an interactive map with custom markers and infowindows. We also explored the MarkerClusterer library to cluster markers and make the map more visually appealing. This tutorial provides a solid foundation for building more complex maps and adding additional functionality.

Some of the key concepts covered in this lesson include:

  • How to use the Google Maps API to create a map on a webpage.
  • How to fetch data from an external API and display it on a map.
  • How to add markers to a map and customize the marker icon based on data.
  • How to cluster markers with the marker clustering library.
  • How to add a legend and a print button to a map using HTML and CSS.

To further explore and expand on the concepts covered in this lesson, learners can refer to the following resources: