Como criar mapas com React e Leaflet
Publicados: 2022-03-10Capturar informações de um arquivo CSV ou JSON não é apenas complicado, mas também tedioso. Representar os mesmos dados na forma de auxílio visual é mais simples. Neste artigo, representaremos em um mapa os locais dos incidentes de incêndio não médicos aos quais o Corpo de Bombeiros de SF respondeu.
Para este tutorial, usaremos as seguintes ferramentas:
- Folheto
Uma biblioteca JavaScript para mapas interativos - Reagir
Uma biblioteca JavaScript para construir interfaces de usuário - React-Folheto
Componentes do React para mapas do Leaflet
O que é folheto?
Com cerca de 27 mil estrelas, Leaflet.js é uma das principais bibliotecas JavaScript de código aberto para mapas interativos compatíveis com dispositivos móveis. Ele tira proveito de HTML5 e CSS3 em navegadores modernos, sendo acessível também em navegadores mais antigos. Em suma, ele suporta todas as principais plataformas móveis e de desktop.
O folheto pesa cerca de 38 KB e funciona perfeitamente para coisas básicas. Para extensões adicionais, ele pode ser estendido com uma grande quantidade de plugins.
Muitos jornais, incluindo NPR, Washington Post, Boston Globe, entre outros, e outras organizações usam o Leaflet para seus projetos de dados detalhados.
O San Francisco Chronicle, por exemplo, fez um projeto chamado California Fire tracker – um mapa interativo que fornece informações sobre incêndios florestais na Califórnia, usando o Leaflet. Eles não apenas identificaram a origem do incêndio, mas também nos mostraram a trajetória do mesmo.
Como este é um tutorial introdutório, estaremos apenas marcando os locais dos incidentes de incêndio e exibindo alguns detalhes sobre o mesmo.
Antes de pular para o React, vamos entender o básico do Leaflet. Para isso, criaremos um exemplo simples onde estaremos configurando um mapa Leaflet, trabalhando com marcadores e pop-ups.
Primeiro, vamos criar os arquivos index.html e app.js em nossa pasta /project
e vinculá-los ao nosso arquivo index.html .
Para começar a usar o Leaflet, precisamos vincular o Leaflet CSS e o Leaflet JS em nossas tags head. Uma coisa a ter em mente é que o Leaflet CSS vem antes do Leaflet JS. Isso é tudo para o Folheto.
Há mais uma coisa que precisamos adicionar ao nosso arquivo index.html — um contêiner que conterá nosso mapa.
<div></div>
Antes que esqueçamos, vamos dar altura ao nosso div.
#mapid { height: 1000px; }
Agora vem a parte divertida. Se você decidir criar um novo arquivo JavaScript ou continuar nas tags de script, certifique-se de que <div id="mapid">
seja adicionado ao dom antes de chamar L.map('mapid')
.
Você provavelmente está perguntando “Mas, por quê?” Bem, é porque dará um erro se você vincular o mapa a um contêiner que ainda não existe.
Uncaught Error: Map container not found
Criando um mapa
Agora, para a parte divertida. Para inicializar o mapa, passamos nossa div para L.map()
com algumas opções.
const myMap = L.map('mapid', { center: [37.7749, -122.4194], zoom: 13 })
Vamos passo a passo para entender o que acabou de acontecer. Usamos a classe Map da API Leaflet para criar um mapa na página. Passamos dois parâmetros para esta classe:
- Passamos uma variável de string representando o ID
DOM
- Um literal de objeto opcional com opções de mapa
Existem muitas opções que poderíamos passar para nossa classe, mas as duas principais opções são o centro e o zoom. O centro define um centro geográfico inicial do mapa, enquanto o zoom especifica um nível de zoom inicial do mapa. Ambos são indefinidos por padrão.
Para o centro, passamos nas coordenadas de São Francisco. Existem muitos lugares onde podemos realizar geocodificação direta e reversa, mas para pesquisas básicas como essa, podemos pesquisar no Google.
Normalmente, o valor do zoom dependerá do que você deseja exibir. Você quer mostrar uma cidade ou um estado? País ou continente? Vá em frente e brinque com o valor do zoom para ter uma ideia melhor. Para este exemplo, escolhemos 13 porque mostra a cidade inteira.
Outra maneira de inicializar o mapa é usando setView(). Leva o em uma matriz de coordenadas e um número inteiro para o nível de zoom.
const myMap = L.map('map').setView([37.7749, -122.4194], 13);
Por padrão, todas as interações de mouse e toque no mapa estão habilitadas e possui controles de zoom e atribuição.
Criando uma camada
Em seguida, adicionaremos uma camada de mosaico ao nosso mapa; no nosso caso, é uma camada de mosaico Mapbox Streets. Podemos anexar vários tipos de camadas de mosaico instanciando a classe TileLayer.
Para criar uma camada de mosaico, precisamos definir o modelo de URL para a imagem de mosaico, o texto de atribuição e o nível máximo de zoom da camada. O modelo de URL é o que nos dá acesso à camada de bloco desejada do provedor de serviços. Como estamos usando a API Static Tiles do Mapbox, precisaremos solicitar um token de acesso.
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);
Neste ponto, se abrirmos nosso index.html em um navegador, poderemos ver um mapa de São Francisco. Vamos colocar um alfinete no mapa.
Marcadores e círculos
Temos o mapa e a camada, mas não nos aponta para nada específico. Para apontar para um local específico no mapa, o Leaflet nos fornece marcadores.
Para fixar um local, instanciamos o marcador usando a classe Marker, passamos as coordenadas e o adicionamos ao mapa. Aqui estamos usando as coordenadas de Twin Peaks na cidade.
const marker = L.marker([37.7544, -122.4477]).addTo(mymap);
Da mesma forma, podemos vincular um círculo ao mapa usando uma classe Circle
. Passamos algumas opções opcionais, como raio, cor e assim por diante. Para o marcador circle
, estamos passando nas coordenadas do Farol Point Bonita.

const circle = L.circle([37.8157, -122.5295], { color: 'gold', fillColor: '#f03', fillOpacity: 0.5, radius: 200 }).addTo(mymap);
Pop-ups
Isso tudo é ótimo, mas e se quisermos passar mais algumas informações sobre o local. Fazemos isso usando pop-up.
circle.bindPopup("I am pointing to Point Bonita Lighthouse"); marker.bindPopup("I am pointing to Twin Peaks");
O método bindPopup recebe um conteúdo HTML especificado e o anexa ao marcador, para que o pop-up apareça quando você clicar no marcador.
React-Folheto
Agora sabemos como criar um mapa e adicionar marcadores usando Leaflet e JavaScript vanilla. Vamos ver como podemos alcançar os mesmos resultados com React. Não vamos fazer a mesma aplicação, mas sim uma aplicação avançada.
A primeira tarefa para nós é obter um token de acesso do portal de dados abertos de São Francisco. É um portal online onde podemos encontrar centenas de conjuntos de dados da cidade e do condado de São Francisco. Decidi usar este recurso, mas existem muitos outros recursos disponíveis que podemos usar.
Chave de API de acesso
- Crie uma conta e entre no portal.
- Clique no link gerenciar no canto inferior direito.
- Clique em Criar nova chave de API e dê um nome a ela.
- Copie o ID da chave e o segredo da chave. Você precisaria disso para acessar os dados.
Para isso, usaremos os componentes React-Leaflet – react para mapas Leaflet. Vamos criar um aplicativo de reação.
npx create-react-app react-fire-incidents cd react-fire-incidents
Então vamos instalar react-leaflet
e Leaflet executando o seguinte comando em nosso terminal:
npm install react-leaflet leaflet
App.js
Vamos criar uma pasta /components
dentro de src
. Dentro dos componentes, vamos criar um arquivo chamado Map.js . É aqui que o nosso Mapa ficará. Agora vamos editar o App.js removendo o código desnecessário e importando módulos dos axios do react-leaflet axios
recém -criado.
import React, { Component, Fragment } from 'react'; import axios from 'axios'; import Map from './components/Map'
Em nossa classe App, vamos definir uma matriz em nosso estado chamada incidentes — quando a página for carregada, enviaremos nossos dados para essa matriz.
class App extends Component { state = { incidents: [], } render() { return ( <div> </div> ); } } export default App;
Em seguida, faremos uma solicitação GET quando o componente for montado. Temos o token do aplicativo, mas ainda precisamos de um endpoint. Onde encontramos o ponto final?
Vamos para o portal e clique em Browse Data. Na barra de pesquisa, vamos procurar incidentes de incêndio. O primeiro resultado que aparece é o que estamos procurando. Depois de clicar no link, podemos obter o URL clicando no botão API no canto superior direito.
Passaremos o endpoint para nossa solicitação GET e passaremos um limite e nosso token de aplicativo como parâmetros. Os dados originais têm milhares de registros, mas para simplificar, limitamos a 500. Atualizamos nossa matriz de incidentes com nossos resultados.
Assim que obtivermos os dados, atualizamos nosso estado.
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 }); };
É assim que nosso App.js deve ser.
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
Como já sabemos como criar um mapa Leaflet, essa parte será relativamente fácil. Importaremos os componentes Map
, TileLayer
, Marker
, Popup
do react react-leaflet
.
import React, { Component } from 'react' import { Map, TileLayer, Marker, Popup } from 'react-leaflet'
Se nos lembrarmos do exemplo anterior, precisamos de coordenadas e um nível de zoom para inicializar o mapa. Em nossa classe Map
, nós os definimos em nosso estado usando as variáveis lat
, lng
e zoom
.
export default class Map extends Component { state = { lat: 37.7749, lng: -122.4194, zoom: 13, } render() { return ( <div></div> ) } }
Em seguida, verificaremos se nossa matriz de incidentes está vazia. Se estiver vazio, retornaremos uma mensagem dizendo “Data is Loading”; caso contrário, retornaremos um mapa.
No componente Map
do nosso react-leaflet
, passaremos as coordenadas centrais e um nível de zoom junto com alguns estilos. Em nosso componente TileLayer
, passaremos atribuição e URL semelhante ao nosso exemplo anterior.
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...' ) } }
Em seguida, fazemos um loop sobre nosso props.incident
e passamos as coordenadas de cada incidente para o componente Marker. Como o React nos avisa para passar uma chave para cada item em um array, passaremos uma chave para Marker também.
Dentro do componente Marker
, passamos um componente Popup
. Eu adicionei algumas informações sobre o incidente dentro do pop-up.
<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 é isso. Se executarmos nosso aplicativo e tudo correr bem, poderemos ver um mapa de São Francisco com 500 marcadores apontando para os locais dos incidentes de incêndio. Se clicarmos em um desses marcadores, aparecerá um pop-up com mais informações sobre o incidente.
Empacotando
Apesar de termos coberto muito, isso foi apenas o básico. O folheto é uma ferramenta muito poderosa, e podemos criar muitos tipos diferentes de mapas. Se você quiser brincar, tente adicionar outra camada ou um ícone personalizado. Ou talvez você queira criar um mapa coroplético interativo.