Come creare mappe con React e Leaflet
Pubblicato: 2022-03-10Afferrare le informazioni da un file CSV o JSON non è solo complicato, ma è anche noioso. Rappresentare gli stessi dati sotto forma di ausilio visivo è più semplice. In questo articolo, rappresenteremo i luoghi degli incidenti di incendio non medici a cui i vigili del fuoco di SF hanno risposto su una mappa.
Per questo tutorial, utilizzeremo i seguenti strumenti:
- Volantino
Una libreria JavaScript per mappe interattive - Reagire
Una libreria JavaScript per la creazione di interfacce utente - React-Volantino
Componenti di reazione per le mappe del volantino
Che cos'è il volantino?
Con circa 27.000 stelle, Leaflet.js è una delle principali librerie JavaScript open source per mappe interattive ottimizzate per dispositivi mobili. Sfrutta HTML5 e CSS3 sui browser moderni ed è accessibile anche su quelli meno recenti. Tutto sommato, supporta tutte le principali piattaforme desktop e mobili.
Il volantino pesa circa 38 KB e funziona perfettamente per le cose di base. Per estensioni aggiuntive, può essere esteso con una grande quantità di plugin.
Molti giornali, tra cui NPR, Washington Post, Boston Globe, tra gli altri, e altre organizzazioni utilizzano Leaflet per i loro progetti di dati approfonditi.
Il San Francisco Chronicle, ad esempio, ha realizzato un progetto chiamato California Fire tracker, una mappa interattiva che fornisce informazioni sugli incendi che bruciano in tutta la California, utilizzando Leaflet. Non solo hanno individuato l'origine del fuoco, ma ci hanno anche mostrato la traiettoria.
Poiché questo è un tutorial introduttivo, contrassegneremo solo le posizioni degli incidenti di incendio e mostreremo alcuni dettagli a riguardo.
Prima di entrare in React, comprendiamo le basi di Leaflet. Per questo, creeremo un semplice esempio in cui imposteremo una mappa Leaflet, lavoreremo con marker e popup.
Per prima cosa, creiamo i file index.html e app.js nella nostra cartella /project
e colleghiamo quest'ultima al nostro file index.html .
Per iniziare a utilizzare Leaflet, dobbiamo collegare Leaflet CSS e Leaflet JS nei nostri tag head. Una cosa da tenere a mente è che il volantino CSS viene prima del volantino JS. Questo è tutto per il volantino.
C'è un'altra cosa che dobbiamo aggiungere al nostro file index.html : un contenitore che conterrà la nostra mappa.
<div></div>
Prima di dimenticare, diamo altezza al nostro div.
#mapid { height: 1000px; }
Ora arriva la parte divertente. Sia che tu decida di creare un nuovo file JavaScript o di continuare con i tag di script, assicurati che <div id="mapid">
sia aggiunto al dom prima di chiamare L.map('mapid')
.
Probabilmente stai chiedendo "Ma, perché?" Bene, è perché ti darà un errore se colleghi la mappa a un contenitore che non esiste ancora.
Uncaught Error: Map container not found
Creazione di una mappa
Ora, sulla parte divertente. Per inizializzare la mappa, passiamo il nostro div a L.map()
con alcune opzioni.
const myMap = L.map('mapid', { center: [37.7749, -122.4194], zoom: 13 })
Andiamo passo dopo passo per capire cosa è appena successo. Usiamo la classe Map dell'API Leaflet per creare una mappa sulla pagina. Passiamo in due parametri a questa classe:
- Abbiamo passato una variabile stringa che rappresenta l'ID
DOM
- Un oggetto letterale opzionale con opzioni della mappa
Ci sono molte opzioni che potremmo passare alla nostra classe, ma le due opzioni principali sono il centro e lo zoom. Il centro definisce un centro geografico iniziale della mappa mentre lo zoom specifica un livello di zoom iniziale della mappa. Entrambi non sono definiti per impostazione predefinita.
Per il centro, siamo passati alle coordinate di San Francisco. Ci sono molti posti in cui possiamo eseguire la geocodifica in avanti e indietro, ma per ricerche di base come questa, possiamo google.
Di solito, il valore dello zoom dipende da cosa si desidera visualizzare. Vuoi mostrare una città o uno stato? Paese o continente? Vai avanti e gioca con il valore dello zoom per avere un'idea migliore. Per questo esempio, abbiamo scelto 13 perché mostra l'intera città.
Un altro modo per inizializzare la mappa è usare setView(). Prende in una matrice di coordinate e un numero intero per il livello di zoom.
const myMap = L.map('map').setView([37.7749, -122.4194], 13);
Per impostazione predefinita, tutte le interazioni del mouse e del tocco sulla mappa sono abilitate e dispone di controlli di attribuzione e zoom.
Creazione di un livello
Successivamente, aggiungeremo un tile layer alla nostra mappa; nel nostro caso, è un tile layer Mapbox Streets. Possiamo aggiungere vari tipi di tile layer istanziando la classe TileLayer.
Per creare un livello piastrella, è necessario impostare il modello di URL per l'immagine del riquadro, il testo di attribuzione e il livello di zoom massimo del livello. Il modello di URL è ciò che ci dà accesso al tile layer desiderato dal fornitore di servizi. Poiché stiamo utilizzando l'API Static Tiles di Mapbox, dovremo richiedere un token di accesso.
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);
A questo punto, se apriamo il nostro index.html in un browser, dovremmo essere in grado di vedere una mappa di San Francisco. Mettiamo un segnaposto sulla mappa.
Marcatori E Cerchi
Abbiamo la mappa e il livello, ma non ci indica nulla di specifico. Per indicare una posizione particolare sulla mappa, Leaflet ci fornisce dei marcatori.
Per bloccare una posizione, istanziamo il marker usando la classe Marker, passiamo le coordinate e lo aggiungiamo alla mappa. Qui stiamo usando le coordinate di Twin Peaks in città.
const marker = L.marker([37.7544, -122.4477]).addTo(mymap);
Allo stesso modo, possiamo associare un cerchio alla mappa usando una classe Circle
. Passiamo alcune opzioni opzionali, come raggio, colore e così via. Per il marcatore del circle
, stiamo passando nelle coordinate del faro di Point Bonita.
const circle = L.circle([37.8157, -122.5295], { color: 'gold', fillColor: '#f03', fillOpacity: 0.5, radius: 200 }).addTo(mymap);
Popup
È tutto fantastico, ma se volessimo passare qualche informazione in più sulla posizione. Lo facciamo usando il popup.
circle.bindPopup("I am pointing to Point Bonita Lighthouse"); marker.bindPopup("I am pointing to Twin Peaks");
Il metodo bindPopup accetta un contenuto HTML specificato e lo aggiunge al marcatore, in modo che il popup venga visualizzato quando si fa clic sul marcatore.
React-Volantino
Ora sappiamo come creare una mappa e aggiungere marcatori usando Leaflet e vanilla JavaScript. Vediamo come possiamo ottenere gli stessi risultati con React. Non creeremo la stessa applicazione, ma creeremo invece un'applicazione avanzata.
Il primo compito per noi è ottenere un token di accesso dal portale Open Data di San Francisco. È un portale online in cui possiamo trovare centinaia di set di dati dalla città e dalla contea di San Francisco. Ho deciso di utilizzare questa risorsa, ma ci sono molte altre risorse là fuori che possiamo usare invece.
Accedi alla chiave API
- Crea un account e accedi al portale.
- Fare clic sul collegamento di gestione in basso a destra.
- Fai clic su Crea nuova chiave API e assegnagli un nome.
- Copia il tuo ID chiave e Key Secret. Ne avrai bisogno per accedere ai dati.
Per questo, useremo React-Leaflet – componenti di reazione per le mappe di Leaflet. Creiamo un'app di reazione.
npx create-react-app react-fire-incidents cd react-fire-incidents
Quindi installiamo react-leaflet
e Leaflet eseguendo il seguente comando nel nostro terminale:
npm install react-leaflet leaflet
App.js
Creiamo una cartella /components
all'interno di src
. All'interno dei componenti, creiamo un file chiamato Map.js . È qui che vivrà la nostra mappa. Ora modifichiamo App.js rimuovendo il codice non necessario e importando moduli da react-leaflet axios
e Map.js appena creato.
import React, { Component, Fragment } from 'react'; import axios from 'axios'; import Map from './components/Map'
Nella nostra classe App, definiremo un array nel nostro stato chiamato incidenti: quando la pagina verrà caricata, inseriremo i nostri dati in questo array.
class App extends Component { state = { incidents: [], } render() { return ( <div> </div> ); } } export default App;
Successivamente, faremo una richiesta GET quando il componente viene montato. Abbiamo il token dell'app, ma abbiamo ancora bisogno di un endpoint. Dove troviamo l'endpoint?
Andiamo al portale e clicchiamo su Sfoglia dati. Nella barra di ricerca, cerchiamo gli incidenti di incendio. Il primo risultato che si presenta è quello che stiamo cercando. Dopo aver fatto clic sul collegamento, possiamo ottenere l'URL facendo clic sul pulsante API in alto a destra.
Passeremo l'endpoint alla nostra richiesta GET e passeremo un limite e il nostro token dell'app come parametri. I dati originali hanno migliaia di record, ma per semplificare le cose, li abbiamo limitati a 500. Aggiorniamo il nostro array di incidenti con i nostri risultati.
Una volta ottenuti i dati, aggiorniamo il nostro stato.
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 }); };
Ecco come dovrebbe essere il nostro 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
Poiché sappiamo già come creare una mappa del volantino, questa parte sarà relativamente facile. Importeremo i componenti Map
, TileLayer
, Marker
, Popup
da react-leaflet
.
import React, { Component } from 'react' import { Map, TileLayer, Marker, Popup } from 'react-leaflet'
Se ricordiamo dall'esempio precedente, abbiamo bisogno delle coordinate e di un livello di zoom per l'inizializzazione della mappa. Nella nostra classe Map
, li definiamo nel nostro stato usando variabili lat
, lng
e zoom
.
export default class Map extends Component { state = { lat: 37.7749, lng: -122.4194, zoom: 13, } render() { return ( <div></div> ) } }
Quindi verificheremo se la nostra serie di incidenti è vuota. Se è vuoto, restituiremo un messaggio che dice "Dati in caricamento"; in caso contrario, restituiremo una mappa.
Nel componente Map
del nostro react-leaflet
, passeremo le coordinate centrali e un livello di zoom insieme ad alcuni stili. Nel nostro componente TileLayer
, passeremo l'attribuzione e l'URL in modo simile al nostro esempio precedente.
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...' ) } }
Successivamente, eseguiamo il ciclo del nostro props.incident
e passiamo le coordinate di ogni incidente al componente Marker. Poiché React ci avverte di passare una chiave a ogni elemento in un array, passeremo anche una chiave a Marker.
All'interno del componente Marker
, passiamo a un componente Popup
. Ho aggiunto alcune informazioni sull'incidente all'interno del popup.
<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>
E questo è tutto. Se eseguiamo la nostra app e se tutto è andato bene, dovremmo essere in grado di vedere una mappa di San Francisco con 500 indicatori che ci indicano i luoghi degli incendi. Se facciamo clic su uno di questi indicatori, verrà visualizzato un popup con ulteriori informazioni sull'incidente.
Avvolgendo
Anche se abbiamo trattato molto, queste erano solo le basi. Leaflet è uno strumento molto potente e possiamo creare molti tipi diversi di mappe. Se vuoi giocare, prova ad aggiungere un altro livello o un'icona personalizzata. O forse ti piacerebbe creare una mappa coropletica interattiva.