Leer ficheros GeoJSON — II

Daremos estilo a los elementos que se obtienen como “feature” en los ficheros GeoJSON

Segunda parte donde hemos leído un fichero GeoJSON y hemos pintado la información con lo básico. Aquí personalizaremos los elementos sustituyendo el marcador por defecto dándole un toque más elegante y mejor presencia.

En este artículo seguiremos aprendiendo más aspectos de como podemos trabajar con los datos de GeoJSON. Anteriormente, hemos aprendido a leer el fichero GeoJSON y a añadir la opción de implementar un popup a cada elemento con la propiedad "onEachFeature" dentro de la capa geoJSON

Lo que vamos a aprender en este artículo es a sustituir los marcadores que viene por defecto por marcadores circulares que personalizaremos condicionalmente por su valor de la magnitud del terremoto. Así conseguiremos que los datos sean más fáciles de interpretar que si los dejamos tal y como están, que hasta que hacemos click no sabemos su intensidad.

Si tenéis curiosidad por los mapas y concretamente trabajar con Leaflet os dejo más artículos relacionados (que irá ampliando):

Requisitos

Para empezar con ello, lo primero que necesitaremos es cumplir estos requisitos:

Una vez que ya cumplimos estos requisitos sencillos, vamos a por el apartado de mejorar la interpretación de la información GeoJSON en nuestros mapas para hacerlo más personalizado y a nuestro gusto.

Antes de nada, si lo deseáis,. podéis iniciar el proyecto para tenerlo en marcha e ir haciendo los cambios y así poder ver el resultado paso a paso.

Para iniciar el proyecto, debemos de ejecutar:

npm start

Una vez ejecutado, se debe de abrir una nueva pestaña en nuestro navegador con esta apariencia:

Aclarado esto, para completar el objetivo, iremos paso a paso hasta llegar a este resultado:

Sustituir marcador por marcador circular

Lo que buscamos en este caso es sustituir el marcador básico que tenemos para mostrar la información con un elemento vectorial circular que nos permitirá añadir ese elemento y darle un radio mayor o menor dependiendo de la intensidad de la magnitud del terremoto para dar a entender a los usuarios que visualizan el mapa que el terremoto es más serio o menos dependiendo de ese radio.

Para realizar este primer paso, debemos de usar la propiedad “Point to layer” dentro de la capa geoJSON.

Lo que nos dice la documentación básicamente es lo siguiente:

Función que define cómo los puntos GeoJSON generan capas de que se muestran. Se llama internamente cuando se agregan datos, pasando la función de punto GeoJSON y su Latitud y Longitud. El valor predeterminado será un marcador predeterminado. Esto es lo que he mencionado al inicio del artículo, que si no se especifica nada, será un marcador.

Tal y como se especifica en la documentación la función será de este estilo:

function pointToLayer (feature (1), latlng (2) {
return marker(latlng); (3)
},

Lo que viene a ser:

  • (1): El elemento GeoJSON (Point, LineString,…). En este caso particular es un punto (Point) u ahí tendremos toda la info tal y como vimos en el artículo anterior dentro de la propiedad “features” que es un array con todos los elementos donde tenemos la información completa y donde utilizaremos “properties”:
  • (2): Latitud y longitud del elemento que se va a dibujar, esto lo tenemos que usar para añadir el valor al nuevo elemento vectorial.
  • (3): Marcador por defecto

Sabiendo como funciona el apartado de "pointToLayer" vamos a crear la función para dibujar un círculo que varia su radio dependiendo de su magnitud. Para que el radio coja un tamaño considerable y apreciable, vamos a multiplicar el valor de la magnitud por 4.5, quedando de la siguiente manera:

import {circleMarker} from 'leaflet';
...
function pointToLayer (feature: any, latlng: any) {
return circleMarker(latlng, { radius: 4.5 * feature.properties.mag });
}

Lo aplicamos al ejemplo que quedará de la siguiente manera:

Como se puede apreciar ha cambiado el elemento vectorial y ha diferencias entre unos y otros para visualizar la magnitud. Cuanto más radio tenga más magnitud tiene ese terremoto.

Conseguimos diferenciarlo algo aunque todavía es necesario hacerlo más visual y esto lo podemos hacer personalizando el color del elemento vectorial siguiendo unas condiciones.

Podemos hacer click en varios círculos para ver las diferencias. Por ejemplo, pulsando en uno bastante pequeño:

Y a continuación haciendo click en uno con mayor radio, que como se puede apreciar el valor de la magnitud es mayor y ahí se puede ver las diferencias entre uno y otro, pero sigue siendo insuficiente.

Colorear marcador circular en base a condicional

Lo que vamos a hacer es colorear de un color u otro dependiendo de unas condiciones que vamos a establecer posteriormente.

Los colores son elegidos al azar, podéis colorearlo como más os guste, no estará ni mejor ni peor, cuestión de gustos.

Los condicionales que voy a asignar, son los siguientes, y estos irán en base a la magnitud:

  • Valor desde 0 hasta 1 (no incluido): “white”
  • Valor desde 1 hasta 2 (no incluido): “green”
  • Valor desde 2 hasta 3 (no incluido): “#6e8c51”
  • Valor desde 3 hasta 4 (no incluido): “yellow”
  • Valor desde 4 hasta 5 (no incluido): “#f5d142”
  • Valor desde 5 hasta 6 (no incluido): “orange”
  • Valor desde 6 hasta 7 (no incluido): “red”
  • A partir de 7: “pink”

Este apartado personalizado será para pintar el color del relleno de todos los círculos dibujados en el mapa, que será lo siguiente:

Por lo tanto, vamos a dejar creada la función para obtener el color del relleno de los círculos que se dibujarán en los elementos del mapa:

// Para personalizar las zonas con diferentes colores
function getColor(numberValue: number) {
return numberValue >= 0 && numberValue < 1
? "white"
: numberValue >= 1 && numberValue < 2
? "green"
: numberValue >= 2 && numberValue < 3
? "#6e8c51"
: numberValue >= 3 && numberValue < 4
? "yellow"
: numberValue >= 4 && numberValue < 5
? "#f5d142"
: numberValue >= 5 && numberValue < 6
? "orange"
: numberValue >= 6 && numberValue < 7
? "red"
: "pink";
}

Ahora, tenemos que añadir el apartado para darle estilo que en este caso cogerá unas propiedades comunes para todos los círculos y pintará el relleno del círculo dependiendo de los valores de magnitud recibidos.

Las propiedades del círculo son las siguientes (recordad que estas propiedades están en la documentación especificadas en el apartado “Path” que es común para los elementos vectoriales):

  • fillColor: Color del relleno que se especifica de manera dinámica con la función que hemos creado para obtener el color dinámicamente.
  • weight: Ancho de los bordes en pixels.
  • opacity: Opacidad del borde, por defecto es 1, es decir, 100% por lo que no es transparente a menos que añadamos un valor comprendido entre 0 y 1, siendo 0 sin opacidad y 0.5 un 50% de opacidad.
  • color: Color del borde, valor por defecto: ‘#3388ff’
  • fillOpacity: Color del relleno, que estará ligado a "fillColor". Los valores de la opacidad serán de 0 a 1 siendo 0 un 0%, 0.5 un 50% y 1 un 100%.

Ahora para especificar el estilo del elemento individual (como hemos realizado para añadir el círculo en vez del marcador), tenemos que tener en cuenta la propiedad “style” dentro de las propiedades del elemento vectorial “geoJSON” siendo esta la estructura que debemos de seguir. recordad que esta propiedad es para especificar las propiedades del apartado “Path” de cualquier elemento vectorial como “circle”, “circleMarker” (el que estamos usando), “marker” y etc.:

function style(feature (1)) {
return {} (2)
},

(1): El elemento GeoJSON (Point, LineString,…) como se ha mencionado anteriormente.

(2): Las propiedades del path del elemento con el que estamos trabajando y esto será donde especifiquemos el fillColor, color,… mencionadas antes de este punto.

Por lo tanto, vamos a especificar la función style y la añadimos como propiedad del layer geoJSON:

function getColor(numberValue: number) {
return numberValue >= 0 && numberValue < 1
....
}
function style(feature: any) {
return {
fillColor: getColor(feature.properties.mag), // Llama a la función para colorear
weight: 1,
color: "white",
fillOpacity: 1, // Por defecto es 0.2, le damos para que no trasparente
};
}
...axios.get(
URL
).then((result) => {
const geoJsonValue = geoJSON(result.data, {
onEachFeature: bindPopup,
pointToLayer,
style, // <=====================
}).addTo(map);
....
});

Volvemos al navegador y lo que ya debemos de obtener es algo de este estilo:

¡Vaya cambio ha pegado a mejor! Faltarían pulir detalles como añadir un control de leyenda basándonos en los colores que se asignan a los elementos.

¿Cómo se puede hacer esto? Muy fácil, todas las claves para conseguir crear un control de leyenda lo tenéis en este artículo que publiqué hace unas semanas

Os dejo como siempre el código fuente de lo trabajado:

Sería interesante que en los comentarios añadáis vuestros comentarios con vuestros ejemplos, ¡¡seguro que podemos aprender de otros ejemplos!!

Extra

Viendo estos tres últimos artículos sobre Leaflet y llegados a este punto, ¿Seriáis capaces de añadir un control de leyenda para interpretar mejor los datos?

Un resultado podría ser lo siguiente que como se puede apreciar los datos de la leyenda están unidos a lo que pone en la leyenda y hace que a simple vista puedas identificar las intensidades aproximadas:

Os animo a que lo intentéis y luego podáis comparar con el resultado que añado yo:

Presencia en redes sociales.

Podéis encontrarme en las siguientes redes.

--

--

[{#frontend:[#mobile:{#android, #kotlin-java, #ionic}}, {#web:{#angular, #material, #bootstrap}}],{#backend: [{#graphql, #symfony,#express, #mongodb, #mysql}]}]

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Anartz Mugika Ledo🤗

[{#frontend:[#mobile:{#android, #kotlin-java, #ionic}}, {#web:{#angular, #material, #bootstrap}}],{#backend: [{#graphql, #symfony,#express, #mongodb, #mysql}]}]