6.2.Servicios web Geonames -Terremotos
Visualizador de terremotos
Atencion!!
Nos han encargado realizar un mapa mundial para visualizar los últimos terremotos acontecidos
-
Sabemos que GeoNames.org tiene un servicio JSON para interrogar los terremotos
-
Podemos utilizar el estilo dark de fondo
-
El estilo de Mapbox tiene un tipo "circle" que puedo cambiar de color y tamaño
https://docs.mapbox.com/mapbox-gl-js/style-spec/#layers-circle
Paso 1: Servicio GeoNames
-
Geonames.org Buscamos el servicio de terremotos y cuál es su implementación
-
https://www.geonames.org/export/JSON-webservices.html#earthquakesJSON
Paso 2:
-
Crearemos el archivo terremotos.html
-
Añadimos código con mapa base "dark"
<html>
<head>
<meta charset='utf-8' />
<title>Terremotos</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<link href='css/estilobase.css' rel='stylesheet' />
<script>
var map;
function init() {
mapboxgl.accessToken = "pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA";
map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [9.746, 40.473],
zoom: 5.5,
hash: true,
pitch: 0,
attributionControl: false
});
map.addControl(new mapboxgl.AttributionControl({
compact: true
}));
map.addControl(new mapboxgl.NavigationControl());
} //fin init
</script>
</head>
<body onload="init()">
<div id='map'></div>
</body>
</html>
Paso 3:Creamos archivo JS
- Dentro de nuestro directorio /geoweb/js/ creamos el archivo terremotos.js, dónde crearemos funciones especificas de nuestro proyect
- Dentro de nuestro directorio /geoweb/js/ creamos el archivo utils.js , dónde crearemos funciones genéricas que puedan ser reutilizadas
Paso 4. Añadimos JS
- Añadimos estos archivos (de momento vacíos) a terremotos.html
<html>
<head>
<meta charset='utf-8' />
<title>Terremotos</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<link href='css/estilobase.css' rel='stylesheet' />
<script src='js/utils.js'></script>
<script src='js/terremotos.js'></script>
<script>
var map;
function init() {
mapboxgl.accessToken = "pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA";
map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [9.746, 40.473],
zoom: 5.5,
hash: true,
pitch: 0,
attributionControl: false
});
map.addControl(new mapboxgl.AttributionControl({
compact: true
}));
map.addControl(new mapboxgl.NavigationControl());
} //fin init
</script>
</head>
<body onload="init()">
<div id='map'></div>
</body>
</html>
Paso 5: función genérica GET
-
Dentro del archivo js/utils.js vamos a crear una función asíconcrona genérica para enviar y recibir respuesta de cualquier servicio GET que retorne un JSON
-
async function
: Es un funcion en JavaScript que retornará un valor sólo cuando haya recibido la respuesta -
fetch
: La API Fetch proporciona una interfaz JavaScript para acceder y manipular partes del canal HTTP, tales como peticiones y respuestas https://developer.mozilla.org/es/docs/Web/API/Fetch_API/Utilizando_Fetch. Para hacer peticiones tipo Ajax
async function enviarPeticion(url) {
return fetch(url)
.then(function (response) {
return response.json()
})
.then(function (data) {
//console.log('Respuesta', data);
return data;
}).catch(function (error) {
console.log('Error', error);
alert("Error peticion");
return null;
});
}
Paso 6 :convertir la respuesta de JSON GeoNames al formato GeoJSON
-
Creamos una función para convertir la respuesta de JSON GeoNames al formato GeoJSON en terremotos.js
-
Ejemplo peticion: https://secure.geonames.org/earthquakesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&username=masterupc
-
Estructura respuesta GeoNames
{
"earthquakes":[
{
"datetime":"2011-03-11 04:46:23",
"depth":24.4,
"lng":142.369,
"src":"us",
"eqid":"c0001xgp",
"magnitude":8.8,
"lat":38.322
},
{
"datetime":"2012-04-11 06:38:37",
"depth":22.9,
"lng":93.0632,
"src":"us",
"eqid":"c000905e",
"magnitude":8.6,
"lat":2.311
},
{
"datetime":"2007-09-12 09:10:26",
"depth":30,
"lng":101.3815,
"src":"us",
"eqid":"2007hear",
"magnitude":8.4,
"lat":-4.5172
}
]
}
-
Miramos web https://geojson.io cómo és un GeoJSON
-
Deberíamos convertir con código el JSON de GeoNames a un GeoJSon de puntos
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"datetime":"2011-03-11 04:46:23", "magnitude":8.8},
"geometry": {
"type": "Point",
"coordinates": [
142.369,
38.322
]
}
},
{
"type": "Feature",
"properties": {"datetime":"2012-04-11 06:38:37","magnitude":8.6},
"geometry": {
"type": "Point",
"coordinates": [
93.0632,
2.311
]
}
},
{
"type": "Feature",
"properties": {"datetime":"2007-09-12 09:10:26","magnitude":8.4},
"geometry": {
"type": "Point",
"coordinates": [
101.3815,
-4.5172
]
}
}
]
}
Si tuvieramos que realizar reproyecciones o operaciones espaciales
Paso 6.1 : Función terremotosGeonamesToGeoJSON()
- Creamos dentro de /js/terremotos.js la funcion terremotosGeonamesToGeoJSON
function terremotosGeonamesToGeoJSON(respuestaGeonames){
var geoJSON ={
"type": "FeatureCollection",
"features": []
};
for (var i =0; i < respuestaGeonames.earthquakes.length; i++){
geoJSON.features.push(
{
"type": "Feature",
"properties": {"magnitude":respuestaGeonames.earthquakes[i].magnitude,
"datetime":respuestaGeonames.earthquakes[i].datetime },
"geometry": {
"type": "Point",
"coordinates": [
respuestaGeonames.earthquakes[i].lng,
respuestaGeonames.earthquakes[i].lat
]
}
}
);
} //fin loop
return geoJSON;
} //fin funcion
Paso 7 : Función generarPeticionTerremotos()
- Vamos a añadir otra funcion dentro de terremotos.js para:
- Capturar las coordenadas de mapa (BoundigBox)
- Crear la petición a Geonames
- Enviar petición
- Capturar la respuesta y convertirla a GeoJSON
- Generar Source y Layer de Mapbox Style y añadir datos
Justo debajo toda de la función terremotosGeonamesToGeoJSON() añadimos"
function generarPeticionTerremotos() {
var peticion = 'https://secure.geonames.org/earthquakesJSON?' +
'north=' + map.getBounds()._ne.lat + '&' +
'south=' + map.getBounds()._sw.lat + '&' +
'east=' + map.getBounds()._ne.lng + '&' +
'west=' + map.getBounds()._sw.lng + '&' +
'maxRows=50&' +
'minMagnitude=5&' +
'username=masterupc&';
//date : 'yyyy-MM-d
enviarPeticion(peticion).then(function (respuestaGeonames) {
var geoJSON = terremotosGeonamesToGeoJSON(respuestaGeonames);
if (!map.getSource("terremotos_source")) {
map.addSource("terremotos_source", {
type: "geojson",
data: geoJSON
});
map.addLayer({
'id': 'terremotos',
'type': 'circle',
'source': 'terremotos_source',
'paint': {
'circle-color': [
'interpolate',
['linear'],
['get', 'magnitude'],
3, '#ebe709',
5, '#eb1809',
7, '#ef4bf2',
],
'circle-opacity': 0.75,
'circle-radius': [
'interpolate',
['linear'], ['get', 'magnitude'],
3, 8,
5, 16,
8, 32
]
}
});
map.addLayer({
'id': 'terremotos-textos',
'type': 'symbol',
'source': 'terremotos_source',
'layout': {
'text-field': [
'format', ['get', 'magnitude'],
],
'text-size': 10
},
'paint': {
'text-color': 'rgba(255,255,255,1)'
}
});
} else {
map.getSource("terremotos_source").setData(geoJSON);
}
});
} // fin funcion
Paso 8:La función generarPeticionTerremotos()
-
La función generarPeticionTerremotos() és la función principal que necesitamos que se ejecute:
- Al cargar el mapa (evento
load
) - Cada vez que me muevo por el mapa (eventos
moveend
yzoomend
)
- Al cargar el mapa (evento
<html>
<head>
<meta charset='utf-8' />
<title>Terremotos</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<link href='css/estilobase.css' rel='stylesheet' />
<script src='js/utils.js'></script>
<script src='js/terremotos.js'></script>
<script>
var map;
function init() {
mapboxgl.accessToken ='pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [9.746, 40.473],
zoom: 5.5,
hash: true,
pitch: 0,
attributionControl: false
});
map.addControl(new mapboxgl.AttributionControl({
compact: true
}));
map.addControl(new mapboxgl.NavigationControl());
map.on("load", function () {
generarPeticionTerremotos();
}); // fin load mapa
map.on("zoomend", function () {
generarPeticionTerremotos();
});
map.on("moveend", function () {
generarPeticionTerremotos();
});
} //fin init
</script>
</head>
<body onload="init()">
<div id='map'></div>
</body>
</html>
Paso 9:función para generar popups
- Dentro del archivo utils.js añadimos una función para enseñar popup, pero NO al hacer click sino simplemente al passar por encima
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
function addPopupToMap(nombreCapa) {
map.on('mousemove', nombreCapa, function (e) {
var text = "";
//console.info(e);
for (key in e.features[0].properties) {
text += "<b>" + key + "</b>:" + e.features[0].properties[key] + "<br>";
}
popup.setLngLat(e.lngLat)
.setHTML(text)
.addTo(map);
});
map.on('mouseenter', nombreCapa, function () {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', nombreCapa, function () {
map.getCanvas().style.cursor = '';
popup.remove();
});
}// fin funcion
Paso 10: Llamamos a la funcion addPopupToMap()
- Llamamos a la funcion addPopupToMap() pasando el nombre de nuestra capa activa:
<html>
<head>
<meta charset='utf-8' />
<title>Terremotos</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<link href='css/estilobase.css' rel='stylesheet' />
<script src='js/utils.js'></script>
<script src='js/terremotos.js'></script>
<script>
var map;
function init() {
mapboxgl.accessToken ='pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [9.746, 40.473],
zoom: 5.5,
hash: true,
pitch: 0,
attributionControl: false
});
map.addControl(new mapboxgl.AttributionControl({
compact: true
}));
map.addControl(new mapboxgl.NavigationControl());
map.on("load", function () {
generarPeticionTerremotos();
addPopupToMap("terremotos");
}); // fin load mapa
map.on("zoomend", function () {
generarPeticionTerremotos();
});
map.on("moveend", function () {
generarPeticionTerremotos();
});
} //fin init
</script>
</head>
<body onload="init()">
<div id='map'></div>
</body>
</html>

¿Podemos añadir canviar a projection:globe el mapa
¿Podemos añadir un color más para terremotos de más 8 magnitud?
¿Podemos cambiar dinamicamente el valor minMagnitude de la petición a GeoNames?
Sabrías añadir este geojson de placas tectónicas como una capa más
¿Añadimos Titulo?
¿Subimos el ejemplo al GitHub?
git pull
git add .
git commit -m "terremotos"
git push