Some stories are best told with a map. Data journalists covering changing conditions in a population's demographics, the environment, an international conflict, or telling a simple travel story frequently provide geographic context in their graphics.
This template is designed to accelerate building out a "scrollytelling" map story. The primary input is a story broken into sections (chapters
), each hooked to a particular view of a map.
Optionally, you can input a custom Mapbox Style with layers styled in Studio and toggle the layer's opacity.
The output is an HTML and JavaScript file. These outputs can be hosted on any web-accessible location, with no extra code or infrastructure required. Note that embedding the output as an iFrame in another page will not work as expected. The scroll-driven interface requires the full page.
This template is for data journalists and digital storytellers of any kind. No coding experience is required. If you are planning to include some custom map layers, you will need some familiarity with Mapbox Studio.
To configure and publish a story, you will need:
-
A Mapbox access token. Sign up for a free account at mapbox.com to get one.
-
A text editor. Atom, Sublime Text, and Visual Studio Code are all fine choices.
-
A place to publish your work. Any service that hosts static files that can be accessed with a browser will do.
-
A story. This is unquestionably the hardest part. The best stories for this template will have sections that benefit from a map.
-
Attention to detail. The configuration file does require specific syntax and punctuation. Braces, brackets, commas, and quotes are important. Follow the
config.js.template
for guidance. Some familiarity with JSON is recommended. -
Optionally, some spatial data in your Mapbox map. The template has options to include layer names to show and hide the data as the story sections transition. You may want to highlight a neighborhood, or show satellite data from two different times.
The template does not rely on any particular CSS framework, fonts, or images. There are some basic styles in the head
of the HTML file that can be changed, so feel free to adapt and add to these to match your site and story brand.
-
Download this repository as a ZIP file using the button above, and unzip it. If you are using
git
, clone this repository. -
If you are new to coding in JavaScript, follow the instructions for Vanilla JS. If you are already working with React, are comfortable with the command line and build systems, and/or want bundled and minified code, choose React.
In your local copy of this repository (the unzipped file you downloaded), navigate to the src/vanilla-js/
directory.
Make a copy of config.js.template
and name it config.js
. Open the new config.js
file in your text editor.
-
Select the map style you want to use (the default is Mapbox Streets, but you can find more here https://docs.mapbox.com/api/maps/#styles, or use one of your custom Studio styles).
-
Add a Mapbox access token. A good practice is to create a separate token per map to be able to track traffic to your different maps.
-
Choose whether or not to display a marker at the center of each map location.
-
Choose a theme for the story text. There are
light
anddark
options. -
Choose where your story should be aligned over the map. Options are
center
,left
,right
.
{
style: 'mapbox://styles/mapbox/streets-v11',
accessToken: 'YOUR_ACCESS_TOKEN',
showMarkers: true,
alignment: 'left',
title: 'Story Title Goes Here',
subtitle: 'A subtitle going into more detail goes here',
byline: 'By a Digital Storyteller',
footer: 'Sources and citations, etc. live down at the bottom of the story',
chapters: [...]
}
- Add as many
chapters
in your template as needed. You'll need a,
between each section, but no comma at the end. Here is what achapter
looks like:
{
id: 'identifier',
title: 'Title',
image: './path/to/image/source.png',
description: 'Copy these sections to add to your story.',
location: {
center: [-77.020636, 38.886900],
zoom: 13.5,
pitch: 60,
bearing: -43.2
},
onChapterEnter: [],
onChapterExit: []
}
-
Fill out your sections as needed. Give each section a unique name in the section
id
property. This will become the HTMLdiv
id
, so avoid spaces in the name. Thetitle
,description
properties are optional. Thedescription
supports HTML tags. If you have an image that goes with that section of the story, add the path to the image in theimage
property. -
For
location
, you can use thehelper.html
file to help you determine the map's position. This tool prints the location settings of the map on the screen in a format ready for copy/paste into the template. -
Repeat until you have the location entered for each of your sections.
-
Open
index.html
in a browser, and scroll. Voila!
Using the helper.html
file, you can search for places, zoom, pan, tilt, and rotate the map to get the desired map position (Hint: To tilt and rotate the map, right-click and drag the map).
Notice the location parameters are updated in the upper left corner with everytime you move the map. You can copy the location definition from that page into the config.js
location
property section.
There is also a hosted version of this file at https://demos.mapbox.com/location-helper/
Here is a sample configuration:
var config = {
style: 'mapbox://styles/branigan/cjz37rcb003ib1cr3s8rnkt2d',
accessToken: 'pk.eyJ1IjoibWJ4c29sdXRpb25zIiwiYSI6ImNrMm01aG9hdTBlZGwzbXQ1ZXVrNHNmejAifQ.QHQA0N6XPWddCXtvoODHZg',
showMarkers: false,
theme: 'light',
alignment: 'center',
title: 'Glaciers of Glacier National Park',
subtitle: 'Change in coverage from 1998 to 2015',
byline: '',
footer: 'Story copy from Wikipedia, map data from USGS',
chapters: [
{
id: 'glacier-np',
title: 'Glacier National Park Glaciers',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/2015-06-19_Glacier_National_Park_%28U.S.%29_8633.jpg/800px-2015-06-19_Glacier_National_Park_%28U.S.%29_8633.jpg',
description: 'Glacier National Park is dominated by mountains which were carved into their present shapes by the huge glaciers of the last ice age. These glaciers have largely disappeared over the last 12,000 years. Evidence of widespread glacial action is found throughout the park in the form of U-shaped valleys, cirques, arêtes, and large outflow lakes radiating like fingers from the base of the highest peaks.',
location: {
center: [-113.91666, 48.66451],
zoom: 8,
pitch: 0.00,
bearing: 0.00
},
onChapterEnter: [
{
layer: 'gnpglaciers-1998',
opacity: 0.25
},
{
layer: 'glaciernp-boundary',
opacity: 0.25
}
],
onChapterExit: [
{
layer: 'gnpglaciers-1998',
opacity: 0.25
},
{
layer: 'glaciernp-boundary',
opacity: 0
}
]
},
{
id: 'harrison1998',
title: 'Harrison Glacier, 1998',
image: '',
description: 'Harrison Glacier is located in the US state of Montana in Glacier National Park. Situated on a southeast facing ridge immediately south of Mount Jackson, Harrison Glacier is the largest glacier in Glacier National Park.',
location: {
center: [-113.72917, 48.58938],
zoom: 12.92,
pitch: 39.50,
bearing: 36.00
},
onChapterEnter: [],
onChapterExit: []
}
]
}
Note: items in bold are required.
style
: This is the Mapbox style url
to use for the app. It can be a standard style, or a custom style from your Mapbox account. Use a custom style if you want to include custom data or layers.
accessToken
: Your Mapbox access token.
showMarkers
: This controls whether markers are shown at the centerpoint of each chapter. If true
, the map will display a default blue, inverted-teardrop icon.
theme
: Two basic themes (light and dark) are available.
alignment
: This defines where the story text should appear over the map. Options are center
, left
, and right
. When the browser window is less than 750 pixels wide, the story will be center
aligned.
title
: The title of the overall story. (Optional)
subtitle
: A subtitle for the story. (Optional)
byline
: Credit the author of the story. (Optional)
footer
: Citations, credits, etc. that will be displayed at the bottom of the story.
chapters
: This contains all of the story content and map controls for each section of the story. Array of objects
id
: A slug-style ID for the chapter. This is read by the JavaScript driving the app and is assigned as an HTMLid
for thediv
element containing the rest of the story. A best-practice format would be to use kebab case, likemy-story-chapter-1
.title
: The title of the section, displayed in anh3
element.image
: The path to an image to display in this section.description
: The main story content for the section. This should be aligned with what the reader is seeing on the map. In the vanilla version, this field will render as HTML. Images, links, and other items can be included as HTML.location
: Details about the map display and camera view.center
: Center coordinates of the map, aslongitude, latitude
zoom
: Zoom level of the map.pitch
: Angle of the map view.0
is straight down, and60
is highly tilted.bearing
: Degrees of rotation clockwise from North (0
). Negative values represent counter-clockwise rotation.
onChapterEnter
: Layers to be displayed/hidden/muted when the section becomes active. Array of objectslayer
: Layer name as assigned in Mapbox Studio.opacity
: The opacity to display the layer.0
is fully transparent,1
is fully opaque.
onChapterExit
: Same asonChapterEnter
except it is triggered when the section becomes inactive. Array of objects
Add and style each custom layer in your Studio style. Before the final publish, set any layers's style to be hidden with 0
opacity. Do not hide the layer. For example, if you have a circle
layer, makes sure the color-opacity
and/or the stroke-opacity
is set to 0.
This will ensure that the map appears correctly when the story page loads. To adjust the opacity of the layers as the reader scrolls through the story, use the onChapterEnter
or onChapterExit
configuration options to set your desired opacity for the layer.
The output of the React version of this template is functionally identical to the vanilla version. Use this version if you prefer to use React to build and deploy your story.
This application was built and tested using
- Node version 10.16.3
- NPM version 6.9.0
In your local copy of this repository, navigate to the src/react-js/
directory.
Install dependencies listed in the package.json
file:
yarn install
Run the development server:
yarn start
Follow the instructions above for setting up your configuration file and building out your story. Once the application is ready for deployment, run:
yarn build
This command will generate a build
directory that contains everything you will need to deploy your story. As with the vanilla JavaScript version, you will only need a deployment location capable of hosting static files.
src
: Source code directoryreact-js
: Code for the React version of the templatevanilla-js
: Code for the vanilla version of the template
example
: Example storiesglacier
: Glaciers of Glacier National Park exampleglacier-react
: React version of the abovebike-philly
: Philadelphia bicycle infrastructure example
For the Vanilla
version, host the index.html
and config.js
files in the same directory in a web-accessible location. For the React
version, copy the contents of the build
directory to a web-accessible location.
- Mapbox GL JS
- Scrollama.js
- React
John Branigan on the Mapbox Solutions Architecture Team
BSD 3-Clause License
- Lo Bénichou for the idea, support, and awesome feedback throughout the design and build process
- Paige Moody and Lem Thornton for early testing and feedback
- Chris Toomey for ushering this work through and keeping things on track
- Journalists with stories that help us make sense of what goes around us