How to Create a Summer Road Trip Mapping App with Gatsby and Leaflet

Summer is the perfect time to hit the open road and explore new destinations. But planning a multi-stop road trip can get overwhelming trying to visualize the route and all the places you want to visit. That‘s where an interactive mapping app can help!

In this step-by-step tutorial, we‘ll learn how to combine the powers of Gatsby and Leaflet to build a web app that showcases a summer road trip route. You‘ll be able to plot the path between stops, add markers for each location, and create custom popups with images and information about what you‘ll do at each stop.

By the end, you‘ll have a working prototype you can adapt for your own summer adventure or mapping project. Let‘s get mapping!

Prerequisites

Before we jump into the code, make sure you have the following set up:

  • Node.js installed on your computer
  • A code editor like VS Code
  • Basic familiarity with React and Git

You‘ll also need the Gatsby CLI to create a new project. Install it globally with:

npm install -g gatsby-cli

Setting up a new Gatsby project

With the setup out of the way, let‘s scaffold a new Gatsby app. In your terminal, navigate to the directory where you want to create the project and run:

gatsby new summer-road-trip-map

This will generate a new directory called summer-road-trip-map with the basic file structure for a Gatsby app. Move into the directory and start the local development server:

cd summer-road-trip-map
gatsby develop

In your browser, navigate to http://localhost:8000 and you should see the default Gatsby starter page.

Importing Leaflet

Leaflet is a lightweight open-source library for building interactive maps. To use it in our Gatsby app, we first need to install the necessary dependencies.

Stop the development server (ctrl + c) and run:

npm install leaflet gatsby-plugin-react-leaflet

leaflet is the core library, while gatsby-plugin-react-leaflet makes it easier to integrate with Gatsby‘s build process.

Next, add the Leaflet CSS file to gatsby-browser.js in the root of your project:

import "./node_modules/leaflet/dist/leaflet.css"

And finally, to tell Gatsby to use the Leaflet plugin, add it to the plugins array in gatsby-config.js:

module.exports = {
  plugins: [
    ‘gatsby-plugin-react-leaflet‘
  ]
}

Now we‘re ready to start mapping!

Preparing the map data

Before we can draw our route, we need some data to tell Leaflet what points to map. Create a new file at src/data/locations.js and add the following:

export const locations = [
  {
    id: 1,
    name: "Yosemite Valley",
    coordinates: [37.865101, -119.538329],
    description: "Explore granite cliffs, waterfalls, and sequoia groves.",
    image: "https://images.unsplash.com/photo-1589810635657-232948472d98?w=600&h=400&fit=crop"
  },
  {
    id: 2,  
    name: "Tuolumne Meadows",
    coordinates: [37.873779, -119.358336],
    description: "Enjoy subalpine meadows, starry skies and rugged peaks.",
    image: "https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=600&h=400&fit=crop"
  },
  {
    id: 3,
    name: "Death Valley",
    coordinates: [36.507389, -117.079408], 
    description: "Discover exotic landscapes in this below-sea-level basin.",
    image: "https://images.unsplash.com/photo-1545165375-b61286d1a2a6?w=600&h=400&fit=crop"
  },
  {
    id: 4,
    name: "Ancient Bristlecone Pine Forest",
    coordinates: [37.566112, -118.172280],   
    description: "Gaze at the world‘s oldest trees, some nearly 5000 years old.",
    image: "https://images.unsplash.com/photo-1617328587655-c3ed75e29b4a?w=600&h=400&fit=crop"
  },
  {
    id: 5,
    name: "Alabama Hills",
    coordinates: [36.606941, -118.113755],
    description: "Camp and sightsee amongst rusty-hued granite boulders.",
    image: "https://images.unsplash.com/photo-1600521465632-e1de2bbc19da?w=600&h=400&fit=crop"  
  },
  {
    id: 6,
    name: "Sequoia & Kings Canyon",
    coordinates: [36.787010, -118.775558],
    description: "Marvel at the largest trees in the world.",
    image: "https://images.unsplash.com/photo-1585077145761-0aa2754f1e4e?w=600&h=400&fit=crop"
  }
]

This represents the stops on a hypothetical road trip through California‘s Sierra Nevada mountains. Each location has:

  • A unique id
  • name of the stop
  • coordinates in [latitude, longitude] format
  • Short description of what you can do there
  • image URL to show in the popup (I‘m using landscape images from Unsplash)

Feel free to customize this data for your own trip. Just make sure to keep the same object shape for each location.

Rendering the map

With our location data ready, let‘s plot it on a map! Create a new file at src/pages/index.js and add this code:

import * as React from ‘react‘
import { MapContainer, TileLayer } from ‘react-leaflet‘
import { locations } from ‘../data/locations‘
import Markers from ‘../components/Markers‘
import Route from ‘../components/Route‘

const MAPBOX_API_KEY = ‘YOUR MAPBOX API KEY‘;
const MAPBOX_USERID = ‘YOUR MAPBOX USERNAME‘;
const MAPBOX_STYLEID = ‘YOUR MAPBOX STYLE ID‘; 

const IndexPage = () => {

  return (
    <div className="container">
      <MapContainer 
        center={[37.8283, -119.5795]} 
        zoom={6} 
        scrollWheelZoom={false}
      >
        <TileLayer
          url={`https://api.mapbox.com/styles/v1/${MAPBOX_USERID}/${MAPBOX_STYLEID}/tiles/256/{z}/{x}/{y}@2x?access_token=${MAPBOX_API_KEY}`}
          attribution="Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>"
        />
        <Markers locations={locations} /> 
        <Route locations={locations} />
      </MapContainer>  
    </div>
  )
}

export default IndexPage;

Let‘s break this down:

  • First we import the locations data and the Markers and Route components we‘ll create next.

  • For the base map layer, I‘m using a custom Mapbox tile set. For this you‘ll need a free Mapbox account. Replace MAPBOX_API_KEY, MAPBOX_USERID, and MAPBOX_STYLEID with your own credentials.

  • The MapContainer component initializes the map, centered over the Sierra Nevada mountains at a zoom level suitable for our route. Inside MapContainer we have:

    • TileLayer loads the base map tiles from Mapbox
    • Markers will render a marker at each stop
    • Route will draw lines connecting the stops

Let‘s implement those two components now. First create a new file at src/components/Markers.js:

import * as React from ‘react‘
import { Marker, Popup } from ‘react-leaflet‘;
import { divIcon } from ‘leaflet‘;
import ‘leaflet/dist/leaflet.css‘;

const customMarkerIcon = divIcon({
  className: ‘marker‘,
  iconSize: [30, 30], 
  iconAnchor: [15, 30],
  popupAnchor: [0, -20]
});

const Markers = ({ locations }) => {

  return (
    <>
      {locations.map(location => (
        <Marker 
          key={location.id} 
          position={location.coordinates} 
          icon={customMarkerIcon}
        >
          <Popup>
            <div className="popup-container">
              <img src={location.image} alt={location.name} />
              <div className="popup-text">  
                <h2>{location.name}</h2>
                <p>{location.description}</p>
              </div>
            </div>  
          </Popup>
        </Marker>
      ))}
    </>
  );
};

export default Markers;

For each location, this component renders a Marker at the given coordinates. The Popup contains the location name, description, and image.

I‘m also using a custom divIcon for the marker symbols instead of Leaflet‘s default.

Now let‘s add the route lines in src/components/Route.js:

import { useEffect } from ‘react‘;  
import L from ‘leaflet‘;
import ‘leaflet-routing-machine‘;
import ‘leaflet-routing-machine/dist/leaflet-routing-machine.css‘;

const Route = ({ locations = [], map }) => {  

  useEffect(() => {
    if (!map) return;

    const routingControl = L.Routing.control({
      waypoints: locations.map((loc) => L.latLng(loc.coordinates)),
      lineOptions: {
        styles: [
          {
            color: ‘black‘,
            opacity: 0.5,
            weight: 4
          }
        ]  
      },
      addWaypoints: false,
      draggableWaypoints: false,
      fitSelectedRoutes: true,
      showAlternatives: false,
    }).addTo(map.leafletElement);

    return () => map.leafletElement.removeControl(routingControl);
  }, [map, locations]);

  return null;
};

export default Route;

This component uses the Leaflet Routing Machine plugin to calculate and draw the route lines based on the location coordinates.

The useEffect hook adds the route to the map when the component mounts and removes it on unmount. This ensures the route updates if the locations or map changes.

Styling with CSS

To polish off the design, add the following CSS to src/pages/index.css:

.container {
  height: 100vh;
}

.leaflet-container {
  width: 100%;
  height: 100%;
}

.marker {
  background-color: #fff;
  border: 2px solid #6fce72;
  border-radius: 50%;
  cursor: pointer;
}

.popup-container {
  width: 300px;
  text-align: center; 
}

.popup-container img {
  width: 100%;
  height: auto;
  margin-bottom: 0.5rem;
}

.popup-text h2 {
  font-size: 1.2rem;
  margin-bottom: 0.5rem;
}

.popup-text p {
  font-size: 1rem;
  margin-bottom: 0;  
}

This styles the map to fill the window, centers the popup content, and makes the custom markers white circles with a green border.

And with that, our Summer Road Trip Mapping App is complete! To see it in action, start the development server again with gatsby develop and open http://localhost:8000 in your browser.

Next Steps

There are many ways you could expand on this starter app:

  • Add more locations and details to each stop
  • Customize the map style further in Mapbox Studio
  • Make the route editable by adding/removing stops
  • Use Gatsby‘s data layer to pull location content from Markdown files or a CMS
  • Allow the user to click on the map to add their own stops

I hope this tutorial has shown you the possibilities of combining Gatsby and Leaflet to create interactive mapping apps. With a little creativity and the power of open-source tools, you can bring your summer road trip plans to life!

Have any mapping projects of your own to share? Let me know in the comments. Happy coding, and safe travels!

Similar Posts