En este blog vamos a ver cómo implementar un mapa con la librería Leaflet, accediendo a la Api opendatasoft para poder localizar mediante coordenadas las diferentes provincias y municipios de España. Además, accederemos a la Api de Aemet para acceder al tiempo de cada zona interesada. La tecnología que se va a utilizar es React.

Instalación de dependencias Leaflet

Para comenzar vamos a crear un proyecto nuevo con el comando npx create-react-app mapaleaflet. Una vez tengamos el proyecto inyectaremos las dependencias de las librerías que vamos a utilizar:

  • npm install -s react react-dom leaflet
  • npm install -s react-leaflet

Como leaflet tiene su propio diseño, tenemos que añadir también el su css.

  • npm i leaflet-css

Leaflet trabaja con types por lo que tenemos que instalar la libreria:

  • npm install -D @types/leaflet

Uso de los componentes

Leaflet se encarga de representar las capas del mapa, mientras que React renderiza el componente <MapContainer></MapContainer> junto con todo el contenido que engloba la creación del mapa, el cual se sitúa dentro de dichas etiquetas.

Es importante saber que los mapas son un proyecto colaborativo y están bajo una licencia abierta, por lo tanto la marca de agua debe estar presente siempre. Las url donde podemos encontrar los diferentes diseños de los mapas es https://geopois.com/blog/leaflet/leaflet-tiles. Dicha url, para poder visualizar el nuestro, debemos incluirla como parámetro del componente <TileLayer>.

 <TileLayer  attribution=’&copy; 
<a href=»http://osm.org/copyright»>OpenStreetMap</a> 
contributors’  url=»https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png»  />

El componente MapContainer requiere de ciertos parámetros para poder ajustar el foco inicial (coordenadas) y el zoom, entre otros.

MapComponent.js

Primero importamos los componentes que vamos a utilizar y el css de leaflet:

import { MapContainer, Marker, Popup, TileLayer } from ‘react-leaflet’;

import ‘leaflet-css/dist/leaflet.css’;

//creamos una constante con las coordenadas por defecto

const coordenadas=[51.505, -0.09];

render(){

return(

<MapContainer
center={coordenadas}
zoom=’7′
scrollWheelZoom={true}>

// si queremos que al hacer scroll haga zoom

<TileLayer  
attribution=’&copy; <a href=»http://osm.org/copyright»>OpenStreetMap</a> contributors’  
url=»https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png»

// a medida que cambian las coordenadas y el zoom, los parámetros {z}, {x} e {y} cambian para mostrarlos la parte del mapa que nos interesa

 />

</MapContainer>

)

Una vez que tenemos la instancia del mapa podremos visualizarlo. Lo que toca ahora es darle vida. Otros de los componentes que se pueden utilizar dentro del MapContainer son, por ejemplo, los <Marker> y el <Popup>.

¿Qué hace cada uno?

Marker es el icono que nos indica un punto concreto en el mapa.

<Marker 

position={coordenadas} icon={Iconlocation}

>

El parámetro icon recibe un objeto, dicho objeto tendrá las propiedades de L.icon. De esta manera podemos personalizar el icono e incluso utilizar otros que no vengan por defecto con leaflet.

Si queremos utilizar varios iconos, creamos tantos objetos como deseemos. La creación del mismo quedaría asi:

IconLocation.js

Primero importamos el objeto L de leaflet para poder crear el icono y el .png o .jpg que vayamos a utilizar.

import L from ‘leaflet’;

import icon from ‘./assets/icono.png’;

const IconLocation=L.icon({

iconUrl: icon,

iconSize: new L.Point(60,75)

})

export default IconLocation;

Existen multitud de propiedades que podemos modificar a gusto.

Volviendo a nuestro componente MapComponent.js, seguimos analizando el resto de componentes que vamos a utilizar para trabajar con nuestro mapa.

MapComponent.js

El componente <Popup> nos permite mostrar una tarjeta informativa cada vez que hacemos clic en un marcador en el mapa. Podemos mostrar toda la información que deseemos, en este proyecto vamos a mostrar: la provincia, el municipio, las coordenadas y la temperatura máxima y mínima.

¿cómo se utiliza?

Simplemente vamos a introducir dentro de la etiqueta que abre y la que cierra, todo aquello que deseemos.

<Popup> .. Nuestro diseño de tarjeta .. </Popup>

Acceso a Api OpenDataSoft

Para buscar información en el mapa vamos a crear un formulario con un select. Este va a contener options con el nombre del municipio y como value la posición en el array.

Form.js

OpendataSoft nos va a devolver un array de objetos, cada objeto va a ser un municipio. Dentro de cada objeto vamos a tener información del tipo: coordenadas, provincia, comunidad autónoma etc.

objetomapa

Para acceder al servicio y poder disponer de esta información utilizamos Axios.

*Es buena práctica tener un documento Global.js para guardar en un objeto todas las url que vamos a utilizar.

Según cargamos el componente vamos a llamar al método que accede al servicio:

componentDidMount=()=>{
this.listarMunicipios();
}

listarMunicipios=()=>{

axios.get(urlOpendata).then(res=>{

//res.data nos devuelve la información de la imagen de arriba

this.setState({

municipios: res.data.records // si observamos en la imagen de arriba, records nos devuelve todos los objetos de municipio, por lo que estamos guardando un array de objetos

})

})

}

Lo que tenemos que hacer ahora es pintar cada uno de los municipios. Para ello, nos dirigimos al render() y recorremos this.state.municipios.

quedaría asi:

this.state.municipios.map((municipio, i)=>{

return(

<option value={i} >{municipio.info.fields.municipio}</option>

)

})

Una vez tenemos impreso el select en el html, podemos realizar la búsqueda y así poder mostrar en el mapa un Marker.

Como tenemos en el state.comunidades el array de objetos de la búsqueda, vamos a utilizarlo para no tener que realizar otra petición al servicio. Al disponer de la posición en el array (el value del option es la posición) vamos a acceder a la información concreta de dicho array con ayuda del índice.

index= React.createRef(); // referencia al select seleccionado del formulario de búsqueda

buscarMunicipio(e)=>{

e.preventDefault();

let objMunicipio= this.state.municipio[index]

// guardamos del objeto la información que vayamos a utilizar

this.setState({

coordenadas:  { 

latobjMunicipio.geometry.coordinates[1],

 lngobjMunicipio.geometry.coordinates[0]

 },

provincia: objMunicipio.fields.provincia,

municipioobjMunicipio.fields.municipio,           

 cpobjMunicipio.fields.codigo_postal,

})

}

Una vez que tenemos en el state todo lo que necesitamos, importamos el componente MapComponent y le enviamos cada una de las propiedades para poder reflejarlas en el mapa.

esto quedaría así:

  <Mapcomponent provincia={this.state.provinciacp={this.state.cp}  municipio={this.state.municipiocoordenadas={this.state.coordenadas} />

MapComponent.js

Desde MapComponent vamos a recibir mediante props los parámetros anteriores.

constructor(props) {    

super(props);

this.state = {      

coordenadas: props.coordenadas,      
zoom: 7,      
cp: props.cp   

 }

Vamos colocando cada parámetro en su lugar dentro de<MapContainer>

<MapContainer center={this.props.coordenadas} zoom={this.state.zoom}>

<TileLayer

attribution=’&copy; <a href=»http://osm.org/copyright»>OpenStreetMap</a> contributors’  
url=»https://dev.{s}.tile.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png»

/>

 <Marker 
position={this.props.coordenadas
icon={Iconlocation}
>            
<Popup>              
<div className=»card-body»>               
<h5 className=»card-title»>Provincia: {this.props.provincia} </h5>                
<h5 className=»card-title»>Municipio: {this.props.municipio}</h5>                
<p className=»»>Lat: {this.props.coordenadas.lat}</p>                
<p>Long: {this.props.coordenadas.lng}</p>                
<h6>El tiempo</h6>                
<Aemet cp={this.props.cp} />             
</div>            
</Popup>          
</Marker>

</MapContainer>

Acceso a Api Aemet

Para poder cargar la temperatura en nuestro <Popup> vamos a acceder a Aemet con Axios.

Lo que necesitamos es el cp del municipio seleccionado, este lo obtenemos mediante los props que hemos recibido.

Creamos un componente nuevo, lo llamaremos Aemet y recibirá el cp.
Vamos a añadirlo dentro de popup.

<MapContainer>
<Popup>
<Aemet cp={this.props.cp/>  

Aemet.js

Según se crea el componente vamos a realizar la búsqueda:

componentDidMount=()=>{
this.tiempoMunicipio();
}

temperatura


tiempoMunicipio=()=>{

axios.get(urlAemet).then(res=>{

// res.data = https://opendata.aemet.es/opendata/sh/cfaea297
//la primera petición devuelve una URL del servicio al que vamos a acceder
return res.data;

}).then(res =>{

axios.get(res).then(res=>{

// nos devuelve la información de la imagen de arriba, ahora queremos acceder a la temperatura
var resultado = res.data[0].prediccion.dia[0].temperatura;

this.setState({                            
status: true,                            
temperatura: { max: resultado .maxima, min: resultado .minima }                       
  })

})

})

}

Como lo hemos guardado en el state, vamos a pintarlo en el render para que sea visible el resultado desde el componente MapComponet.

render(){
return(
<h6> 
Máximas: {this.state.temperatura.max}º, 
Mínimas: {this.state.temperatura.min}º
</h6>
)
}

Resultado

resultado


Autor: Carlota Lobo Sanz

Curso: Desarrollo Web Full Stack, MultiCloud y Multiplataforma 

Centro: Tajamar 

Año académico: 2020-2021 

GitHub: https://github.com/carlotaLobo/REACT-POST-LEAFLET.git

URL SERVICIOS:

 

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.