Create interactive hover effects with Mapbox GL JS
In this tutorial, you will create a map that shows the locations of earthquakes that have happened in the last week. You will use Mapbox GL JS to create the map and visualize the data, then you will use expressions to style each earthquake feature according to the magnitude of the earthquake. Finally, you will use feature state to apply these styles to the earthquake features when a user mouses over the feature and remove them when a user mouses away.
Getting started
To complete this tutorial, you will need:
- A Mapbox access token. Your Mapbox access tokens are on your Account page.
- Mapbox GL JS. Mapbox GL JS is a JavaScript API for building web maps.
- A text editor. Use the text editor of your choice for writing HTML, CSS, and JavaScript.
- The USGS Earthquake Catalog API. You will use the USGS Earthquake Catalog API to retrieve information about all earthquakes with a magnitude of one or more that have happened within the past week.
Feature state and expressions
Feature state is a set of user-defined attributes that can be dynamically assigned to a feature on the map. You can use feature state with expressions to style the features of a vector or GeoJSON source in either a dataset or tileset. Each feature in the source must have a unique numeric id
for feature state to work correctly. If you are adding a GeoJSON source at runtime, which is what you will do in this tutorial, you can use the generateId
option in map.addSource()
to add an id
to each feature. For vector sources or GeoJSON sources that are added before runtime, you must set a unique id
for each feature before the source is added to the map.
You can think of feature state as a switch that turns a fan on or off. You will use feature state to define what the switch is, and expressions to set the style. In this case, the trigger is a user mousing over or away from a feature, which will update the style of the feature based on the rules set by the expressions.
With feature state, you can update the styling of a map layer's individual features based on user interaction, without needing to re-render the underlying geometry and data after each interaction event.
In this tutorial, the feature state trigger will be a user's mouse hovering over an earthquake feature, and you will use feature state to update the radius size and the color of the feature based on its magnitude value.
Create a map
To get started, you will create a map using Mapbox GL JS. Open your text editor and create a new file named index.html
. Set up this new HTML file by pasting the following code into your text editor:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Create interactive hover effects with Mapbox GL JS</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js"></script>
<link
href="https://api.tiles.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css"
rel="stylesheet"
/>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN ';
const map = new mapboxgl.Map({
container: 'map', // Specify the container ID
style:
'mapbox://styles/mapbox/outdoors-v12', // Specify which map style to use
center: [-122.44121, 37.76132], // Specify the starting position [lng, lat]
zoom: 3.5 // Specify the starting zoom
});
</script>
</body>
</html>
This code creates the structure of the page. It imports Mapbox GL JS in the <head>
of the page, which allows you to use Mapbox GL JS functionality and style in your web app.
This code contains a <div>
element with the ID map
in the <body>
of the page. This <div>
is the container in which the map will be displayed on the page.
Save your changes. Open the HTML file in your browser to see the rendered map, which is centered on the western United States.
Add the sidebar
In the <body>
of your HTML, add a new <div>
. This <div>
will be used to display an individual earthquake's magnitude, location, and the time that it happened:
<div class="quake-info">
<div><strong>Magnitude:</strong> <span id="mag"></span></div>
<div><strong>Location:</strong> <span id="loc"></span></div>
<div><strong>Date:</strong> <span id="date"></span></div>
</div>
To style the new <div>
, add the following CSS to the <style>
section of your HTML:
.quake-info {
position: absolute;
font-family: sans-serif;
margin-top: 5px;
margin-left: 5px;
padding: 5px;
width: 30%;
border: 2px solid black;
font-size: 14px;
color: #222;
background-color: #fff;
border-radius: 3px;
}
Finally, create three new constants that you will use to target the new <span>
s using their IDs. Add the following code to your JavaScript, above the closing </script>
tag:
const magDisplay = document.getElementById('mag');
const locDisplay = document.getElementById('loc');
const dateDisplay = document.getElementById('date');
Save your work and refresh the page. The new sidebar will be on the left side of the page. In an upcoming step, you will use the <span>
s that you created to display the magnitude, location, and time of the earthquakes in the sidebar.
Add the earthquake source
The Mapbox GL JS addSource
instance lets you add a new data source to a map. In this case, you will use data from the USGS Earthquake Catalog API, which returns information about recent earthquakes, including the magnitude, location, and the time at which the earthquake happened.
By default, the Earthquake Catalog API returns all events from the prior 30 days. But for this web app, you will instead return events from the past seven days using the optional starttime
parameter. You will use the JavaScript Date
constructor to get the date seven days ago as an ISO 8601 timestamp, as required by the USGS Earthquake Catalog API. Add the following JavaScript to your file:
const today = new Date();
// Use JavaScript to get the date a week ago
const priorDate = new Date().setDate(today.getDate() - 7);
// Set that to an ISO8601 timestamp as required by the USGS earthquake API
const priorDateTs = new Date(priorDate);
const sevenDaysAgo = priorDateTs.toISOString();
You will use the sevenDaysAgo
constant in a call to the Earthquake Catalog API. (If you use a time-specific JavaScript library like Moment.js, getting the current date minus seven days will take fewer steps. This tutorial shows the implementation in plain JavaScript.)
For this web app, you will use the Earthquake Catalog API's optional format
parameter to return the data as GeoJSON. You will also restrict the results to earthquakes with a magnitude of one or higher by using the optional eventtype
and minmagnitude
parameters.
With these optional parameters, the USGS Earthquake Catalog API query will be:
"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&minmagnitude=1&starttime=" + sevenDaysAgo
To add results from a call to the Earthquake Catalog API to your app as a source, you will wrap addSource
inside a map.on('load')
function so that the new source is not loaded before the map is rendered. Add the following code to your JavaScript:
map.on('load', () => {
map.addSource('earthquakes', {
type: 'geojson',
data: `https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&minmagnitude=1&starttime=${sevenDaysAgo}`,
generateId: true // This ensures that all features have unique IDs
});
});
Feature state relies on each feature having a numeric id
that is unique
across the source or source layer.If you are using a GeoJSON source that is
generated at runtime, as with the results from the Earthquake Catalog API in
this tutorial, you can add an id
to each feature by setting the generateId
property in map.addSource()
to true
. This generates an id
for each
feature in the new source, based on the feature's index in the source data.The
generateId
method only works for GeoJSON sources that are added at runtime.
For tilesets, or for GeoJSON sources that are added before runtime, you must
set unique id
s for each feature before the source is added to the map.
In the next step, you will add a style layer that uses the source earthquakes
to the map.