Create Your First 3D Map

1. Before you begin

This codelab is intended to help you understand how to create your first 3D Map using Photorealistic 3D Maps in Maps JavaScript. You will learn the basics about loading the right components of the Maps Javascript API, displaying your first 3D Map and drawing features on it.

What you will build.

First map that you will create.

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

  • Loads the Maps JavaScript API dynamically.
  • Displays a 3D Map centered on the CN Tower in Toronto.
  • Displays a boundary around a location.
  • Turns off the points of interest on the 3D Map.
  • Extrudes the boundary to cover the location.

What you'll learn

  • Getting started with Google Maps Platform.
  • Loading the Maps JavaScript API dynamically from JavaScript code using Dynamic Library Import.
  • Load a 3D Map using the Map3DElement class.
  • Using polygons and extrusion to draw on the map.

2. Prerequisites

You'll need to familiarize yourself with the items here 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:

  • Maps JavaScript API

Yes that's all you will need to add 3D Maps to your page, nothing else, very straightforward!

Other Requirements for this Codelab

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

  • A Google Cloud account with billing enabled
  • A Google Maps Platform API key with the Maps JavaScript API enabled
  • Basic knowledge of JavaScript, HTML, and CSS
  • A text editor or IDE of your choice, to save an edit a file to view
  • A web browser to view the file in as you work

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.

4. Load the Maps JavaScript API

Once you have followed all of the steps in the getting set up section you are all good to get started on building your first 3D Map.

Create the simplest web page you can imagine.

First we will create a very basic web page to host all of our code. You can do this in any editor or platform of your choice.

 <!DOCTYPE html>
 <html>
   <head>
    <title>3D Maps Codelab</title>
     <style>
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
   </head>
   <body>
   </body>
 </html>

Add the code and save the file into an accessible location using a name such as 3dmap.html, then open this up in a web browser to view the current state of the page and see if you have any errors.

Like 2D Maps the foundation of 3D Maps is the Maps Javascript API, so you will first need to load that.

This may be done in a number of ways, which you can find at the Load the Maps JavaScript API section of the documentation.

In this demonstration we are going to use the more modern Dynamic Library Import method as this lets you control only the elements you need to load, saving on download size and startup times.

Add the dynamic loader

To use the dynamic loader make sure you add the following script tag to your web page, adding in your own API KEY at the appropriate place (which you obtained in step 2). Place this script tag between the body sections of the basic web page.

  <script async defer>
    (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
      key: "YOUR_API_KEY",
      v: "alpha",
    });
  </script>

Note at this stage of the product release we are using the alpha branch of the API to get access to the 3D Maps. This contains the most experimental features of the products and lets you test early access code as it is being developed so you can be ready to use it at release time.

You should now have a basic web page containing the dynamic loader (if you open the page the view will be blank, but should have no errors), we are now ready to add the 3D Map.

If for some reason your code is not working, you can go to Step 6 and compare it to the final result to see what is wrong.

To find out why the page might not be working, take a look at the error console in your browser to debug the reason. The error page gives instructions about how to do this for different browsers and also explains various error messages and gives some common reasons why the API might not be working. This is a good resource to use throughout development to work out what might be wrong with any implementation.

5. Display a map

So now we are all set to add our first 3D Map to the page!

3D maps are created using the google.maps.maps3d.Map3DElement class, which allows us to create and work with 3D Map instances. In this codelab we will be working with the 3D Map object directly rather than through the HTML tag.

Create the Init Function and load the library

First we will create a function that loads the element into the page. Look at the code, we first create an asynchronous function, which allows us to make sure that the whole of the element is loaded before proceeding with the rest of the code. We then run the init function as the page loads.

Add this after the loading script within the body section of the page.

  <script>
    async function init() {
      const { Map3DElement } = await google.maps.importLibrary("maps3d");
    }
    init();               
  </script>

Note that we use the await expression to make sure that the library is loaded before proceeding.

Create the 3D map element and specify the location

Next we need to specify the location we want to have the map view. For 3D Maps there are a number of different parameters you can use to set the view. These refer to the virtual camera parameters that describe what you are looking at within the scene.

Let us create a view of the CN Tower that looks a little like this.

First map that you will create.

First we need to specify the coordinates we want to look at. These are made up of two different views

  1. The point we want to look at, including its altitude.
  2. The distance and direction of the virtual camera that is looking at the point.

If you look at the following image, you can get an idea of how these settings work.

Picture showing the Map Element settings.

The center of the element is the point you are looking at, whilst the range is the distance away that you are from the object and the tilt is the angle at which you are viewing the image. You can also set the heading and roll of the object if you want to control those as well, but we are not using this here.

Now we will go and create the 3D Map on the page, add the following code to the page in the init section after the library has been imported.

  const map3DElement = new Map3DElement({
      center: { lat: 43.6425, lng: -79.3871, altitude: 400 },
      range: 1000,
      tilt: 60,
  });

  document.body.append(map3DElement);

First we create the element and set the appropriate location parameters, then we add the component on the page (we could assign it to an existing div if that was present if we wanted to).

Your code should now look like the example here:

<!DOCTYPE html>
<html>

<head>
    <title>3D Maps Codelab</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script async defer>
        (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
            key: "YOUR_API_KEY",
            v: "alpha",
        });
    </script>
    <script>
        async function init() {
            const { Map3DElement } = await google.maps.importLibrary("maps3d");
            
            const map3DElement = new Map3DElement({
                center: { lat: 43.6425, lng: -79.3871, altitude: 400 },
                range: 1000,
                tilt: 60,
            });

            document.body.append(map3DElement);
        }
        
        init();
    </script>
</body>
</html>

We can now save the file and open the page in a browser to see it working. We should see the camera looking down on the tower as is shown in the image. Have a play around before moving on and adding a box over the tower.

First map that you will create.

6. Add and extrude features

So now that we have a 3D Map, let going and highlight an object to users that it is an item of interest. In this case we are going to use a polygon and the extrusion function to create a box around the CN tower, so that it looks something like the following view.

A view of the location with an extruded polygon.

Hide the clutter

The first thing you might notice is that we have turned off the points of interest. In this map we want the focus to be the tower itself so we need to get rid of the other visual elements.

In order to do this we need to add the following code to hide the labels. Add it after the last line of code you added in the last section.

  map3DElement.defaultLabelsDisabled = true;

Setting this property disables the labels on the map, this not only includes points of interest but also, road and boundary lines and creates a "clean" view of the location.

Add and style the polygon

The next step is to add the polygon to the page. This can be done in two steps. First we need to load the functions that contain the required information and the next to specify the styling details about the polygon, such as its color or whether it displays behind other features.

First we add the required classes to the page, using the following line of code.

  const { Polygon3DElement, AltitudeMode } = await google.maps.importLibrary("maps3d");

This loads the Polygon3DElement and AltitudeMode classes into the page, which are required to add a polygon object into the view.

A Polygon can have a number of different settings that can control the view, from the stroke width, color (either by name or hex value) and opacity of the boundary and fill settings, to control on whether it is shown behind other features or buildings, for example : drawing occluded segments. You can find more details in the documentation for the Polygon3DElement class.

The other feature we need to set is so that the Polygon is drawn in an extruded manner. This means to draw a polygon at its set altitude and then extend it down to the ground. This gives the polygon an amount of height like a box (which you can see in the image above). This also requires us to set the altitude mode on the polygon, which is why we needed to load the AltitudeMode constants above. In order to extrude a polygon this needs to be set to either ABSOLUTE or RELATIVE_TO_GROUND in order to get the correct position from the heights on the polygon vertices.

The code creates a literal object which contains these properties that can then be used to create the Polygon3DElement object as shown:

  const polygonOptions = {
    strokeColor: "#EA4335",
    strokeWidth: 4,
    strokeOpacity: 0.8,
    fillColor: "blue",
    fillOpacity: 0.2,
    altitudeMode: "ABSOLUTE",
    extruded: true,
    drawsOccludedSegments: true,
  }

  const towerPolygon = new google.maps.maps3d.Polygon3DElement(polygonOptions);

Now we have created the polygon object and we must also set its geographic coordinates. Polygons can have both inner and outer coordinates depending on how they are being represented, innerCoordinates give the form of cut outs within the polygon and outerCoordinates define the outer boundary of the polygon. As this is a polygon and not a line the coordinates need to start and end at the same point in order to give a complete shape.

You can specify the coordinates using an array of LatLng or LatLngAltitude objects or literals and we can see this for our basic polygon.

  towerPolygon.outerCoordinates = [
    { lat: 43.6427196, lng: -79.3876802, altitude: 600 },
    { lat: 43.6421742, lng: -79.3869184, altitude: 600 },
    { lat: 43.643001, lng: -79.3866475, altitude: 600 },
    { lat: 43.6427196, lng: -79.3876802, altitude: 600 }
  ];

Now we have set up the styling and coordinates for the polygon we are ready to add it to the page. Polygons are child elements of the Map Element and need to be added to an existing map object in the page. Add the following code into the page.

  map3DElement.append(towerPolygon);

Once we have that we should have the following full implementation, as shown here (except it will have your own API key). We are ready to run the page and see the result.

<!DOCTYPE html>
<html>

<head>
    <title>3D Maps Codelab</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script async defer>
        (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
            key: "YOUR_API_KEY",
            v: "alpha",
        });
    </script>
    <script>
        async function init() {
            const { Map3DElement } = await google.maps.importLibrary("maps3d");
            
            const map3DElement = new Map3DElement({
                center: { lat: 43.6425, lng: -79.3871, altitude: 400 },
                range: 1000,
                tilt: 60,
            });

            map3DElement.defaultLabelsDisabled = true;

            const { Polygon3DElement, AltitudeMode } = await google.maps.importLibrary("maps3d");

            const polygonOptions = {
                strokeColor: "#EA4335",
                strokeWidth: 4,
                strokeOpacity: 0.8,
                fillColor: "blue",
                fillOpacity: 0.2,
                altitudeMode: "ABSOLUTE",
                extruded: true,
                drawsOccludedSegments: true,
            }

            const towerPolygon = new google.maps.maps3d.Polygon3DElement(polygonOptions);

            towerPolygon.outerCoordinates = [
                { lat: 43.6427196, lng: -79.3876802, altitude: 600 },
                { lat: 43.6421742, lng: -79.3869184, altitude: 600 },
                { lat: 43.643001, lng: -79.3866475, altitude: 600 },
                { lat: 43.6427196, lng: -79.3876802, altitude: 600 }
            ];

            map3DElement.append(towerPolygon);

            document.body.append(map3DElement);
        }
        
        init();
    </script>

</body>
</html>

If the code is correct you should see a page with the following 3D Map and polygon.

The view that you should have when your code is complete.

You successfully built your first 3D map using Google Maps Platform, including loading the Maps JavaScript API, creating a 3D map and adding an extruded polygon.

7. 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:

  • Add a button to toggle on and off the points of interest.
  • Add some lines that show a route to and from different places..
  • Set some boundary restrictions to control where the user can move the view to.
  • Check out the additional libraries available for the Maps JavaScript API that enable additional services, such as Places or Directions.

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