Add a map to your website (JavaScript)

1. Before You Begin

In this codelab, you learn everything you need to get started using Google Maps Platform for the web. You learn all the basics, from getting set up to loading the Maps JavaScript API, displaying your first map, working with markers and marker clustering, drawing on the map, and handling user interaction.

What you'll build

e52623cb8578d625.png

In this codelab, you build a simple web app that does the following:

  • Loads the Maps JavaScript API
  • Displays a map centered on Sydney, Australia
  • Displays custom markers for popular attractions in Sydney
  • Implements marker clustering
  • Enables user interaction that recenters and draws a circle on the map when a marker is clicked

What you'll learn

  • Getting started with Google Maps Platform
  • Loading the Maps JavaScript API dynamically from JavaScript code
  • Loading a map
  • Using markers, custom markers, and marker clustering
  • Working with the Maps JavaScript API event system to provide user interaction
  • Controlling the map dynamically
  • Drawing on the map

2. Prerequisites

You'll need to familiarize with the items below to complete this Codelab. If you are already familiar with working with Google Maps Platform, skip ahead to the Codelab!

Required Google Maps Platform Products

In this Codelab, you'll use the following Google Maps Platform products:

Other Requirements for this Codelab

To complete this codelab, you'll need the following accounts, services, and tools:

  • A Google Cloud Platform account with billing enabled
  • A Google Maps Platform API key with the Maps JavaScript API enabled
  • Basic knowledge of JavaScript, HTML, and CSS
  • Node.js installed on your computer
  • A text editor or IDE of your choice

Get started with Google Maps Platform

If you haven't used Google Maps Platform before, follow the Get Started with Google Maps Platform guide or watch the Getting Started with Google Maps Platform playlist to complete the following steps:

  1. Create a billing account.
  2. Create a project.
  3. Enable Google Maps Platform APIs and SDKs (listed in the previous section).
  4. Generate an API key.

3. Get Set Up

Set up Google Maps Platform

If you do not already have a Google Cloud Platform account and a project with billing enabled, please see the Getting Started with Google Maps Platform guide to create a billing account and a project.

  1. In the Cloud Console, click the project drop-down menu and select the project that you want to use for this codelab.

  1. Enable the Google Maps Platform APIs and SDKs required for this codelab in the Google Cloud Marketplace. To do so, follow the steps in this video or this documentation.
  2. Generate an API key in the Credentials page of Cloud Console. You can follow the steps in this video or this documentation. All requests to Google Maps Platform require an API key.

Node.js setup

If you do not already have it, go to https://nodejs.org/ to download and install the Node.js runtime on your computer.

Node.js comes with the npm package manager, which you need to install dependencies for this codelab.

Project starter template setup

Before you begin this codelab, do the following to download the starter project template, as well as the complete solution code:

  1. Download or fork the GitHub repo for this codelab at https://github.com/googlecodelabs/maps-platform-101-js.

The starter project is located in the /starter directory and includes the basic file structure you need to complete the codelab. Everything you need to work with is located in the /starter/src directory. 2. Once you download the starter project, run npm install in the /starter directory. This installs all of the needed dependencies listed in package.json. 3. Once your dependencies are installed, run npm start in the directory.

The starter project has been set up for you to use webpack-dev-server, which compiles and runs the code you write locally. webpack-dev-server also automatically reloads your app in the browser any time you make code changes.

If you'd like to see the full solution code running, you can complete the setup steps above in the /solution directory.

4. Load the Maps JavaScript API

Before you begin, please make sure you follow the steps in Getting Set Up. All done? Okay, time to build your first web app using Google Maps Platform!

The foundation of using Google Maps Platform for the web is the Maps JavaScript API. This API provides a JavaScript interface for using all of the features of Google Maps Platform, including the map, markers, drawing tools, and other Google Maps Platform services, such as Places.

If you have previous experience with the Maps JavaScript API, you may be familiar with loading it by inserting a script tag into an HTML file like this:

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

This is still a perfectly valid way of loading the API, but in modern JavaScript dependencies are normally dynamically included from code. To accomplish the equivalent of the script tag above from code, you'll use the @googlemaps/js-api-loader module. The JS API Loader is already included in the dependencies of the project's package.json file, so it was installed when you ran npm install earlier.

To use the JS API Loader, do the following:

  1. Open /src/app.js. This file is where you will do all of your work for this codelab.
  2. Import the Loader class from @googlemaps/js-api-loader.

    Add the following to the top of app.js:
     import { Loader } from '@googlemaps/js-api-loader';
    
  3. Create an apiOptions object.

    The Loader class requires a JSON object that specifies various options for loading the Maps JavaScript API, including your Google Maps Platform API key, what version of the API you want to load, and any additional libraries provided by the Maps JS API you want to load. For the purposes of this codelab, you only need to specify the API key by appending the following to app.js:
     const apiOptions = {
       apiKey: "YOUR API KEY"
     }
    
  4. Create an instance of Loader and pass it your apiOptions.
     const loader = new Loader(apiOptions);
    
  5. Load the Maps JS API.

    To load the API, call load() on the Loader instance. The JS API Loader returns a promise that resolves once the API is loaded and ready for use. Add the following stub to load the API and handle the promise:
     loader.load().then(() => {
       console.log('Maps JS API loaded');
     });
    

If everything is successful you should see the console.log statement in the browser console. Using Chrome, this additional window can be accessed at View -> Developer -> Javascript Console.

4fa88d1618cc7fd.png

To recap, you've now dynamically loaded the Maps JavaScript API from code and defined the callback function that is executed once the Maps JavaScript API is done loading.

Your app.js file should look something like this:

    import { Loader } from '@googlemaps/js-api-loader';

    const apiOptions = {
      apiKey: "YOUR API KEY"
    }

    const loader = new Loader(apiOptions);

    loader.load().then(() => {
      console.log('Maps JS API Loaded');
    });

Now that the Maps JavaScript API is loaded, you'll load the map in the next step.

5. Display a map

Time to display your first map!

The most commonly used part of the Maps JavaScript API is google.maps.Map, which is the class that allows us to create and manipulate map instances. Take a look at how that's done by creating a new function called displayMap().

  1. Define your map settings.

    The Maps JavaScript API supports a variety of different settings for the map, but only two are required:
    • center: sets the latitude and longitude for the center of the map.
    • zoom: sets the initial zoom level of the map.
    Use the following code to center the map on Sydney, Australia, and give it a zoom level of 14, which is just the right zoom level to show the city center.
     function displayMap() {
       const mapOptions = {
         center: { lat: -33.860664, lng: 151.208138 },
         zoom: 14
       };
     }
    
  2. Get the div where the map should be injected into the DOM.

    Before you can display the map, you need to tell the Maps JavaScript API where you want it to be displayed in the page. If you take a quick look in index.html, you see that there's already a div that looks like this:
     <div id="map"></div>
    
    To tell the Maps JavaScript API this is where you want the map to be injected, use document.getElementById to get its DOM reference:
     const mapDiv = document.getElementById('map');
    
  3. Create an instance of google.maps.Map.

    To ask the Maps JavaScript API to create a new map that can be displayed, create an instance of google.maps.Map, and pass in the mapDiv and mapOptions. You also return the Map instance from this function so that you can do more with it later:
     const map = new google.maps.Map(mapDiv, mapOptions);
     return map;
    
  4. Display the map!

    Once you define all of the logic for creating your map instance, all that's left is to call displayMap() from the JS API promise handler so that it is called once the Maps JavaScript API loads:
     loader.then(() => {
       console.log('Maps JS API loaded');
       const map = displayMap();
     });
    

You should now see a beautiful map of Sydney in your browser:

fb0cd6bc38532780.png

To recap, in this step you defined display options for the map, created a new map instance, and injected it into the DOM.

Your displayMap() function should look something like this:

function displayMap() {
  const mapOptions = {
    center: { lat: -33.860664, lng: 151.208138 },
    zoom: 14
  };
  const mapDiv = document.getElementById('map');
  const map = new google.maps.Map(mapDiv, mapOptions);
  return map;
}

6. Cloud-based map styling (Optional)

You can customize the style of your map using Cloud-based map styling.

Create a Map ID

If you have not yet created a map ID with a map style associated to it, see the Map IDs guide to complete the following steps:

  1. Create a map ID.
  2. Associate a map ID to a map style.

Adding the Map ID to your app

To use the map ID you created, modify the displayMap function in the app.js file and pass your map ID in the mapId property of the mapOptions object.

app.js

function displayMap() {
  const mapOptions = {
    center: { lat: -33.860664, lng: 151.208138 },
    zoom: 14,
    mapId: 'YOUR_MAP_ID'
  };
  const mapDiv = document.getElementById('map');
  return new google.maps.Map(mapDiv, mapOptions);
}

Once you've completed this, you should now see the style you selected on the map!

7. Add markers to the map

There's lots of things developers do with the Maps JavaScript API, but putting markers on the map is definitely the most popular. Markers allow you to show specific points on the map, and are a common UI element for handling user interaction. If you've used Google Maps before, then you're probably familiar with the default marker, which looks like this:

590815267846f166.png

In this step, you'll use google.maps.Marker to put markers on the map.

  1. Define an object for your marker locations.

    To start, create a new addMarkers() function, and declare a locations object that has the following set of latitude/longitude points for popular tourist attractions in Sydney.

    Also, note that you need to pass your Map instance to the function. You'll use this later when you create your marker instances.
     function addMarkers(map) {
       const locations = {
         operaHouse: { lat: -33.8567844, lng: 151.213108 },
         tarongaZoo: { lat: -33.8472767, lng: 151.2188164 },
         manlyBeach: { lat: -33.8209738, lng: 151.2563253 },
         hyderPark: { lat: -33.8690081, lng: 151.2052393 },
         theRocks: { lat: -33.8587568, lng: 151.2058246 },
         circularQuay: { lat: -33.858761, lng: 151.2055688 },
         harbourBridge: { lat: -33.852228, lng: 151.2038374 },
         kingsCross: { lat: -33.8737375, lng: 151.222569 },
         botanicGardens: { lat: -33.864167, lng: 151.216387 },
         museumOfSydney: { lat: -33.8636005, lng: 151.2092542 },
         maritimeMuseum: { lat: -33.869395, lng: 151.198648 },
         kingStreetWharf: { lat: -33.8665445, lng: 151.1989808 },
         aquarium: { lat: -33.869627, lng: 151.202146 },
         darlingHarbour: { lat: -33.87488, lng: 151.1987113 },
         barangaroo: { lat: - 33.8605523, lng: 151.1972205 }
       }
     }
    
  2. Create an instance of google.maps.Marker for each marker you want displayed.

    To create your markers, use the code below to iterate through the locations object using a for...in loop, create a set of options for how each marker should be rendered, and then create an instance of google.maps.Marker for each location.

    Notice the icon property of markerOptions. Remember the default map pin from earlier? Did you know you can also customize the pin to be any image you want? Well, you can!

    The icon property allows you to provide the path to any image file you want to use as a custom marker. If you started this codelab using our project template, then an image is already included for you in /src/images.

    Notice also that you need to store your marker instances in an array and return them from the function so that they can be used later.
     const markers = [];
     for (const location in locations) {
       const markerOptions = {
         map: map,
         position: locations[location],
         icon: './img/custom_pin.png'
       }
       const marker = new google.maps.Marker(markerOptions);
       markers.push(marker);
     }
     return markers;
    
  3. Display the markers.

    The Maps JavaScript API automatically creates and displays a marker whenever a new instance of google.maps.Marker is created, so now all you need to do is update your JS API promise handler to call addMarkers() and pass it your Map instance:
     loader.then(() => {
       console.log('Maps JS API loaded');
       const map = displayMap();
       const markers = addMarkers(map);
     });
    

You should now see custom markers on the map:

1e4a55de15215480.png

To recap, in this step you defined a set of marker locations and created an instance of google.maps.Marker with a custom marker icon for each location.

Your addMarkers() function should look something like this:

    function addMarkers(map) {
      const locations = {
        operaHouse: { lat: -33.8567844, lng: 151.213108 },
        tarongaZoo: { lat: -33.8472767, lng: 151.2188164 },
        manlyBeach: { lat: -33.8209738, lng: 151.2563253 },
        hyderPark: { lat: -33.8690081, lng: 151.2052393 },
        theRocks: { lat: -33.8587568, lng: 151.2058246 },
        circularQuay: { lat: -33.858761, lng: 151.2055688 },
        harbourBridge: { lat: -33.852228, lng: 151.2038374 },
        kingsCross: { lat: -33.8737375, lng: 151.222569 },
        botanicGardens: { lat: -33.864167, lng: 151.216387 },
        museumOfSydney: { lat: -33.8636005, lng: 151.2092542 },
        maritimeMuseum: { lat: -33.869395, lng: 151.198648 },
        kingStreetWharf: { lat: -33.8665445, lng: 151.1989808 },
        aquarium: { lat: -33.869627, lng: 151.202146 },
        darlingHarbour: { lat: -33.87488, lng: 151.1987113 },
        barangaroo: { lat: - 33.8605523, lng: 151.1972205 }
      }
      const markers = [];
      for (const location in locations) {
        const markerOptions = {
          map: map,
          position: locations[location],
          icon: './img/custom_pin.png'
        }
        const marker = new google.maps.Marker(markerOptions);
        markers.push(marker);
      }
      return markers;
    }

In the next step, you'll look at how to improve the user experience of markers using marker clustering.

8. Enable marker clustering

When using a lot of markers or markers that are in close proximity to one another, you may encounter an issue where the markers overlap or appear too crowded together, which causes a bad user experience. For example, after creating the markers in the last step, you may have noticed this:

6e39736160c6bce4.png

This is where marker clustering comes in. Marker clustering is another commonly implemented feature, which groups nearby markers into a single icon that changes depending on the zoom level, like this:

4f372caab95d7499.png

The algorithm for marker clustering divides the visible area of the map into a grid, then clusters icons that are in the same cell. Luckily, you don't have to worry about any of that because the Google Maps Platform team created a helpful, open-source utility library called MarkerClustererPlus that does everything for you automatically. You can view the source for MarkerClustererPluson GitHub.

  1. Import the MarkerCluster.

    For the template project for this codelab, the MarkerClustererPlus utility library is already included in the dependencies declared in the package.json file, so you already installed it when you ran npm install at the beginning of this codelab.

    To import the library, add the following to the top of your app.js file:
     import MarkerClusterer from '@google/markerclustererplus';
    
  2. Create a new instance of MarkerClusterer.

    To create marker clusters, you need to do two things: provide the icons you want to use for your marker clusters, and create a new instance of MarkerClusterer.

    First, declare an object that specifies the path to the icons you want to use. In the template project, there are already a set of images saved in ./img/m. Notice the image filenames are numbered sequentially with the same prefix: m1.png, m2.png, m3.png, and so on.

    When you set the imagePath property in the options for the marker clusterer, you simply provide the path and file prefix, and the marker clusterer automatically uses all files with that prefix and append a number to the end.

    Second, create a new instance of MarkerClusterer, and pass it the instance of Map where you want the marker clusters displayed and an array of Marker instances that you want clustered.
     function clusterMarkers(map, markers) {
       const clustererOptions = { imagePath: './img/m' }
       const markerCluster = new MarkerClusterer(map, markers, clustererOptions);
     }
    
  3. Display the marker clusters.

    Call clusterMarkers() from the JS API promise handler. The marker clusters are automatically added to the map when the MarkerClusterer instance is created in the function call.
     loader.then(() => {
       console.log('Maps JS API loaded');
       const map = displayMap();
       const markers = addMarkers(map);
       clusterMarkers(map, markers);
     });
    

You should now see a couple marker clusters on your map.

e52623cb8578d625.png

Notice that if you zoom in or out, MarkerClustererPlus automatically renumbers and resizes the clusters for you. You can also click on any marker cluster icon to zoom in and see all of the markers included in that cluster.

d572fa11aca13eeb.png

To recap, in this step you imported the open-source MarkerClustererPlus utility library and used it to create an instance of MarkerClusterer that automatically clustered the markers you created in the previous step.

Your clusterMarkers() function should look something like this:

    function clusterMarkers(map, markers) {
      const clustererOptions = { imagePath: './img/m' }
      const markerCluster = new MarkerClusterer(map, markers, clustererOptions);
    }

Next, you'll learn how to handle user interaction.

9. Add user interaction

Now you have a great looking map that displays some of Sydney's most popular tourist destinations. In this step, you'll add some additional handling of user interactions using the event system of the Maps JavaScript API to further improve the user experience of your map.

The Maps JavaScript API provides a comprehensive event system that uses JavaScript event handlers to allow you to handle various user interactions in code. For example, you can create event listeners to trigger code execution for interactions like the user clicking on the map and markers, panning the view of the map, zooming in and out, and more.

In this step, you'll add a click listener to your markers, and then programmatically make the map pan to put the marker the user clicked at the center of the map.

  1. Set a click listener on your markers.

    All of the objects in the Maps JavaScript API that support the event system implement a standard set of functions for handling user interaction, such as addListener, removeListener, and more.

    To add a click event listener to each marker, iterate the markers array and call addListener on the marker instance to attach a listener for the click event:
     function addPanToMarker(map, markers) {
       markers.map(marker => {
         marker.addListener('click', event => {
    
         });
       });
     }
    
  2. Pan to a marker when it is clicked on.

    The click event is triggered whenever a user clicks or taps on a marker, and returns an event as a JSON object with information about the UI element that was clicked. To improve the user experience of the map, you can handle the click event and use its LatLng object to get the latitude and longitude of the marker that was clicked.

    Once you have that, simply pass that to the Map instance's built-in panTo() function to have the map smoothly pan to recenter on the clicked marker by adding the following in the callback function of the event handler:
     const location = { lat: event.latLng.lat(), lng: event.latLng.lng() };
     map.panTo(location);
    
  3. Assign the click listeners.

    Call addPanToMarker() from the JS API promise handler, and pass it your map and markers to execute the code and assign your click listeners.
     loader.then(() => {
       console.log('Maps JS API loaded');
       const map = displayMap();
       const markers = addMarkers(map);
       clusterMarkers(map, markers);
       addPanToMarker(map, markers);
     });
    

Now go to the browser and click on your markers. You should see the map automatically pan to recenter when a marker is clicked.

To recap, in this step, you used the event system of the Maps JavaScript API to assign a click listener to all of the markers on the map, retrieved the latitude and longitude of the marker from the fired click event, and used that to recenter the map whenever a marker is clicked.

Your addPanToMarker() function should look something like this:

    function addPanToMarker(map, markers) {
      markers = markers.map(marker => {
        marker.addListener('click', event => {
          const location = { lat: event.latLng.lat(), lng: event.latLng.lng() };
          map.panTo(location);
        });
      });
      return markers;
    }

Only one more step to go! Next, you'll further improve the user experience of the map by using the drawing features of the Maps JavaScript API.

10. Draw on the map

So far, you've created a map of Sydney that shows markers for popular tourist destinations and handles the user interaction. For the last step of this codelab, you'll use the drawing features of the Maps JavaScript API to add an additional useful feature to your map experience.

Imagine that this map is going to be used by users that want to explore the city of Sydney. A useful feature would be to visualize a radius around a marker when it is clicked. This would allow the user to easily understand what other destinations are within an easy walking distance of the clicked marker.

The Maps JavaScript API includes a set of functions for drawing shapes on the map, such as squares, polygons, lines, and circles. Next, you'll render a circle to show an 800-meter (approximately half-mile) radius around a marker when it is clicked.

  1. Draw a circle with google.maps.Circle.

    The drawing functions in the Maps JavaScript API give you a wide variety of options for how a drawn object appears on the map. To render a circular radius, declare a set of options for a circle, such as color, stroke weight, where the circle should be centered and its radius, then create a new instance of google.maps.Circle to create a new circle:
     function drawCircle(map, location) {
       const circleOptions = {
         strokeColor: '#FF0000',
         strokeOpacity: 0.8,
         strokeWeight: 1,
         map: map,
         center: location,
         radius: 800
       }
       const circle = new google.maps.Circle(circleOptions);
       return circle;
     }
    
  2. Draw the circle when a marker is clicked.

    To draw the circle when the user clicks on a marker, all you need to do is call the drawCircle() function you wrote above from the click listener callback in addPanToMarker(), and pass it the map and location of the marker.

    Notice how a conditional statement is also added that calls circle.setMap(null). This removes the previously rendered circle from the map if the user clicks another marker, so that you don't end up with a map covered in circles as your user explores the map.

    Your addPanToMarker() function should look something like this:
     function addPanToMarker(map, markers) {
       let circle;
       markers.map(marker => {
         marker.addListener('click', event => {
           const location = { lat: event.latLng.lat(), lng: event.latLng.lng() };
           map.panTo(location);
           if (circle) {
             circle.setMap(null);
           }
           circle = drawCircle(map, location);
         });
       });
     }
    

All done! Go to your browser, and click on one of the markers. You should see a circular radius rendered around it:

254baef70c3ab4d5.png

11. Congratulations

You successfully built your first web app using Google Maps Platform, including loading the Maps JavaScript API, loading a map, working with markers, controlling and drawing on the map, and adding user interaction.

To see the completed code, check out the finished project in the /solutions directory.

What's next?

In this codelab, you covered the basics of what you can do with the Maps JavaScript API. Next, try adding some of these features to the map:

  • Change the map type to display satellite, hybrid, and terrain maps.
  • Enable localization to load the map in different languages.
  • Customize other user interactions like zoom and map controls.
  • Add info windows to display information when markers are clicked.
  • Check out the additional libraries available for the Maps JavaScript API that enable additional functionality, such as Places, drawing, and visualization.

To continue learning more ways you can work with Google Maps Platform on the web, check out these links: