13_React - Mapas e Locais(Overpass, Nominatim e OpenStreetMap)
Para criar um site em Vite com React que encontre hospitais, delegacias, escolas e outros locais próximos usando um dropdown, podemos utilizar a Geolocation API para obter a posição do usuário e a Overpass API (baseada no OpenStreetMap) para buscar locais próximos. O Leaflet será usado para exibir um mapa interativo.
Passo a Passo
- Configurar o projeto com Vite e React.
- Adicionar as dependências para Leaflet e React-Leaflet.
- Criar componentes para o dropdown e para exibir os locais no mapa.
1. Criação do Projeto Vite com React
No terminal, execute os seguintes comandos:
# Instalar o Vite com template React
npm create vite@latest my-location-app --template react
cd my-location-app
# Instalar Leaflet e React-Leaflet
npm install leaflet react-leaflet
2. Código do Aplicativo
Com o projeto configurado, vamos criar os componentes necessários.
Estrutura do Projeto
my-location-app/
├── src/
│ ├── App.jsx
│ ├── components/
│ │ ├── Dropdown.jsx
│ │ └── MapView.jsx
│ └── main.jsx
├── index.html
└── package.json
App.jsx
Este é o componente principal do aplicativo. Ele gerencia o estado para o tipo de local selecionado e a posição do usuário.
import React, { useState, useEffect } from 'react';
import Dropdown from './components/Dropdown';
import MapView from './components/MapView';
function App() {
const [userLocation, setUserLocation] = useState(null);
const [selectedPlace, setSelectedPlace] = useState('hospital');
const [places, setPlaces] = useState([]);
// Obter a localização do usuário
useEffect(() => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
setUserLocation({
lat: position.coords.latitude,
lon: position.coords.longitude,
});
},
() => alert('Não foi possível obter a localização.')
);
}
}, []);
// Buscar locais próximos usando Overpass API
useEffect(() => {
if (userLocation) {
const fetchPlaces = async () => {
const url = `https://overpass-api.de/api/interpreter?data=[out:json];node["amenity"="${selectedPlace}"](around:3000,${userLocation.lat},${userLocation.lon});out;`;
const response = await fetch(url);
const data = await response.json();
setPlaces(data.elements || []);
};
fetchPlaces();
}
}, [userLocation, selectedPlace]);
return (
<div>
<h1>Encontre Locais Próximos</h1>
<Dropdown selectedPlace={selectedPlace} setSelectedPlace={setSelectedPlace} />
{userLocation && <MapView userLocation={userLocation} places={places} />}
</div>
);
}
export default App;
Dropdown.jsx
Componente para selecionar o tipo de local no dropdown.
import React from 'react';
const Dropdown = ({ selectedPlace, setSelectedPlace }) => {
const handleChange = (event) => {
setSelectedPlace(event.target.value);
};
return (
<select value={selectedPlace} onChange={handleChange}>
<option value="hospital">Hospital</option>
<option value="police">Delegacia</option>
<option value="school">Escola</option>
<option value="restaurant">Restaurante</option>
<option value="bank">Banco</option>
</select>
);
};
export default Dropdown;
MapView.jsx
Este componente exibe o mapa e adiciona marcadores para os locais encontrados.
import React from 'react';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';
// Corrigir ícones padrão do Leaflet
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
});
const MapView = ({ userLocation, places }) => {
return (
<MapContainer center={[userLocation.lat, userLocation.lon]} zoom={13} style={{ height: "400px", width: "100%" }}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution='© OpenStreetMap contributors' />
{/* Marcador para a posição do usuário */}
<Marker position={[userLocation.lat, userLocation.lon]}>
<Popup>Você está aqui</Popup>
</Marker>
{/* Marcadores para os locais encontrados */}
{places.map(place => (
<Marker key={place.id} position={[place.lat, place.lon]}>
<Popup>
<strong>{place.tags.name || 'Nome não disponível'}</strong><br />
{place.tags['addr:street'] || 'Endereço não disponível'}
</Popup>
</Marker>
))}
</MapContainer>
);
};
export default MapView;
main.jsx
Este é o ponto de entrada do aplicativo.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Estilização Opcional (index.css
)
Para estilizar o dropdown e o layout geral:
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: auto;
padding: 20px;
}
h1 {
text-align: center;
}
select {
padding: 10px;
font-size: 16px;
margin: 10px 0;
}
Executar o Projeto
Após configurar o código, inicie o servidor de desenvolvimento:
npm run dev
Esse projeto exibirá um dropdown para selecionar o tipo de local (como hospital, delegacia, etc.) e um mapa interativo com a posição do usuário e os locais próximos encontrados.