Comment créer des cartes avec React et Leaflet
Publié: 2022-03-10Saisir des informations à partir d'un fichier CSV ou JSON n'est pas seulement compliqué, mais aussi fastidieux. Représenter les mêmes données sous forme d'aide visuelle est plus simple. Dans cet article, nous allons représenter les emplacements des incendies non médicaux auxquels le service d'incendie de SF a répondu sur une carte.
Pour ce tutoriel, nous utiliserons les outils suivants :
- Brochure
Une bibliothèque JavaScript pour les cartes interactives - Réagir
Une bibliothèque JavaScript pour créer des interfaces utilisateur - Dépliant React
Composants React pour les cartes Leaflet
Qu'est-ce qu'un dépliant ?
Avec environ 27 000 étoiles, Leaflet.js est l'une des principales bibliothèques JavaScript open source pour les cartes interactives adaptées aux mobiles. Il tire parti de HTML5 et CSS3 sur les navigateurs modernes tout en étant également accessible sur les plus anciens. Dans l'ensemble, il prend en charge toutes les principales plates-formes de bureau et mobiles.
Leaflet pèse environ 38 Ko et fonctionne parfaitement pour les choses de base. Pour des extensions supplémentaires, il peut être étendu avec une grande quantité de plugins.
De nombreux journaux, dont NPR, Washington Post, Boston Globe, entre autres, et d'autres organisations utilisent Leaflet pour leurs projets de données approfondis.
Le San Francisco Chronicle, par exemple, a réalisé un projet appelé California Fire tracker – une carte interactive qui fournit des informations sur les incendies de forêt en Californie, à l'aide de Leaflet. Non seulement ils ont identifié l'origine de l'incendie, mais ils nous ont également montré la trajectoire de celui-ci.
Puisqu'il s'agit d'un didacticiel d'introduction, nous ne marquerons que les emplacements des incendies et afficherons quelques détails à ce sujet.
Avant de vous lancer dans React, comprenons les bases de Leaflet. Pour cela, nous allons créer un exemple simple où nous allons configurer une carte Leaflet, travailler avec des marqueurs et des popups.
Commençons par créer les fichiers index.html et app.js dans notre dossier /project
et lions ce dernier à notre fichier index.html .
Pour commencer à utiliser Leaflet, nous devons lier Leaflet CSS et Leaflet JS dans nos balises head. Une chose à garder à l'esprit est que Leaflet CSS vient avant Leaflet JS. C'est tout pour Leaflet.
Il y a encore une chose que nous devons ajouter à notre fichier index.html — un conteneur qui contiendra notre carte.
<div></div>
Avant d'oublier, donnons de la hauteur à notre div.
#mapid { height: 1000px; }
Vient maintenant la partie amusante. Que vous décidiez de créer un nouveau fichier JavaScript ou de continuer dans les balises de script, assurez-vous que <div id="mapid">
est ajouté au dom avant d'appeler L.map('mapid')
.
Vous demandez probablement "Mais, pourquoi?" Eh bien, c'est parce que cela vous donnera une erreur si vous liez la carte à un conteneur qui n'existe pas encore.
Uncaught Error: Map container not found
Création d'une carte
Maintenant sur la partie amusante. Pour initialiser la carte, nous passons notre div à L.map()
avec quelques options.
const myMap = L.map('mapid', { center: [37.7749, -122.4194], zoom: 13 })
Allons étape par étape pour comprendre ce qui vient de se passer. Nous utilisons la classe Map de l'API Leaflet pour créer une carte sur la page. On passe en deux paramètres à cette classe :
- Nous avons passé une variable de chaîne représentant l'ID
DOM
- Un littéral d'objet facultatif avec des options de carte
Il existe de nombreuses options que nous pourrions transmettre à notre classe, mais les deux principales options sont le centre et le zoom. Le centre définit un centre géographique initial de la carte tandis que le zoom spécifie un niveau de zoom initial de la carte. Ils sont tous les deux indéfinis par défaut.
Pour le centre, nous sommes passés aux coordonnées de San Francisco. Il existe de nombreux endroits où nous pouvons effectuer un géocodage avant et arrière, mais pour une recherche de base comme celle-ci, nous pouvons le rechercher sur Google.
Habituellement, la valeur du zoom dépendra de ce que vous voulez afficher. Voulez-vous montrer une ville ou un état ? Pays ou continent ? Allez-y et jouez avec la valeur de zoom pour avoir une meilleure idée. Pour cet exemple, nous avons choisi 13 car il montre toute la ville.
Une autre façon d'initialiser la carte consiste à utiliser setView(). Il prend le dans un tableau de coordonnées et un entier pour le niveau de zoom.
const myMap = L.map('map').setView([37.7749, -122.4194], 13);
Par défaut, toutes les interactions souris et tactiles sur la carte sont activées, et elle dispose de commandes de zoom et d'attribution.
Création d'un calque
Ensuite, nous ajouterons une couche de tuiles à notre carte ; dans notre cas, il s'agit d'une couche de tuiles Mapbox Streets. Nous pouvons ajouter différents types de couches de tuiles en instanciant la classe TileLayer.
Pour créer une couche de tuiles, nous devons définir le modèle d'URL pour l'image de la tuile, le texte d'attribution et le niveau de zoom maximal de la couche. Le modèle d'URL est ce qui nous donne accès à la couche de tuiles souhaitée du fournisseur de services. Puisque nous utilisons l'API Static Tiles de Mapbox, nous devrons demander un jeton d'accès.
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', { attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery (c) <a href="https://www.mapbox.com/">Mapbox</a>', maxZoom: 18, id: 'mapbox/streets-v11', accessToken: 'your.mapbox.access.token' }).addTo(mymap);
À ce stade, si nous ouvrons notre index.html dans un navigateur, nous devrions pouvoir voir une carte de San Francisco. Laissons tomber une épingle sur la carte.
Marqueurs et cercles
Nous avons la carte et la couche, mais cela ne nous indique rien de spécifique. Pour pointer vers un endroit particulier sur la carte, Leaflet nous fournit des marqueurs.
Pour épingler un emplacement, nous instancions le marqueur à l'aide de la classe Marker, transmettons les coordonnées et l'ajoutons à la carte. Ici, nous utilisons les coordonnées de Twin Peaks dans la ville.
const marker = L.marker([37.7544, -122.4477]).addTo(mymap);
De même, nous pouvons lier un cercle à la carte en utilisant une classe Circle
. Nous passons quelques options facultatives, telles que le rayon, la couleur, etc. Pour le marqueur de circle
, nous passons dans les coordonnées du phare de Point Bonita.

const circle = L.circle([37.8157, -122.5295], { color: 'gold', fillColor: '#f03', fillOpacity: 0.5, radius: 200 }).addTo(mymap);
Popups
Tout cela est bien, mais que se passe-t-il si nous voulons transmettre plus d'informations sur l'emplacement. Nous faisons cela en utilisant popup.
circle.bindPopup("I am pointing to Point Bonita Lighthouse"); marker.bindPopup("I am pointing to Twin Peaks");
La méthode bindPopup prend un contenu HTML spécifié et l'ajoute au marqueur, de sorte que la fenêtre contextuelle s'affiche lorsque vous cliquez sur le marqueur.
Dépliant React
Nous savons maintenant comment créer une carte et ajouter des marqueurs à l'aide de Leaflet et de JavaScript vanille. Voyons comment nous pouvons obtenir les mêmes résultats avec React. Nous n'allons pas faire la même application mais plutôt faire une application avancée.
La première tâche pour nous est d'obtenir un jeton d'accès à partir du portail San Francisco Open Data. C'est un portail en ligne où nous pouvons trouver des centaines d'ensembles de données de la ville et du comté de San Francisco. J'ai décidé d'utiliser cette ressource, mais il existe de nombreuses autres ressources que nous pouvons utiliser à la place.
Accéder à la clé API
- Créez un compte et connectez-vous au portail.
- Cliquez sur le lien de gestion vers le bas à droite.
- Cliquez sur Créer une nouvelle clé API et donnez-lui un nom.
- Copiez votre identifiant de clé et votre clé secrète. Vous en aurez besoin pour accéder aux données.
Pour cela, nous utiliserons React-Leaflet - composants de réaction pour les cartes Leaflet. Créons une application de réaction.
npx create-react-app react-fire-incidents cd react-fire-incidents
Installons ensuite react-leaflet
et Leaflet en exécutant la commande suivante dans notre terminal :
npm install react-leaflet leaflet
App.js
Créons un dossier /components
à l'intérieur de src
. À l'intérieur des composants, créons un fichier nommé Map.js . C'est là que notre carte vivra. Modifions maintenant App.js en supprimant le code inutile et en important des modules à partir d' react-leaflet axios
react-leaflet et du Map.js nouvellement créé.
import React, { Component, Fragment } from 'react'; import axios from 'axios'; import Map from './components/Map'
Dans notre classe App, nous allons définir un tableau dans notre état appelé incidents - lorsque la page se charge, nous allons pousser nos données dans ce tableau.
class App extends Component { state = { incidents: [], } render() { return ( <div> </div> ); } } export default App;
Ensuite, nous ferons une requête GET lors du montage du composant. Nous avons le jeton d'application, mais nous avons toujours besoin d'un point de terminaison. Où trouve-t-on le point final ?
Dirigeons-nous vers le portail et cliquez sur Parcourir les données. Dans la barre de recherche, recherchons les incidents d'incendie. Le premier résultat qui apparaît est ce que nous recherchons. Une fois que nous avons cliqué sur le lien, nous pouvons obtenir l'URL en cliquant sur le bouton API en haut à droite.
Nous transmettrons le point de terminaison à notre requête GET, et transmettrons une limite et notre jeton d'application en tant que paramètres. Les données d'origine contiennent des milliers d'enregistrements, mais par souci de simplicité, nous les avons limitées à 500. Nous mettons à jour notre tableau d'incidents avec nos résultats.
Une fois que nous obtenons les données, nous mettons à jour notre état.
async componentDidMount() { const res = await axios.get('https://data.sfgov.org/resource/wr8u-xric.json', { params: { "$limit": 500, "$$app_token": YOUR_APP_TOKEN } }) const incidents = res.data; this.setState({incidents: incidents }); };
Voici à quoi devrait ressembler notre App.js.
class App extends Component { state = { incidents: [], } async componentDidMount() { const res = await axios.get('https://data.sfgov.org/resource/wr8u-xric.json', { params: { "$limit": 500, "$$app_token": YOUR_APP_TOKEN } }) const incidents = res.data; this.setState({incidents: incidents }); }; render() { return ( <Map incidents={this.state.incidents}/> ); } } export default App;
Map.js
Puisque nous savons déjà comment créer une carte Leaflet, cette partie sera relativement facile. Nous allons importer les composants Map
, TileLayer
, Marker
, Popup
de react- react-leaflet
.
import React, { Component } from 'react' import { Map, TileLayer, Marker, Popup } from 'react-leaflet'
Si nous nous souvenons de l'exemple précédent, nous avons besoin de coordonnées et d'un niveau de zoom pour initialiser la carte. Dans notre classe Map
, nous les définissons dans notre état en utilisant les variables lat
, lng
et zoom
.
export default class Map extends Component { state = { lat: 37.7749, lng: -122.4194, zoom: 13, } render() { return ( <div></div> ) } }
Ensuite, nous vérifierons si notre tableau d'incidents est vide. S'il est vide, nous renverrons un message disant « Les données sont en cours de chargement » ; sinon, nous renverrons une carte.
Dans le composant Map
de notre react-leaflet
, nous passerons les coordonnées du centre et un niveau de zoom avec un peu de style. Dans notre composant TileLayer
, nous transmettrons une attribution et une URL similaires à notre exemple précédent.
render() { return ( this.props.incidents ? <Map center={[this.state.lat, this.state.lng]} zoom={this.state.zoom} style={{ width: '100%', height: '900px'}} > <TileLayer attribution='© <a href="https://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> </Map> : 'Data is loading...' ) } }
Ensuite, nous parcourons notre props.incident
et transmettons les coordonnées de chaque incident au composant Marker. Étant donné que React nous avertit de transmettre une clé à chaque élément d'un tableau, nous transmettrons également une clé à Marker.
À l'intérieur du composant Marker
, nous passons un composant Popup
. J'ai ajouté des informations sur l'incident dans la fenêtre contextuelle.
<Map center={[this.state.lat, this.state.lng]} zoom={this.state.zoom} style={{ width: '100%', height: '900px'}}> <TileLayer attribution='© <a href="https://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> { this.props.incidents.map(incident => { const point = [incident['point']['coordinates'][1], incident['point']['coordinates'][0]] return ( <Marker position={point} key={incident['incident_number']} > <Popup> <span>ADDRESS: {incident['address']}, {incident['city']} - {incident['zip_code']}</span> <br/> <span>BATTALION: {incident['battalion']}</span><br/> </Popup> </Marker> ) }) } </Map>
Et c'est tout. Si nous exécutons notre application, et si tout se passe bien, nous devrions être en mesure de voir une carte de San Francisco avec 500 marqueurs nous indiquant les emplacements des incendies. Si nous cliquons sur l'un de ces marqueurs, une fenêtre contextuelle apparaîtra avec plus d'informations sur l'incident.
Emballer
Même si nous avons couvert beaucoup de choses, ce n'était que les bases. Leaflet est un outil très puissant, et nous pouvons créer de nombreux types de cartes. Si vous voulez jouer, essayez d'ajouter un autre calque ou une icône personnalisée. Ou peut-être souhaitez-vous créer une carte choroplèthe interactive.