ArcGIS API for JavaScript

An interactive 3D globe of extremes - a DIY mapping guide

Some months ago I worked with John Nelson on an interactive 3D globe and the project turned out really nicely, so I’ve written a blog post that shows how to create this globe using ArcGIS API for JavaScript.

Screenshot of the interactive 3D globe
The globe of extremes

John Nelson worked with Vizzuality on the Half Earth project and in that process he created a basemap prototype that we’ll use in this tutorial. You can read all about it in his blog post (or as John would put it, don’t read it!). For the globe we were inspired by the Half-Earth globe as well as this beautiful virtual globe and this awesome hand-crafted globe. In this blog post we’ll show you step by step how to create this interactive 3D globe:

Before we get started with the tutorial, the repository for this app is here and each commit corresponds to one step in the tutorial. Click on “see the code” to see the corresponding commit on Github.

Step 1: where we create a globe with a custom basemap

See the code

We start off with a basic setup: we have an HTML page where we initialize a Map and a SceneView that renders the map. Additionally, in the CSS page we set the map container to cover the whole screen.

The important part here is adding the TileLayer that John created as part of the basemap:


const basemap = new Basemap({
  baseLayers: [
    new TileLayer({
       url: "https://tiles.arcgis.com/tiles/.../MapServer"
    })
  ]
});

const map = new Map({
  basemap: basemap
});

step 1 - globe
Globe after step 1

Step 2: where the globe starts looking fancy

See the code

After the first step the globe has a very realistic background and for our app I’d like to give it a playful look that will invite users to explore the data on the globe. For that, we’ll remove the stars and the atmosphere and we’ll add a custom background gradient on the body: background: radial-gradient(#12bff2,#0269a1);. We’ll also set altitude constraints so that the user can’t zoom in or out too much to avoid that they get lost.

Another change that we’ll make to the globe is adding some CSS filters to increase the saturation and additionally we’ll add a white halo around it: filter: saturate(1.5) drop-shadow(0 0 20px white); .

step 2 - globe
Globe after step 2

Step 3: where we exaggerate… the terrain

See the code

In this map we’ll show the highest and the lowest points on Earth, but with the real elevation values you can barely see any changes in the terrain height. To solve that, we’ll exaggerate both land and ocean surface elevation. We’ll use the Topobathy elevation service provided by Esri to have access to world elevation data.

With this technique, the 3D perception of terrain increases considerably as we exaggerate the elevation:

exaggerated elevation
Example of exaggerated elevation

Exaggerating the elevation layer can be done in the API by extending the BaseElevationLayer. In the fetchTile() method we multiply the elevation of each data value with the exaggeration value. After playing around with several values we decided on 60 times larger for values above 0 meters and 40 times smaller for values below 0 meters.


function fetchTile(level, row, col) {
  return this._elevation.fetchTile(level, row, col).then(
    function(data) {
      for (let i = 0; i < data.values.length; i++) {
        if (data.values[i] >= 0) {
          data.values[i] = data.values[i] * 60;
        }
        else {
          data.values[i] = data.values[i] * 40;
        }
      }
      return data;
    }.bind(this));
}

step 3 - globe
Globe after step 3

Step 4: where we add a shiny ocean surface

See the code

John had this cool idea of adding a glassy, semi-transparent surface as the ocean surface, a bit like in this globe. Currently, specular reflection is supported in the API for GLTF models. So our small hack was to add a sphere in GLTF format that has a reflective material and the radius of the Earth. We downloaded the sphere from Sketchfab, but if you want to create it yourself, the KhronosGroup maintains a list of 3D modelling applications that support GLTF. The workflow would be that you create the 3D model in one of those applications, export it as a GLTF and then load it in the API. The sphere is semi-transparent so that we can see the ocean floor through it:


const radius = 6358137; // approximate Earth radius in meters

const origin = new Point({
  x: 0, y: 0, z: -(2 * radius)
});

const oceanSurface = new Graphic({
  geometry: origin,
  symbol: {
    type: "point-3d",
    symbolLayers: [
      {
        type: "object",
        resource: {
          href: "./sphere/scene.gltf"
        },
        width: 2 * radius
      }
    ]
  }
});
view.graphics.add(oceanSurface);

step 4 - globe
Globe after step 4

Step 5: where some clouds show up

See the code

Continuing with the experiments, we wanted to add some clouds to our globe. NASA has satellite images of clouds available for public use, so we added a layer of clouds using the Mesh class. Basically we create a sphere with Mesh.createSphere() and we map the clouds image as a texture on the sphere. Of course, the clouds are then not exactly in the place they were when the image was taken, but that is not very relevant for our visualization. We elevated clouds from the globe by adding an offset of 300km to the radius of the Earth and setting this as the radius of the mesh sphere.

step 5 - globe
Globe after step 5

Step 6: where we collect and display the extreme points

See the code

This was the tedious part of this project: actual data collection. The main resource was this wikipedia article of extreme points on Earth. There’s no magic going on here, after some online research, we manually created a GeoJSON file with the points and loaded it in our app as a GeoJSONLayer. For this globe we need some symbols that stand out, so we created a PointSymbol3D with two IconSymbol3DLayers representing concentric circles. When clicking on an icon a popup shows up, displaying the information stored in the GeoJSON file. We docked the popup in the upper right corner and we applied some custom CSS to style it.

step 6 - globe
Globe after step 6

Step 7: where we create the Intro page✨

See the code

As an “Intro” page we want to have a message that tells the user what the app is about. The globe shouldn’t be too distracting, so we’re going to blur the globe using a css filter while the intro message is displayed. Once the user clicks on Go to globe the globe starts spinning to show the user that they can interact with it.

In this step we’ll also add an “About” page (which is technically the same as the “Intro” page with different content) to give the user more information about the data and the tools that were used to build this app.

step 7 - globe
Globe after step 7

And that’s all there is to it! Have fun exploring our globe and we look forward to see what it inspired you to build!

About the author

Raluca is a cartographer with a focus on 3D web cartography. She works as a Product Engineer for ArcGIS API for JavaScript #3D, making demos, writing documentation and testing.

Connect:

Next Article

Simplify weather measurements in the field using Arcade

Read this article