Howdy, I am Ben Tyler. I specialize in and developing aesthetic and functional websites and applications. I love collaborating on projects, so if you need to hire a developer or an adviser for a project, please get in touch!
Get in touch!Building a 3D React Map Component Using Mapbox
Date: 1/20/2021
Time to Read: 2 minutes
This post is part of my Building Interactive Maps with React course - a course for anyone wanting to learn how to build interactive maps and integrate them into their React applications. If you enjoy this guide, then chances are you will enjoy the course too!
Mapbox released GL JS V2 recently which has a whole slew of awesome features, but the one I am most excited is the addition of 3D terrain rendering. I have been waiting for this feature for a looooooooong time. A lot of the applications I build are focused on the outdoors and feature an interactive map. Just about every one of these apps would benefit greatly from the ability to render things in 3D. That is a now a reality!
The best part about the new release is just how easy it is to render 3D terrain. This post will walk you through how to create a React Map component with 3D terrain rendering. The process is more or less exactly what you would follow for creating any other Mapbox Gl JS map in React.
Before You Get Started
This guide assumes the following:
- you are adding this component to an existing React app. If you do not already have an app to add this too or are unsure of how to setup a React app, check out the React docs.
- you already have a Mapbox account and access token. You can sign up here
Installing Mapbox
To get started, let's install Mapbox.
1
2# yarn3yarn add mapbox-gl4
5# npm6npm install mapbox-gl --save7
8
Then make sure you include the GL JS CSS file in the <head>
of your html document. If you are using Create React App or a similarly structured app, add it to the <head>
of the index.html
file in the public
directory.
1<link2 href="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css"3 rel="stylesheet"4/>5
Developing the Map Component
The next several steps will walk you through how to create a dead simple Map component with 3D rendering enabled. Create a new component called Map
and then copy and paste the snippet below. This will render a simple interactive map.
1import React, { useRef, useEffect } from "react"2import mapboxgl from "mapbox-gl"3
4// Grab the access token from your Mapbox account5// I typically like to store sensitive things like this6// in a .env file7mapboxgl.accessToken = process.env.REACT_APP_MAPBOX_TOKEN8
9export const Map = () => {10 const mapContainer = useRef()11
12 // this is where all of our map logic is going to live13 // adding the empty dependency array ensures that the map14 // is only created once15 useEffect(() => {16 // create the map and configure it17 // check out the API reference for more options18 // https://docs.mapbox.com/mapbox-gl-js/api/map/19 const map = new mapboxgl.Map({20 container: "map",21 style: "mapbox://styles/mapbox/satellite-streets-v11",22 center: [-119.99959421984575, 38.619551620333496],23 zoom: 14,24 })25 }, [])26
27 return (28 <div29 id="map"30 ref={mapContainer}31 style={{ width: "100%", height: "100vh" }}32 />33 )34}35
Taking It All 3D
At this point you should have a basic 2D satellite streets map rendering successfully. Converting this rendering to 3D is a surprisingly small amount of work. We need to do the following:
- adjust the map pitch (aka the camera angle) so that we are not looking straight down at the map
- add the Mapbox DEM (digital elevation model) source to our map
First, we add the pitch
property to the map configuration. This value can be between 0 and 85. For this example, I personally prefer 60. And then lastly, we need to add a load event listener and define the logic for adding Mapbox's DEM tiles, generating the 3D terrain, and adding a sky layer for a nice touch.
That's it! If you revisit your app, you should not have a 3D rendering that resembles what you would see in Google Earth.
1import React, { useRef, useEffect } from "react"2import mapboxgl from "mapbox-gl"3
4// Grab the access token from your Mapbox account5// I typically like to store sensitive things like this6// in a .env file7mapboxgl.accessToken = process.env.REACT_APP_MAPBOX_TOKEN8
9export const Map = () => {10 const mapContainer = useRef()11
12 // this is where all of our map logic is going to live13 // adding the empty dependency array ensures that the map14 // is only created once15 useEffect(() => {16 // create the map and configure it17 // check out the API reference for more options18 // https://docs.mapbox.com/mapbox-gl-js/api/map/19 const map = new mapboxgl.Map({20 container: "map",21 style: "mapbox://styles/mapbox/satellite-streets-v11",22 center: [-119.99959421984575, 38.619551620333496],23 zoom: 14,24 pitch: 60,25 })26
27 map.on("load", () => {28 map.addSource("mapbox-dem", {29 type: "raster-dem",30 url: "mapbox://mapbox.mapbox-terrain-dem-v1",31 tileSize: 512,32 maxZoom: 16,33 })34 map.setTerrain({ source: "mapbox-dem", exaggeration: 1.5 })35 map.addLayer({36 id: "sky",37 type: "sky",38 paint: {39 "sky-type": "atmosphere",40 "sky-atmosphere-sun": [0.0, 90.0],41 "sky-atmosphere-sun-intensity": 15,42 },43 })44 })45 }, [])46
47 return (48 <div49 id="map"50 ref={mapContainer}51 style={{ width: "100%", height: "100vh" }}52 />53 )54}55
If you found thus post useful, give me a follow on Twitter or consider picking up a copy of the Building Interactive Maps with React course.