Get started with the Isochrone API
This tutorial demonstrates how you can use the Mapbox Isochrone API, which uses Mapbox routing profiles and travel times, to create a web app that allows users to estimate how far they could travel by foot, bicycle, or car within a set amount of time.
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.
- Mapbox Isochrone API. The Isochrone API computes areas that are reachable within a specified amount of time from a location, and returns the reachable regions as contours of polygons or lines that you can display on a map.
- Mapbox Assembly. Assembly is an open source CSS framework you will use to style the user interface for your app.
- A text editor. Use the text editor of your choice for writing HTML, CSS, and JavaScript.
Using the Isochrone API
An Isochrone API request requires three parameters:
profile
: The Mapbox routingprofile
that the query should use. This can bewalking
for pedestrian and hiking travel times,cycling
for travel times by bicycle, ordriving
for travel times by car.coordinates
: A{longitude,latitude}
coordinate pair around which to center the isochrone lines.contours_minutes
: Times that describe the duration in minutes of the trip. This can be a comma-separated list of up to four times. The maximum duration is 60 minutes.
https://api.mapbox.com/isochrone/v1/mapbox/{profile}/{coordinates}.json?{contours_minutes}&access_token=YOUR_MAPBOX_ACCESS_TOKEN
The Isochrone API also accepts several optional parameters that can be used to customize the query. For this app, you will be using one optional parameter:
polygons
: This parameter specifies whether to return the contours as GeoJSON polygons or linestrings. Whenpolygons=true
, any contour that forms a ring is returned as a polygon.
To learn more about the Isochrone API and its other optional parameters, explore the Isochrone API documentation.
This example query uses the driving
routing profile, has a contours_minutes
of 15, and has the polygons
parameter set to true
:
https://api.mapbox.com/isochrone/v1/mapbox/driving/-117.17282,32.71204?contours_minutes=15&polygons=true&access_token=YOUR_MAPBOX_ACCESS_TOKEN
To see the JSON response to this query, you can paste it into your browser. The response's geometry
object contains an array of coordinates
that describe the outlines of the isochrone contour. The response also contains a features
object that describes styling rules for drawing the polygon, including its fill color and fill opacity. You will use the information returned by the Isochrone API to draw and style the contours of the returned isochrone to the app's map.
Create a map
To start the app, you will create a map using Mapbox GL JS.
- Open your text editor.
- 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>Get started with the Isochrone API</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
{/* Import Mapbox GL JS */}
<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"
/>
{/* Import Assembly */}
<link
href="https://api.mapbox.com/mapbox-assembly/v1.3.0/assembly.min.css"
rel="stylesheet"
/>
<script src="https://api.mapbox.com/mapbox-assembly/v1.3.0/assembly.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
{/* Create a container for the map */}
<div id="map"></div>
<script>
// Add your Mapbox access token
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN ';
const map = new mapboxgl.Map({
container: 'map', // Specify the container ID
style:
'mapbox://styles/mapbox/streets-v12', // Specify which map style to use
center: [-77.0369, 38.895], // Specify the starting position
zoom: 11.5 // Specify the starting zoom
});
</script>
</body>
</html>
This code creates the structure of the page. It also imports Mapbox GL JS and Assembly in the <head>
of the page. The Mapbox GL JS JavaScript and CSS files allow you to use Mapbox GL JS functionality and map style, and the Assembly CSS framework allows you to further refine the style of the non-map elements on the page.
There is 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 Mapbox headquarters in Washington D.C.
Add the sidebar
Next, add a sidebar to the web app that will allow users to select a transportation profile and time duration.
In the <body>
of your HTML, add a new <div>
. This <div>
holds the app's options and uses Assembly classes for styling.
The code for the form uses Assembly
classes. These classes provide CSS styling
for the specified elements. For example, applying the classes absolute fl my24 mx24 py24 px24 bg-gray-faint round
to the parent div
sets its position
to absolute
and floats it to the left, gives it margin and padding of 24
pixels, sets the background to a light gray, and adds a border radius to round
the corners. In your own app, you could also use plain CSS or the CSS
framework of your choice to style the sidebar and the buttons instead of using
Assembly.
<div class="absolute fl my24 mx24 py24 px24 bg-gray-faint round">
<form id="params">
<h4 class="txt-m txt-bold mb6">Choose a travel mode:</h4>
<div class="mb12 mr12 toggle-group align-center">
<label class="toggle-container">
<input name="profile" type="radio" value="walking" />
<div class="toggle toggle--active-null toggle--null">Walking</div>
</label>
<label class="toggle-container">
<input name="profile" type="radio" value="cycling" checked />
<div class="toggle toggle--active-null toggle--null">Cycling</div>
</label>
<label class="toggle-container">
<input name="profile" type="radio" value="driving" />
<div class="toggle toggle--active-null toggle--null">Driving</div>
</label>
</div>
<h4 class="txt-m txt-bold mb6">Choose a maximum duration:</h4>
<div class="mb12 mr12 toggle-group align-center">
<label class="toggle-container">
<input name="duration" type="radio" value="10" checked />
<div class="toggle toggle--active-null toggle--null">10 min</div>
</label>
<label class="toggle-container">
<input name="duration" type="radio" value="20" />
<div class="toggle toggle--active-null toggle--null">20 min</div>
</label>
<label class="toggle-container">
<input name="duration" type="radio" value="30" />
<div class="toggle toggle--active-null toggle--null">30 min</div>
</label>
</div>
</form>
</div>
This code and the Assembly classes applied to it create a sidebar that contains toggle buttons that users will be able to select their desired mode of transportation (walking, cycling, or driving) and the amount of time to spend (10, 20, or 30 minutes).
Save your work and refresh the page. The sidebar will display on the left side of the page. While it looks good, clicking the buttons doesn't do anything — yet. In the next step, you will add a call to the Isochrone API, which you will be able to hook up to the user interface to create an interactive app.
Add the Isochrone API
To integrate the Isochrone API into your app, you will write a new function, getIso
, that will construct the query string and will use fetch to make the Isochrone API call. Add the following code to your JavaScript, after the map
constant that you used to initialize the map:
// Create constants to use in getIso()
const urlBase = 'https://api.mapbox.com/isochrone/v1/mapbox/';
const lon = -77.034;
const lat = 38.899;
const profile = 'cycling'; // Set the default routing profile
const minutes = 10; // Set the default duration
// Create a function that sets up the Isochrone API query then makes an fetch call
async function getIso() {
const query = await fetch(
`${urlBase}${profile}/${lon},${lat}?contours_minutes=${minutes}&polygons=true&access_token=${mapboxgl.accessToken}`,
{ method: 'GET' }
);
const data = await query.json();
console.log(data);
}
// Call the getIso function
// You will remove this later - it's just here so you can see the console.log results in this step
getIso();
Since you have not set up the layers yet that will draw the isochrone contour described in the response to the map, this code prints the results of the query to the console. Save your work and refresh the page, and open your browser's developer tools panel. You will see the Isochrone API response object printed out to the console.
Draw the isochrone contour
In the last step, you created a console.log
statement to view the API response. But for this app, you want to show the isochrone contours on the map! To do this in Mapbox GL JS, you need to set up a new source and a new layer. Learn more about the addSource
and addLayer
methods in the Mapbox GL JS documentation.
Remove the getIso();
call from the bottom of your JavaScript. Replace it with the following code:
map.on('load', () => {
// When the map loads, add the source and layer
map.addSource('iso', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: []
}
});
map.addLayer(
{
id: 'isoLayer',
type: 'fill',
// Use "iso" as the data source for this layer
source: 'iso',
layout: {},
paint: {
// The fill color for the layer is set to a light purple
'fill-color': '#5a3fc0',
'fill-opacity': 0.3
}
},
'poi-label'
);
// Make the API call
getIso();
});
Next, swap the console.log(data)
statement in the getIso
function with the following code, which will set the iso
source to the data returned by the API call:
// Set the 'iso' source's data to what's returned by the API query
map.getSource('iso').setData(data);
Save your changes and refresh the page in your browser. An isochrone contour for the hardcoded parameters (the cycling
routing profile and a trip duration of 10 minutes) is added to the map.
Make the app interactive
Now, you need to hook the buttons that you created earlier up to your JavaScript so that users can change the routing profile and the trip duration and see the results displayed on the map. Add the following code to the bottom of your JavaScript, before the closing </script>
tag:
// Target the "params" form in the HTML portion of your code
const params = document.getElementById('params');
// When a user changes the value of profile or duration by clicking a button, change the parameter's value and make the API query again
params.addEventListener('change', (event) => {
if (event.target.name === 'profile') {
profile = event.target.value;
} else if (event.target.name === 'duration') {
minutes = event.target.value;
}
getIso();
});
Now, when you click the buttons to change the routing profile or the trip duration, the event listener sets the parameter in the query to the new value and runs the getIso
function again. This in turn redraws the new isochrone contours to the map.
Save your changes and refresh the page in your browser. Click on different combinations of routing profiles and trip durations to see the isochrone contour change.
Add a marker
As the last step, you will add a marker to your map at the coordinates of the query to make the center of the isochrone contour more distinct. In this case, the coordinates used represent the location of the Mapbox office in Washington D.C.
Add the following code to your JavaScript, before the map.on('load')
function:
const marker = new mapboxgl.Marker({
color: '#314ccd'
});
// Create a LngLat object to use in the marker initialization
// https://docs.mapbox.com/mapbox-gl-js/api/#lnglat
const lngLat = {
lon: lon,
lat: lat
};
To draw the marker on the map when the map loads, add the following code inside of your map.on('load')
function:
// Initialize the marker at the query coordinates
marker.setLngLat(lngLat).addTo(map);
Now, when you save your work and refresh the page, you will see a blue marker at the specified coordinates.
Final product
You have created an app that uses the Mapbox Isochrone API to visualize how far a person could walk, bike, or drive within a given amount of time.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Demo: Get started with the Isochrone API</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Mapbox GL JS -->
<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"
/>
<!-- Mapbox Assembly -->
<link
href="https://api.mapbox.com/mapbox-assembly/v1.3.0/assembly.min.css"
rel="stylesheet"
/>
<script src="https://api.mapbox.com/mapbox-assembly/v1.3.0/assembly.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="absolute fl my24 mx24 py24 px24 bg-gray-faint round">
<form id="params">
<h4 class="txt-m txt-bold mb6">Choose a travel mode:</h4>
<div class="mb12 mr12 toggle-group align-center">
<label class="toggle-container">
<input name="profile" type="radio" value="walking" />
<div class="toggle toggle--active-null toggle--null">Walking</div>
</label>
<label class="toggle-container">
<input name="profile" type="radio" value="cycling" checked />
<div class="toggle toggle--active-null toggle--null">Cycling</div>
</label>
<label class="toggle-container">
<input name="profile" type="radio" value="driving" />
<div class="toggle toggle--active-null toggle--null">Driving</div>
</label>
</div>
<h4 class="txt-m txt-bold mb6">Choose a maximum duration:</h4>
<div class="mb12 mr12 toggle-group align-center">
<label class="toggle-container">
<input name="duration" type="radio" value="10" checked />
<div class="toggle toggle--active-null toggle--null">10 min</div>
</label>
<label class="toggle-container">
<input name="duration" type="radio" value="20" />
<div class="toggle toggle--active-null toggle--null">20 min</div>
</label>
<label class="toggle-container">
<input name="duration" type="radio" value="30" />
<div class="toggle toggle--active-null toggle--null">30 min</div>
</label>
</div>
</form>
</div>
<script>
mapboxgl.accessToken = '{{MAPBOX_ACCESS_TOKEN}}';
const map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v12', // stylesheet
center: [-77.0369, 38.895], // starting position [lng, lat]
zoom: 11.5 // starting zoom
});
// Target the params form in the HTML
const params = document.getElementById('params');
// Create variables to use in getIso()
const urlBase = 'https://api.mapbox.com/isochrone/v1/mapbox/';
const lon = -77.034;
const lat = 38.899;
let profile = 'cycling';
let minutes = 10;
// Set up a marker that you can use to show the query's coordinates
const marker = new mapboxgl.Marker({
'color': '#314ccd'
});
// Create a LngLat object to use in the marker initialization
// https://docs.mapbox.com/mapbox-gl-js/api/#lnglat
const lngLat = {
lon: lon,
lat: lat
};
// Create a function that sets up the Isochrone API query then makes a fetch call
async function getIso() {
const query = await fetch(
`${urlBase}${profile}/${lon},${lat}?contours_minutes=${minutes}&polygons=true&access_token=${mapboxgl.accessToken}`,
{ method: 'GET' }
);
const data = await query.json();
// Set the 'iso' source's data to what's returned by the API query
map.getSource('iso').setData(data);
}
// When a user changes the value of profile or duration by clicking a button, change the parameter's value and make the API query again
params.addEventListener('change', (event) => {
if (event.target.name === 'profile') {
profile = event.target.value;
} else if (event.target.name === 'duration') {
minutes = event.target.value;
}
getIso();
});
map.on('load', () => {
// When the map loads, add the source and layer
map.addSource('iso', {
type: 'geojson',
data: {
'type': 'FeatureCollection',
'features': []
}
});
map.addLayer(
{
'id': 'isoLayer',
'type': 'fill',
'source': 'iso',
'layout': {},
'paint': {
'fill-color': '#5a3fc0',
'fill-opacity': 0.3
}
},
'poi-label'
);
// Initialize the marker at the query coordinates
marker.setLngLat(lngLat).addTo(map);
// Make the API call
getIso();
});
</script>
</body>
</html>
Next steps
To build on top of the tools and techniques you used in this tutorial, explore the following resources:
- Learn more about how you can use the Isochrone API's optional parameters to influence what gets returned in the response object in the Isochrone API documentation.
- Learn more about adding layers to a map using Mapbox GL JS in the Add a GeoJSON line example and in the
addLayer
documentation.