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

Préparez-vous pour l'été en créant votre propre application de cartographie pour un road trip avec ce guide étape par étape !

Note de l'auteur : Même si nous traversons des moments difficiles, nous pouvons rester optimistes quant au fait que nous allons surmonter cela ensemble et pouvoir profiter de notre été. Restez en sécurité et lavez-vous les mains. ❤️

Qu'allons-nous construire ?

Nous allons parcourir la création d'une nouvelle application de cartographie qui montre un itinéraire représentant le voyage. Chaque lieu aura une petite carte où nous pourrons ajouter une photo et quelques choses que nous avons faites.

Image Le road trip d'été de Colbana

Pour commencer, nous allons utiliser ce Leaflet Gatsby Starter que j'ai créé pour rendre la configuration initiale un peu plus fluide. Avec notre application amorcée, nous créerons notre liste de lieux et utiliserons l'API de Leaflet pour tracer notre itinéraire sur la carte.

Woah, une application de cartographie ?

Oui. Si vous n'avez jamais joué avec des cartes auparavant, ne vous découragez pas ! Ce n'est pas aussi compliqué que vous le pensez probablement. Si vous préférez commencer par les bases de la cartographie, vous pouvez lire plus sur le fonctionnement de la cartographie d'abord.

Que devons-nous avoir avant de commencer ?

Si vous avez suivi mon dernier tutoriel pour construire un Santa Tracker, vous pouvez suivre les mêmes étapes pour commencer. Si ce n'est pas le cas, nous voulons nous assurer que nous avons les éléments suivants configurés :

  • node ou yarn - J'utiliserai yarn, mais vous pouvez substituer avec npm lorsque c'est approprié
  • CLI de Gatsby - yarn global add gatsby-cli

Si vous n'êtes pas sûr de l'un des éléments ci-dessus, vous pouvez essayer de consulter le début de mon tutoriel précédent.

Nous voulons également mettre en place une base pour notre carte. Nous pouvons le faire en utilisant le Leaflet Gatsby Starter que j'ai assemblé et qui nous fournit une configuration de base avec Leaflet et React Leaflet.

gatsby new my-road-trip https://github.com/colbyfayock/gatsby-starter-leaflet

Image Création d'une nouvelle application Leaflet Gatsby dans le terminal

Une fois que cela a fini de s'exécuter, vous pouvez naviguer vers le répertoire du projet nouvellement créé et démarrer votre serveur de développement local :

cd my-road-trip
yarn develop

Image Démarrage de votre application Gatsby dans le terminal

Si tout se passe comme prévu, votre serveur devrait démarrer et vous devriez maintenant pouvoir voir votre application de cartographie de base dans votre navigateur !

Image Nouvelle application Leaflet Gatsby dans le navigateur

Étape 1 : Nettoyer du code inutile

Le Gatsby Starter que nous utilisons pour lancer cette application contient du code de démonstration dont nous n'avons pas besoin ici. Nous voulons apporter toutes les modifications ci-dessous dans le fichier src/pages/index.js, qui est la page d'accueil de notre application.

Tout d'abord, supprimons tout le contenu de la fonction mapEffect. Cette fonction est utilisée pour exécuter du code qui se déclenche lorsque la carte est rendue.

// Dans src/pages/index.js

async function mapEffect({ leafletElement } = {}) {
  // Supprimez tout ce qui se trouve ici
}

Ensuite, nous ne voulons pas de marqueur cette fois, alors supprimons le composant <Marker de notre composant <Map :

<Map {2026mapSettings} />

Maintenant que nous avons supprimé ces éléments, nous pouvons supprimer toutes les importations et variables suivantes du haut de notre fichier :

  • useRef
  • Marker
  • promiseToFlyTo
  • getCurrentLocation
  • gatsby_astronaut
  • timeToZoom
  • timeToOpenPopupAfterZoom
  • timeToUpdatePopupAfterZoom
  • ZOOM
  • popupContentHello
  • popupContentGatsby
  • markerRef

Après cela, notre carte devrait toujours fonctionner, mais ne rien faire.

Image Nouvelle application de cartographie sans rien de spécial

Suivez avec le commit

Étape 2 : Créer nos lieux de road trip

Cette étape consistera à préparer nos données de localisation qui alimenteront notre application de road trip. Nos lieux incluront des propriétés telles qu'un nom, une date, des choses que nous avons faites et une photo si nous le souhaitons.

Tout d'abord, créez un nouveau fichier dans le répertoire src/data appelé locations.js. À l'intérieur de ce fichier, nous voulons créer et exporter un nouveau tableau.

export const locations = [
  {
    placename: 'Herndon, VA',
    date: '1er août 2015',
    location: {
      lat: 38.958988,
      lng: -77.417320
    },
    todo: [
      'Où nous commençons ! ?'
    ]
  },
  {
    placename: 'Middlesboro, KY',
    date: '1er août 2015',
    location: {
      lat: 36.627517,
      lng: -83.621635
    },
    todo: [
      'Cumberland Gap ?'
    ]
  }
];

Vous pouvez utiliser ce qui précède pour commencer, mais vous voudrez éventuellement changer les détails pour quelque chose de votre choix.

Si vous souhaitez ajouter une image à votre lieu, vous pouvez le faire en incluant une propriété image à l'objet. Vous pouvez utiliser soit une chaîne d'URL, soit importer un fichier local si vous en avez un disponible, comme je le fais dans cet exemple :

import imgHerndonStart from 'assets/images/herndon-start.jpg';

export const locations = [
  {
    placename: 'Herndon, VA',
    date: '1er août 2015',
    image: imgHerndonStart,
    location: {
      lat: 38.958988,
      lng: -77.417320
    },
    todo: [
      'Où nous commençons ! ?'
    ]
  }
]

Une fois que nous avons créé ce fichier, nous pouvons maintenant importer nos lieux dans notre fichier src/pages/index.js afin de pouvoir les utiliser dans notre prochaine étape :

import { locations } from 'data/locations';

Si vous ajoutez un console.log(locations) à l'intérieur de votre page, vous devriez maintenant voir toutes vos données de localisation dans un tableau !

Suivez avec le commit

Étape 3 : Préparer notre application avec quelques fonctions

Pour essayer de garder les choses simples et ciblées, j'ai regroupé 3 composants importants de la création de notre carte en fonctions. Bien qu'il soit disponible pour copier et coller, nous allons parcourir ce qui se passe dans chaque fonction.

Vous pouvez placer chacune de ces fonctions en bas du fichier src/pages/index.js afin qu'elles soient prêtes à être utilisées dans notre prochaine étape.

createTripPointsGeoJson

Notre première fonction va prendre le tableau de nos lieux et retourner un document GeoJSON, avec nos lieux mappés dans une Feature individuelle. Nous utiliserons cette fonction pour créer les points individuels sur notre carte.

Qu'est-ce qu'un document GeoJSON ? C'est essentiellement un objet JavaScript ou un document JSON avec une structure spécifique qui crée une cohérence avec les données géographiques.

function createTripPointsGeoJson({ locations } = {}) {
  return {
    "type": "FeatureCollection",
    "features": locations.map(({ placename, location = {}, image, date, todo = [] } = {}) => {
      const { lat, lng } = location;
      return {
        "type": "Feature",
        "properties": {
          placename,
          todo,
          date,
          image
        },
        "geometry": {
          "type": "Point",
          "coordinates": [ lng, lat ]
        }
      }
    })
  }
}

Alors, que se passe-t-il dans ce qui précède ?

  • Nous prenons un argument de locations, qui sera notre tableau de destinations
  • Nous retournons un objet avec certaines propriétés dynamiques qui lui sont associées
  • Dans l'objet, nous mappons nos lieux à des objets Feature individuels
  • Chaque objet inclut une forme Point utilisant nos coordonnées
  • Il inclut également nos propriétés qui stockent nos métadonnées

Lorsque cette fonction est appelée, nous aurons un nouvel objet JavaScript qui inclut un tableau de Points représentant les lieux où nous nous arrêtons lors de notre road trip.

createTripLinesGeoJson

Nous allons créer une autre fonction similaire à la précédente. Cette fois cependant, au lieu de points, nous voulons créer des lignes qui représentent le passage d'un point à l'autre.

function createTripLinesGeoJson({ locations } = {}) {
  return {
    "type": "FeatureCollection",
    "features": locations.map((stop = {}, index) => {
      const prevStop = locations[index - 1];

      if ( !prevStop ) return [];

      const { placename, location = {}, date, todo = [] } = stop;
      const { lat, lng } = location;
      const properties = {
        placename,
        todo,
        date
      };

      const { location: prevLocation = {} } = prevStop;
      const { lat: prevLat, lng: prevLng } = prevLocation;

      return {
        type: 'Feature',
        properties,
        geometry: {
          type: 'LineString',
          coordinates: [
            [ prevLng, prevLat ],
            [ lng, lat ]
          ]
        }
      }
    })
  }
}

Vous remarquerez immédiatement que cela est très similaire à notre dernière fonction. Nous retournons un objet et définissons nos propriétés de métadonnées sur une liste de Features.

La grande différence, cependant, est que nous créons une Ligne. Pour ce faire, nous recherchons et faisons référence à prevStop qui sera l'arrêt précédent. Nous utiliserons à la fois l'arrêt précédent et notre arrêt actuel afin d'avoir 2 points que nous pouvons utiliser pour tracer la ligne.

Si nous n'avons pas d'arrêt précédent, nous retournons un tableau vide, ce qui signifie essentiellement que nous sommes au début de notre voyage sans ligne avant celui-ci.

Avec l'arrêt précédent et l'arrêt actuel, nous créons un type de Feature LineString avec nos 2 points.

tripStopPointToLayer

Notre dernière fonction va nous permettre de créer un contenu personnalisé pour chacun des points que nous allons ajouter à notre carte. Nous allons en fait utiliser cette fonction dans une propriété Leaflet, donc nous allons conformer nos arguments à cette spécification.

function tripStopPointToLayer( feature = {}, latlng ) {
  const { properties = {} } = feature;
  const { placename, todo = [], image, date } = properties;

  const list = todo.map(what => `<li>${ what }</li>`);
  let listString = '';
  let imageString = '';

  if ( Array.isArray(list) && list.length > 0 ) {
    listString = list.join('');
    listString = `
      <p>Choses que nous ferons ou avons faites…</p>
      <ul>${listString}</ul>
    `;
  }

  if ( image ) {
    imageString = `
      <span class="trip-stop-image" style="background-image: url(${image})">${placename}</span>
    `;
  }

  const text = `
    <div class="trip-stop">
      ${ imageString }
      <div class="trip-stop-content">
        <h2>${placename}</h2>
        <p class="trip-stop-date">${date}</p>
        ${ listString }
      </div>
    </div>
  `;

  const popup = L.popup({
    maxWidth: 400
  }).setContent(text);

  const layer = L.marker( latlng, {
    icon: L.divIcon({
      className: 'icon',
      html: `<span class="icon-trip-stop"></span>`,
      iconSize: 20
    }),
    riseOnHover: true
  }).bindPopup(popup);

  return layer;
}

Une chose que vous remarquerez en travaillant avec cette fonction est que nous créons des chaînes de texte HTML. Étant donné que l'API Leaflet que nous utilisons pour cela n'interface pas directement avec React, nous devons construire manuellement du HTML pour le passer à nos fonctions.

En commençant par le haut :

  • Nous prenons 2 arguments, feature et latlng. Leaflet passe ces 2 valeurs pour que nous les utilisions dans notre fonction.
  • Nous déstructurons notre feature, ce qui nous permet d'assigner nos métadonnées à des variables
  • 2 variables de chaîne sont initialisées que nous utiliserons pour notre HTML
  • Si nous incluons une propriété todo sous forme de tableau, nous ajoutons une nouvelle liste avec chaque élément à l'intérieur.
  • Si nous incluons une image, nous créons une balise image.
  • Avec nos nouvelles chaînes HTML, nous construisons l'intégralité de ce qui sera notre carte popup pour chaque arrêt
  • Avec notre HTML de popup, nous créons une instance de popup Leaflet
  • Avec l'argument latlng et notre popup, nous créons une nouvelle instance de marker Leaflet. Cela représentera le point sur la carte.
  • À l'intérieur de la création du Marker, nous créons une balise HTML de base que nous utiliserons pour styliser le marqueur
  • Nous liaisons ensuite notre popup à cette nouvelle instance de Marker. Cela permettra à la popup d'être associée à ce Marker individuel
  • Enfin, nous retournons notre nouvelle couche

N'oubliez pas de vous assurer que vous placez toutes les fonctions ci-dessus en bas de votre page src/pages/index.js.

Une fois toutes ces fonctions ajoutées, notre carte devrait toujours être la même chose, essentiellement rien ne se passe.

Suivez avec le commit

Étape 4 : Construire notre trajet

C'est là que les choses deviennent intéressantes. Nous allons maintenant utiliser les fonctions que nous avons créées pour construire notre trajet de road trip. Tout notre travail ici sera dans la fonction mapEffect à l'intérieur du fichier src/pages/index.js.

Pour le contexte, notre fonction mapEffect inclut un argument appelé leafletElement. Cette valeur fait référence à l'instance Map que Leaflet reconnaît. Cette instance Map inclut l'état de notre carte ainsi que de nombreuses fonctions utilitaires pour travailler avec notre carte.

Tout d'abord, en haut de la fonction, nous voulons nous assurer que nous avons une carte. Si ce n'est pas le cas, nous pouvons retourner pour sortir de la fonction.

if ( !leafletElement ) return;

Ensuite, nous voulons utiliser la fonction utilitaire eachLayer et supprimer chaque layer de notre élément de carte. Nous faisons cela pour nous assurer que nous avons toujours l'état correct de la couche de la carte.

leafletElement.eachLayer((layer) => leafletElement.removeLayer(layer));

Avec notre carte nettoyée, nous pouvons utiliser 2 des fonctions que nous avons créées pour créer de nouveaux objets GeoJSON.

const tripPoints = createTripPointsGeoJson({ locations });
const tripLines = createTripLinesGeoJson({ locations });

Avec nos objets GeoJSON, nous devons les convertir en instances Leaflet GeoJSON, que nous utiliserons pour les ajouter à la carte.

const tripPointsGeoJsonLayers = new L.geoJson(tripPoints, {
  pointToLayer: tripStopPointToLayer
});

const tripLinesGeoJsonLayers = new L.geoJson(tripLines);

Si vous remarquez dans ce qui précède, nous utilisons notre fonction tripStopPointToLayer. Comme je l'ai laissé entendre auparavant, l'instance geoJson que nous créons inclut une propriété qui nous permet de passer une fonction, nous donnant la possibilité de manipuler la création de la couche. C'est ainsi que nous créons notre point et le contenu de la popup.

Nous pouvons procéder à l'ajout de ces deux nouvelles couches à notre carte en utilisant addTo.

tripPointsGeoJsonLayers.addTo(leafletElement);
tripLinesGeoJsonLayers.addTo(leafletElement);

Ensuite, pour nous assurer que nous zoomons et centrons sur le bon emplacement, nous voulons récupérer les limites de la carte en utilisant la fonction getBounds sur notre instance de couche GeoJSON.

const bounds = tripPointsGeoJsonLayers.getBounds();

Enfin, nous ajustons la vue de notre carte à ces limites en utilisant la fonction fitBounds sur notre instance Map.

leafletElement.fitBounds(bounds);

Une fois que vous avez enregistré et rechargé la page, vous devriez maintenant voir un chemin bleu représentant le saut de chacun de nos lieux sur la carte !

Image Application de cartographie avec trajet de road trip

Un problème cependant. Si vous remarquez, nous ne voyons que le chemin. Cela est dû au fait que nous devons ajouter du CSS, ce que nous ferons dans la prochaine étape.

Suivez avec le commit

Étape 5 : Styliser nos composants de carte

Notre dernière étape consistera à ajouter des styles qui permettront à nos marqueurs de s'afficher et à nos popups de bien paraître.

Dans cette étape, nous travaillerons à l'intérieur du fichier _home.scss, que vous pouvez trouver dans src/assets/stylesheets/pages.

Nous pouvons commencer par copier et coller ce bloc de styles à la fin de ce fichier. Une fois cela fait, nous pouvons parcourir ce qui se passe.

.trip-stop {

  width: 400px;
  overflow: hidden;

  h2 {
    font-size: 1.4em;
    margin-top: 0;
    margin-bottom: .2em;
  }

  p,
  ul,
  h3 {
    font-size: 1.2em;
    font-weight: normal;
  }

  p {
    margin: .2em 0;
  }

  .trip-stop-date {
    color: $grey-600;
    font-size: 1em;
  }

  ul {
    padding: 0 0 0 1.4em;
    margin: 0;
  }

}

.trip-stop-image {
  display: block;
  float: left;
  overflow: hidden;
  width: 150px;
  height: 150px;
  text-indent: 100%;
  color: transparent;
  background-position: center;
  background-size: cover;
}

.trip-stop-content {
  float: left;
  width: 250px;
  padding-left: 1em;
}

.icon-trip-stop {

  display: block;
  width: 1.5em;
  height: 1.5em;
  background-color: $orange-500;
  border-radius: 100%;
  box-shadow: 0 2px 5px rgba(0,0,0,.5);

  &:hover {
    background-color: $deep-orange-400;
  }

}

Il y a trois composants dans nos styles ci-dessus :

  • .trip-stop-images : À l'intérieur de la popup du marqueur, nous pouvons éventuellement inclure une image. Ces styles définissent la taille, rendent le texte transparent, (il est là pour l'accessibilité), et le flottent à gauche afin que notre contenu de popup puisse s'aligner correctement côte à côte.
  • .trip-stop-content : Cela fait référence à l'autre moitié de notre contenu de popup. Tout ce que nous devons faire ici est de nous assurer que notre taille est appropriée et qu'elle flotte à côté de notre image.
  • .icon-trip-stop : La balise HTML que nous utilisons comme désignation d'icône est stylisée ici. Nous la dimensionnons, définissons une couleur en utilisant une variable Scss prédéterminée, et nous sommes prêts à partir.

Une fois ces styles enregistrés, vous devriez maintenant voir les points sur la carte représentant chaque lieu. De plus, vous devriez pouvoir cliquer sur chacun de ces points pour ouvrir une popup contenant des informations sur l'arrêt.

Image Application de cartographie de road trip avec popups

Suivez avec le commit

Étape finale optionnelle : Ajustements de style

La dernière chose qui est complètement optionnelle est de faire quelques ajustements de style pour donner à votre site un peu de personnalité. Je ne vais pas entrer dans les détails, mais si vous souhaitez suivre et habiller un peu les choses, vous pouvez suivre ce commit qui montre chaque changement de code que j'ai fait.

Image Version finale de l'application de cartographie de road trip

Suivez avec le commit

Hourra, nous l'avons fait !

Si vous avez suivi avec moi, ou si vous êtes passé directement au starter, vous devriez maintenant avoir une application de cartographie que vous pouvez utiliser pour votre prochain road trip.

La bonne nouvelle est que ce projet peut s'appliquer à n'importe quoi ! Vous voulez cartographier vos restaurants préférés à Washington, DC ? Ajoutez vos lieux et supprimez les lignes. Vous voulez créer des dessins de lignes sur la carte ? C'est certainement une option.

Quoi que ce soit, si vous avez aimé créer cette carte, soyez créatif et appliquez-la à votre prochain projet !

Vous voulez en savoir plus sur les cartes ?

Vous pouvez consulter quelques-unes de mes autres ressources pour commencer :