Creating an app for mountain biking using Mapbox in React

Creating an app for mountain biking using Mapbox in React

I decided to start a project about two years ago I wanted to create a map for mountain biking in my local area. During my youth, I used to bike and walk on trails. I created an app that shows me parks with mountain biking trails. I used Mapbox again since I wanted to learn more about it after using it for a hackathon in 2020. It was my first time using GIS and I enjoyed it.

Finding the dataset

I used a state dataset, I found several sites with datasets. As a note, this will depend on the website and the state you decided to use for this project. Alternatively, you can use national data that covers the entire country rather than a specific state. I downloaded the JSON file to use.

Getting started with Mapbox API

First, I created a Mapbox account and an access token. After that, I went to their docs and followed the tutorials in these order. I created a custom style and had custom markers I made in Inkscape, but this is optional.

  1. Create a Mapbox account and create an access token
  2. Load data for the map
  3. Create a custom map style (optional)
  4. Add interactivity

To create the map there are two main steps, load the data and add interactivity.

Getting the basics done with JavaScript and React

To start with the application I created a test example using vanilla javascript. Mapbox has a few tutorials on how to use the Mapbox API. After testing the demo using regular javascript I decided to move on creating the react app. Mapbox's tutorial for React is a good start.

Hide access token

As good practice, hide your access token from being public. I created a .env file to store the Mapbox access token and placed it in the .gitignore.

App.js

import React, { useRef, useEffect} from 'react';
import ReactDOM from "react-dom"
import mapboxgl from "mapbox-gl"; // eslint-disable-line import/no-webpack-loader-syntax

import "./App.css"

mapboxgl.accessToken = process.env.REACT_APP_MAPBOX_ACCESS_TOKEN;


const App = () => {
  const mapContainerRef = useRef();
 
  // initialize map when component mounts
  useEffect(() => {
    const map = new mapboxgl.Map({
      container: mapContainerRef.current,
      style: 'style or custom style',
      center: [lng, lat],
      zoom: zoom
    })

    // add navigation control (the +/- zoom buttons)
    map.addControl(new mapboxgl.NavigationControl(), 'bottom-right');


        // load GeoJSON data
        var geojson = {
        //load your dataset
          }
          

    //load in the data using arrow functions
    map.on("load", () => {
     
    // adding the layer 
    map.addLayer({
      'id': 'map id',
      'type': 'symbol',
      'source': 'locations',
      'layout': {
      'icon-image': '{icon}',
      'icon-allow-overlap': true
      },
    })
      })


// add markers to map
geojson.features.forEach(function(marker) {

  // create a HTML element for each feature
  var el = document.createElement('div');
  el.className = 'marker';
  
  // make a marker for each feature and add to the map
  new mapboxgl.Marker(el)
  .setLngLat(marker.geometry.coordinates)
  .setPopup(
  new mapboxgl.Popup({ offset: 25 }) // add popups
  .setText(
  
  marker.properties.Title +
  
   ' | '  +
  
  marker.properties.Address +
  
  ' | ' +
  
    marker.properties.City +
  
    ' | ' +
  
    marker.properties.ZIPCode 
  )
  )
  .addTo(map);
  });


 // cleanup function to remove map on unmount
 return () => map.remove()
}, [])
    

  return <div ref={mapContainerRef} style={{ width: "100%", height: "100vh" }} />;
};


export default App;

App.css

.App {
  text-align: center;
}

.map-container {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}


#map { position: absolute; top: 0; bottom: 0; width: 100%; }
.marker {
background-image: url('customIcon.svg');
background-size: cover;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
.mapboxgl-popup {
max-width: 200px;
}

.mapboxgl-popup-content {
text-align: center;
font-family: 'Open Sans', sans-serif;
}

Gitlab Repo

Resources

Mapbox API tutorials

Subscribe to Coding Fatale

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe