NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Avistamientos de aves en el mar Menor // @namespace http://tampermonkey.net/ // @version 3.0 // @description Introduce un mapa con los avistamientos de aves registrados en el mar Menor. También muestra datos abiertos sobre el estado del agua de la laguna. // @author Paula González Martínez // @match https://es.wikipedia.org/* // @icon https://www.google.com/s2/favicons?sz=64&domain=wikipedia.org // @license GPL-3.0-or-later // @resource leaflet_css https://unpkg.com/leaflet@1.7.1/dist/leaflet.css // @resource legend_css https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.Legend-master/src/leaflet.legend.css // @resource own_css https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/styles.css // @resource markercluster_css https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.markercluster-1.4.1/dist/MarkerCluster.css // @resource markerclusterdefault_css https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.markercluster-1.4.1/dist/MarkerCluster.Defaults.css // @require https://unpkg.com/leaflet@1.7.1/dist/leaflet.js // @require https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/echarts.min.js // @require https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.Legend-master/src/leaflet.legend.js // @require https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/heatmap.js-2.0.5/build/heatmap.js // @require https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/heatmap.js-2.0.5/plugins/leaflet-heatmap/leaflet-heatmap.js // @require https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.markercluster-1.4.1/dist/leaflet.markercluster.js // @grant GM_getResourceText // @grant GM_addStyle // @grant GM_addElement // ==/UserScript== // CSS // Cargar mi propio CSS cargarCSS("own_css"); // Cargar LeafletCSS cargarCSS("leaflet_css"); // Cargar Legend CSS cargarCSS("legend_css"); // Cargar MarkerCluster CSS cargarCSS("markerclusterdefault_css"); cargarCSS("markercluster_css"); // ---------------------------------------------------------------------------------------------------------------------------- // JAVASCRIPT // Cargar Leaflet loadScript("https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"); // Cargar plugin Heatmap loadScript("https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/heatmap.js-2.0.5/build/heatmap.js"); loadScript("https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/heatmap.js-2.0.5/plugins/leaflet-heatmap/leaflet-heatmap.js"); // Cargar plugin MarkerCluster loadScript("https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.markercluster-1.4.1/dist/leaflet.markercluster.js"); // Cargar libreria Echarts loadScript("https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/echarts.min.js"); // Cargar plugin Leyenda loadScript("https://raw.githubusercontent.com/lucyleia28/AvistamientosAvesMarMenor/main/Leaflet.Legend-master/src/leaflet.legend.js"); // ---------------------------------------------------------------------------------------------------------------------------- // VALORES GENERALES // Ruta pagina actual var pathname = window.location.pathname; // Listado especies que mostraran la informacion del mapa const lista_pathname = ["/wiki/Larus_genei", "/wiki/Tadorna_tadorna", "/wiki/Anas_platyrhynchos", "/wiki/Podiceps_cristatus", "/wiki/Gallinula_chloropus", "/wiki/Himantopus_himantopus", "/wiki/Pluvialis_squatarola", "/wiki/Charadrius_alexandrinus", "/wiki/Charadrius_hiaticula", "/wiki/Charadrius_dubius", "/wiki/Arenaria_interpres", "/wiki/Calidris_ferruginea", "/wiki/Calidris_alba", "/wiki/Calidris_alpina", "/wiki/Calidris_minuta", "/wiki/Tringa_nebularia", "/wiki/Tringa_totanus", "/wiki/Chroicocephalus_genei", "/wiki/Chroicocephalus_ridibundus", "/wiki/Larus_michahellis", "/wiki/Sternula_albifrons", "/wiki/Hydroprogne_caspia", "/wiki/Sterna_hirundo", "/wiki/Ardea_cinerea", "/wiki/Ardea_alba", "/wiki/Egretta_garzetta", "/wiki/Apus_apus", "/wiki/Cecropis_daurica", "/wiki/Delichon_urbicum", "/wiki/Oenanthe_oenanthe", "/wiki/Columba_livia", "/wiki/Streptopelia_decaocto", "/wiki/Apus_pallidus", "/wiki/Thalasseus_sandvicensis", "/wiki/Phalacrocorax_carbo", "/wiki/Gulosus_aristotelis", "/wiki/Hirundo_rustica", "/wiki/Curruca_melanocephala", "/wiki/Sturnus_unicolor", "/wiki/Turdus_merula", "/wiki/Erithacus_rubecula", "/wiki/Passer_domesticus", "/wiki/Motacilla_alba", "/wiki/Emberiza_calandra", "/wiki/Phoenicopterus_roseus", "/wiki/Recurvirostra_avosetta", "/wiki/Galerida_cristata", "/wiki/Columba_palumbus", "/wiki/Falco_tinnunculus", "/wiki/Lanius_senator", "/wiki/Galerida_theklae", "/wiki/Phylloscopus_bonelli", "/wiki/Ficedula_hypoleuca", "/wiki/Chloris_chloris", "/wiki/Linaria_cannabina", "/wiki/Burhinus_oedicnemus", "/wiki/Ichthyaetus_audouinii", "/wiki/Myiopsitta_monachus", "/wiki/Cisticola_juncidis", "/wiki/Serinus_serinus", "/wiki/Alectoris_rufa", "/wiki/Streptopelia_turtur", "/wiki/Platalea_leucorodia", "/wiki/Merops_apiaster", "/wiki/Phylloscopus_trochilus", "/wiki/Curruca_iberiae", "/wiki/Muscicapa_striata", "/wiki/Actitis_hypoleucos", "/wiki/Ciconia_ciconia", "/wiki/Curruca_communis", "/wiki/Carduelis_carduelis", "/wiki/Tringa_glareola", "/wiki/Phoenicurus_phoenicurus", "/wiki/Gelochelidon_nilotica", "/wiki/Upupa_epops", "/wiki/Calandrella_brachydactyla", "/wiki/Alauda_arvensis", "/wiki/Cettia_cetti", "/wiki/Bubulcus_ibis", "/wiki/Parus_major", "/wiki/Acrocephalus_schoenobaenus", "/wiki/Sturnus_vulgaris", "/wiki/Calidris_pugnax", "/wiki/Haematopus_ostralegus", "/wiki/Circus_aeruginosus", "/wiki/Glareola_pratincola", "/wiki/Numenius_phaeopus", "/wiki/Nycticorax_nycticorax", "/wiki/Apus_melba", "/wiki/Ardeola_ralloides", "/wiki/Plegadis_falcinellus", "/wiki/Calidris_temminckii", "/wiki/Circus_pygargus", "/wiki/Saxicola_rubicola", "/wiki/Aythya_ferina", "/wiki/Ardea_purpurea", "/wiki/Acrocephalus_scirpaceus", "/wiki/Chlidonias_niger", "/wiki/Ixobrychus_minutus", "/wiki/Pica_pica", "/wiki/Corvus_monedula", "/wiki/Acrocephalus_arundinaceus", "/wiki/Luscinia_megarhynchos", "/wiki/Curruca_undata", "/wiki/Spatula_clypeata", "/wiki/Numenius_arquata", "/wiki/Falco_naumanni", "/wiki/Fulica_atra", "/wiki/Lanius_meridionalis", "/wiki/Chlidonias_hybrida", "/wiki/Motacilla_flava", "/wiki/Tringa_ochropus"]; const marMenor_pathname = "/wiki/Mar_Menor"; // Comprueba que la ruta de la pagina actual este dentro del array de rutas afectadas if (lista_pathname.includes(pathname)) { let mapContainer = crearContenedorMapaLateral(); crearMapa("especifico", mapContainer); } else if(pathname.includes(marMenor_pathname)){ let mapContainer = crearContenedorMapaGeneral(); crearMapa("general", mapContainer); } // ---------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------FUNCIONES------------------------------------------------------------ // ---------------------------------------------------------------------------------------------------------------------------- // Cargar archivos/ficheros // Cargar css function cargarCSS(string){ const css = GM_getResourceText(string); GM_addStyle(css); } // Cargar javascript function loadScript(scriptURL) { 'use strict'; function httpGetAsync(theUrl, callback) { var xmlHttp = new XMLHttpRequest(); xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) callback(xmlHttp.responseText); } xmlHttp.open("GET", theUrl, true); // true for asynchronous xmlHttp.send(null); } return new Promise(function(resolve){ httpGetAsync(scriptURL, function(response){ var s = document.createElement("script"); s.text = response; document.getElementsByTagName("head")[0].appendChild(s); resolve(); }); }); } // ---------------------------------------------------------------------------------------------------------------------------- // Mapas general y especificos // Crear mapa (funcion principal) async function crearMapa(tipo, mapContainer){ // Vista inicial de mi mapa: N, W, y el zoom o altura let zoom = 11; if (tipo == "general") { zoom = 11.5; } let map = L.map('map').setView([37.7325, -0.7790], zoom); // Capa con el mapa base de openstreetmap que se le anyade a map let base = addLayerBase(map); // Agregar area Mar Menor con el punto donde está la boya let area = addLayerArea(map); // Agregar escala let escala = addLayerEscala(map); // MarkerCluster var markers = L.markerClusterGroup({ iconCreateFunction: function(cluster) { var childCount = cluster.getChildCount(); var c = 'marker-cluster marker-cluster-'; if (childCount > 0 && childCount <= 2) { c += 'smallest'; } else if (childCount > 2 && childCount <= 5) { c += 'smaller'; } else if (childCount > 5 && childCount <= 10) { c += 'normal'; } else if (childCount > 10 && childCount <= 15) { c += 'big'; } else if (childCount > 15) { c += 'max'; } return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className: c, style: 'border: solid 2px rgba(0, 0, 0, 0.4y);', iconSize: new L.Point(40, 40) }); } }); // Guia numero de avistamientos addRegistros(); // Llamar a las funciones para mostrar las graficas con los botones del estado del agua llamarGetEstadoMar(); // Listado de codigos de las zonas de avistamientos en el Mar Menor let regionCode = ["L5237105", "L5157229", "L5485879", "L4652966", "L4548723", "L5246392", "L5610561", "L6773140", "L5170203", "L5287538", "L5171766", "L5170186", "L19816002", "L19829303"]; // Periodo observaciones let periodoObservacion = document.querySelector('input[name="periodo"]:checked').value; // Agregar evento cambiar fecha let periodo = document.getElementsByName("periodo"); // Obtener listados de aves y zonas const listadoAves = document.getElementById("listadoAves"); let listadoZonas = ""; let mapaCalor = document.getElementById("mapaCalor"); switch (tipo) { case "especifico": var speciesName = getNombreEspecie(); getAves(map, markers, regionCode, periodoObservacion, speciesName); setListadoZonas(map, markers, regionCode, periodoObservacion, speciesName); // Agregar un controlador de eventos de cambio a cada radio for (var i = 0; i < periodo.length; i++) { periodo[i].addEventListener("change", function() { // Obtener el valor del radio seleccionado var selectedValue = document.querySelector('input[name="periodo"]:checked').value; // Llamar a la función actualizarFecha() con el valor seleccionado como parámetro actualizarFecha(map, markers, regionCode, selectedValue, "especifico"); deseleccionarMapaCalor(map); }); } // Agregar evento a las casillas Listado Zonas listadoZonas = document.getElementById("listadoZonasLateral"); listadoZonas.addEventListener("change", function(event) { if (event.target.classList.contains("check_zonas")) { actualizarMarcadores(map, markers, regionCode, document.querySelector('input[name="periodo"]:checked').value, "zonas-especificas"); } }); // Agregar mapa de calor mapaCalor.addEventListener("change", function() { if (this.checked) { addMapaCalor(map, markers, regionCode, document.querySelector('input[name="periodo"]:checked').value, "especifico"); } else { deseleccionarMapaCalor(map); } }); break; case "general": obtenerObservaciones(map, markers, regionCode, periodoObservacion); setListados(map, markers, regionCode, periodoObservacion, "aves-zonas"); // Agregar evento a las casillas Listado Aves listadoAves.addEventListener("change", function(event) { if (event.target.classList.contains("check_aves")) { actualizarMarcadores(map, markers, regionCode, document.querySelector('input[name="periodo"]:checked').value, "aves"); } }); // Agregar evento a las casillas Listado Zonas listadoZonas = document.getElementById("listadoZonas"); listadoZonas.addEventListener("change", function(event) { if (event.target.classList.contains("check_zonas")) { actualizarMarcadores(map, markers, regionCode, document.querySelector('input[name="periodo"]:checked').value, "zonas"); } }); // Agregar un controlador de eventos de cambio a cada radio for (var j = 0; j < periodo.length; j++) { periodo[j].addEventListener("change", function() { // Obtener el valor del radio seleccionado var selectedValue = document.querySelector('input[name="periodo"]:checked').value; // Llamar a la función actualizarFecha() con el valor seleccionado como parámetro actualizarFecha(map, markers, regionCode, selectedValue, "general"); deseleccionarMapaCalor(map); }); } // Agregar mapa de calor mapaCalor.addEventListener("change", function() { if (this.checked) { addMapaCalor(map, markers, regionCode, document.querySelector('input[name="periodo"]:checked').value, "general"); } else { deseleccionarMapaCalor(map); } }); break; default: console.log("ERROR"); } // Se anyade el mapa al contenedor mapContainer.insertAdjacentHTML("afterbegin", map); } function crearContenedorMapaLateral(){ const infobox = document.getElementsByClassName("infobox")[0]; let body = infobox.firstChild; let filas = body.childNodes; let ultimo = filas[filas.length-1]; // Titulo nueva fila var hilera_titulo = document.createElement("tr"); hilera_titulo.innerHTML = '<th colspan="3" style="text-align:center;background-color: #FF9800;"><a href="https://es.wikipedia.org/wiki/Mar_Menor" style="color: #2C2C2C; text-decoration: none;" title="Avistamientos mar Menor">Avistamientos en el mar Menor</a></th>'; body.insertBefore(hilera_titulo, ultimo); // Inserto el enlace al mapa antes del ultimo elemento // Cuerpo nueva fila var hilera_enlace = document.createElement("tr"); hilera_enlace.innerHTML = '<th colspan="3"><a href="https://es.wikipedia.org/wiki/Mar_Menor" title="Enlace al mar Menor">Ver mar Menor</a></th>'; body.insertBefore(hilera_enlace, ultimo); // Insertar mapa let mapContainer = document.createElement("div"); mapContainer.id = "map"; mapContainer.style = "height: 35em; width: 25em"; hilera_enlace.firstChild.appendChild(mapContainer); // Informacion mapa let infoContainer = document.createElement("div"); infoContainer.id = "infoLateral"; /*let infoElements = document.createElement("div"); infoElements.id = "infoLateralElements";*/ infoContainer.innerHTML = `<h3>Zonas de avistamientos</h3> <div id="listadoZonasLateral"></div> <h3>Fecha avistamientos</h3> <div id="contenedorBotones"> <input type="radio" id="fechaHoy" class="fecha" name="periodo" value="hoy"/> <label for="fechaHoy" class="boton">Hoy</label> <input type="radio" id="fechaSemana" class="fecha" name="periodo" value="semana" checked /> <label for="fechaSemana" class="boton">Última semana</label> <input type="radio" id="fechaMes" class="fecha" name="periodo" value="mes" /> <label for="fechaMes" class="boton">Último mes</label> </div> <h3>Número de avistamientos</h3> <div id="listadoAvistamientos"></div> <input id="mapaCalor" type="checkbox" name="calor" style="margin-bottom: 20px;"/> Mostrar mapa de calor <h3>Estado del agua</h3> <p> Consulta las gráficas sobre el estado del agua </p> <div id="botonesGraficasLateral"> <button class="estadoAgua" value="temperatura">Temperatura</button> <button class="estadoAgua" value="oxigeno">Oxígeno</button> <button class="estadoAgua" value="salinidad">Salinidad</button> <button class="estadoAgua" value="turbidez">Turbidez</button> <button class="estadoAgua" value="transparencia">Transparencia</button> <button class="estadoAgua" value="clorofila">Clorofila</button> </div>`; // Modal para graficas let modal = document.createElement("div"); modal.id = "grafica"; hilera_enlace.firstChild.appendChild(modal); hilera_enlace.firstChild.appendChild(infoContainer); return mapContainer; } function crearContenedorMapaGeneral(){ /*----------ARREGLO TRAS LA ACTUALIZACIÓN DEL FORMATO DE WIKIPEDIA----------*/ // Obtener todos los elementos h2 en la página const h2Elementos = document.getElementsByTagName('h2'); // Seleccionar el primer elemento h2 de la lista const primerElementoH2 = h2Elementos[1]; // Crear un nuevo elemento const seccion_avistamientos = document.createElement("div"); seccion_avistamientos.id = "seccion_avistamientos"; // Insertar el nuevo elemento justo antes del primer h2 primerElementoH2.parentNode.insertBefore(seccion_avistamientos, primerElementoH2); /*--------------------------------------------------------------------------*/ // Insertar titulo let title = document.createElement("h2"); title.innerHTML = '<span class="mw-headline" id="Avistamientos">Avistamiento de aves en el Mar Menor</span><span class="mw-editsection"></span>'; // Insertar mapa let mapContainer = document.createElement("div"); mapContainer.id = "map"; // Informacion mapa let infoContainer = document.createElement("div"); infoContainer.id = "info"; let infoElements = document.createElement("div"); infoElements.id = "infoElements"; infoElements.innerHTML = `<h3>Zonas de avistamientos</h3> <div id="listadoZonas"></div> <h3>Especies avistadas</h3> <div id="listadoAves"></div> <h3>Fecha avistamientos</h3> <div id="contenedorBotones"> <input type="radio" id="fechaHoy" class="fecha" name="periodo" value="hoy"/> <label for="fechaHoy" class="boton">Hoy</label> <input type="radio" id="fechaSemana" class="fecha" name="periodo" value="semana" checked /> <label for="fechaSemana" class="boton">Última semana</label> <input type="radio" id="fechaMes" class="fecha" name="periodo" value="mes" /> <label for="fechaMes" class="boton">Último mes</label> </div> <h3>Número de avistamientos</h3> <div id="listadoAvistamientos"></div> <input id="mapaCalor" type="checkbox" name="calor" style="margin-bottom: 20px;"/> Mostrar mapa de calor <h3>Estado del agua</h3> <p> Consulta las gráficas sobre el estado del agua </p> <div id="botonesGraficas"> <button class="estadoAgua" value="temperatura">Temperatura</button> <button class="estadoAgua" value="oxigeno">Oxígeno</button> <button class="estadoAgua" value="salinidad">Salinidad</button> <button class="estadoAgua" value="turbidez">Turbidez</button> <button class="estadoAgua" value="transparencia">Transparencia</button> <button class="estadoAgua" value="clorofila">Clorofila</button> </div>`; infoContainer.appendChild(infoElements); // Div para mapa general let mapaGeneral = document.createElement("div"); mapaGeneral.id = "mapaGeneral"; mapaGeneral.appendChild(mapContainer); mapaGeneral.appendChild(infoContainer); // Div para informacion avistamientos let info = document.createElement("div"); info.id = "infoUbicacion"; // Modal para graficas let modal = document.createElement("div"); modal.id = "grafica"; let seccion = document.getElementById("seccion_avistamientos"); seccion.appendChild(title); seccion.appendChild(mapaGeneral); seccion.appendChild(info); seccion.appendChild(modal); return mapContainer } // ---------------------------------------------------------------------------------------------------------------------------- // Listados con los datos de los avistamientos // Agregar listados de aves async function setListados(map, markers, regionCode, date, type) { var data = await obtenerObservacionesInfo(map, markers, regionCode, date); var species = []; var regions = []; switch (type) { case "aves-zonas": species = []; regions = []; data.forEach(observation => { var idSpecies = observation.sciName.replace(" ", "").toLowerCase(); if(!species.includes(idSpecies) && observation.howMany > 0){ species.push(idSpecies); document.getElementById("listadoAves").innerHTML += `<label> <input type="checkbox" id="${idSpecies}" name="aves" class="check_aves" \> ${observation.sciName} <span class="checkmark"></span> </label>`; } var idRegion = observation.locId.toLowerCase(); if(!regions.includes(idRegion) && observation.howMany > 0){ regions.push(idRegion); document.getElementById("listadoZonas").innerHTML += `<label> <input type="checkbox" id="${idRegion}" name="zonas" class="check_zonas" \> ${observation.locName} <span class="checkmark"></span> </label>`; } }); if (regions.length < 1 && species.length < 1) { document.getElementById("listadoZonas").innerHTML = `<label>No se han registrado observaciones en esta fecha</label>`; document.getElementById("listadoAves").innerHTML = `<label>No se han registrado observaciones en esta fecha</label>`; } break; case "aves": species = []; data.forEach(observation => { var idSpecies = observation.sciName.replace(" ", "").toLowerCase(); if(!species.includes(idSpecies) && observation.howMany > 0){ species.push(idSpecies); document.getElementById("listadoAves").innerHTML += `<label> <input type="checkbox" id="${idSpecies}" name="aves" class="check_aves" \> ${observation.sciName} <span class="checkmark"></span> </label>`; } }); if (species.length < 1) { document.getElementById("listadoAves").innerHTML = `<label>No se han registrado observaciones en esta fecha</label>`; } break; case "zonas": regions = []; data.forEach(observation => { var idRegion = observation.locId.toLowerCase(); if(!regions.includes(idRegion) && observation.howMany > 0){ regions.push(idRegion); document.getElementById("listadoZonas").innerHTML += `<label> <input type="checkbox" id="${idRegion}" name="zonas" class="check_zonas" \> ${observation.locName} <span class="checkmark"></span> </label>`; } }); if (regions.length < 1) { document.getElementById("listadoZonas").innerHTML = `<label>No se han registrado observaciones en esta fecha</label>`; } break; } } // Agregar listados de zonas async function setListadoZonas(map, markers, regionCode, date, speciesName) { var regions = []; var data = await obtenerObservacionesInfo(map, markers, regionCode, date); data.forEach(observation => { // Comprueba que sea la misma especie que la pasada por parámetro y que hayan avistamientos if(observation.sciName.toLowerCase() === speciesName.toLowerCase() && observation.howMany > 0){ var idRegion = observation.locId.toLowerCase(); if(!regions.includes(idRegion)){ regions.push(idRegion); document.getElementById("listadoZonasLateral").innerHTML += `<label> <input type="checkbox" id="${idRegion}" name="zonas" class="check_zonas" \> ${observation.locName} <span class="checkmark"></span> </label>`; } } }); if (regions.length < 1) { document.getElementById("listadoZonasLateral").innerHTML = `<label>No se han registrado observaciones en esta fecha</label>`; } } // ---------------------------------------------------------------------------------------------------------------------------- // Informacion nombres y fecha // Obtener el nombre de una especie function getNombreEspecie(){ const valorEspecie = window.location.pathname.split("/")[2].split("_"); const nombreEspecie = valorEspecie[0] + " " + valorEspecie[1]; return nombreEspecie; } // Formato habitual fecha function formatoFecha(date) { let fecha = date.split(" ")[0]; return fecha.split("-")[2] + "/" + fecha.split("-")[1] + "/" + fecha.split("-")[0]; } // Actualizar la fecha de los avistamientos async function actualizarFecha(map, markers, regionCode, date, type) { switch (type) { case "general": markers.clearLayers(); document.getElementById("listadoAves").innerHTML = ""; document.getElementById("listadoZonas").innerHTML = ""; await obtenerObservaciones(map, markers, regionCode, date); setListados(map, markers, regionCode, date, "aves-zonas"); break; case "especifico": var speciesName = getNombreEspecie(); markers.clearLayers(); document.getElementById("listadoZonasLateral").innerHTML = ""; getAves(map, markers, regionCode, date, speciesName); setListadoZonas(map, markers, regionCode, date, speciesName); break; } } // ---------------------------------------------------------------------------------------------------------------------------- // Dibujar mapa // Dibujar marcadores async function actualizarMarcadores(map, markers, regionCode, date, type) { // Obtener especies seleccionadas var especiesSeleccionadas = Array.from(document.querySelectorAll('input.check_aves:checked')) .map((checkbox) => checkbox.id); var zonasSeleccionadas = Array.from(document.querySelectorAll('input.check_zonas:checked')) .map((checkbox) => checkbox.id); if (especiesSeleccionadas.length > 0 && zonasSeleccionadas.length > 0) { type = "zonas-aves"; } else if (especiesSeleccionadas.length < 1 && zonasSeleccionadas.length < 1 && type != "zonas-especificas") { type = "limpiar"; } switch (type) { case "aves": var dataAves = await obtenerObservacionesInfo(map, markers, regionCode, date); var regionCodes = []; var speciesIds = []; if (especiesSeleccionadas.length > 0) { // Limpiar los marcadores existentes markers.clearLayers(); // Recorrer las especies seleccionadas y agregar sus observaciones correspondientes dataAves.forEach(observation => { for (const especieSeleccionada of especiesSeleccionadas) { if (observation.sciName.toLowerCase().replace(" ", "") === especieSeleccionada && observation.howMany > 0) { if (!speciesIds.includes(observation.sciName)) { speciesIds.push(observation.sciName); } if (!regionCodes.includes(observation.locId) && speciesIds.includes(observation.sciName)) { regionCodes.push(observation.locId); } } } }); // Agregar evento a las casillas Listado Aves document.getElementById("listadoZonas").innerHTML = ""; for (var i=0; i<speciesIds.length; i++) { getAves(map, markers, regionCodes, date, speciesIds[i]); } setListados(map, markers, regionCodes, date, "zonas"); } else { markers.clearLayers(); actualizarMarcadores(map, markers, regionCode, date, "zonas"); } break; case "zonas": var dataZonas = await obtenerObservacionesInfo(map, markers, regionCode, date); var regionCodeIds = []; if (zonasSeleccionadas.length > 0) { // Limpiar los marcadores existentes markers.clearLayers(); // Recorrer las especies seleccionadas y agregar sus observaciones correspondientes dataZonas.forEach(observation => { for (const zonaSeleccionada of zonasSeleccionadas) { if (observation.locId.toLowerCase() === zonaSeleccionada && observation.howMany > 0) { if (!regionCodeIds.includes(observation.locId)) { regionCodeIds.push(observation.locId); } } } }); // Agregar evento a las casillas Listado Aves document.getElementById("listadoAves").innerHTML = ""; await obtenerObservaciones(map, markers, regionCodeIds, date); setListados(map, markers, regionCodeIds, date, "aves"); } else { markers.clearLayers(); actualizarMarcadores(map, markers, regionCode, date, "aves"); } break; case "zonas-especificas": var zonasSeleccionadasEspe = Array.from(document.querySelectorAll("input.check_zonas:checked")) .map((checkbox) => checkbox.id); var dataZonasEspe = await obtenerObservacionesInfo(map, markers, regionCode, date); var regionCodeIdsEspe = []; var speciesName = getNombreEspecie(); if (zonasSeleccionadasEspe.length > 0) { // Limpiar los marcadores existentes markers.clearLayers(); // Recorrer las especies seleccionadas y agregar sus observaciones correspondientes dataZonasEspe.forEach(observation => { for (const zonaSeleccionadaEspe of zonasSeleccionadasEspe) { if (observation.locId.toLowerCase() === zonaSeleccionadaEspe && observation.howMany > 0) { if (!regionCodeIdsEspe.includes(observation.locId)) { regionCodeIdsEspe.push(observation.locId); } } } }); getAves(map, markers, regionCodeIdsEspe, date, speciesName); } else { markers.clearLayers(); getAves(map, markers, regionCode, date, speciesName); } break; case "zonas-aves": var data = await obtenerObservacionesInfo(map, markers, regionCode, date); var regions = []; // Limpiar los marcadores existentes markers.clearLayers(); // Recorrer las especies seleccionadas y agregar sus observaciones correspondientes data.forEach(observation => { for (const zonaSeleccionada of zonasSeleccionadas) { for (const especieSeleccionada of especiesSeleccionadas) { if (observation.locId.toLowerCase() === zonaSeleccionada && observation.sciName.toLowerCase().replace(" ", "") === especieSeleccionada && observation.howMany > 0) { addLayerPunto(map, markers, observation); } } } }); break; case "limpiar": markers.clearLayers(); document.getElementById("listadoAves").innerHTML = ""; document.getElementById("listadoZonas").innerHTML = ""; await obtenerObservaciones(map, markers, regionCode, date); setListados(map, markers, regionCode, date, "aves"); setListados(map, markers, regionCode, date, "aves-zonas"); break; } } // Dibujar el mapa base de Leaflet function addLayerBase(map){ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 13, attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); return map; } // Dibujar el area del mar menor function addLayerArea(map){ // Agregar capa con el area del mar Menor fetch("https://raw.githubusercontent.com/lucyleia28/marmenor.github.io/main/areaMarMenor.json") .then(res => res.json()) .then(response => { var marMenor = response; var marMenorJS = L.geoJson(marMenor).addTo(map); // Agregar leyenda Interactiva (Si se pone aquí se controla si se dibuja o no al seleccionarlo en la leyenda) let leyenda = addLayerLeyenda(map, marMenorJS, marMenor); }); } // Dibujar puntos de observaciones function addLayerPunto(map, markers, observation){ // Agregar puntos de avistamientos let color = ""; let url = ""; if(observation.howMany <= 2){ color = "#8F9CA0"; url = ""; } else if(observation.howMany > 2 && observation.howMany <= 5){ color = "#C7E466"; url = ""; } else if(observation.howMany > 5 && observation.howMany <= 10){ color = "#FAC500"; url = ""; } else if(observation.howMany > 10 && observation.howMany <= 15){ color = "#E57701"; url = ""; } else if(observation.howMany > 15){ color = "#E33B15"; url = ""; } else{ color = "black"; url = ""; } var puntoObservacion = L.circleMarker(L.latLng(observation.lat, observation.lng), { radius: 8, fillColor: color, color: "black", weight: 2, opacity: 1, fillOpacity: 1, }); var popupContent = ""; if (pathname.includes(marMenor_pathname)) { // General popupContent += "<strong>Especie:</strong> " + observation.sciName + "<br>" + "<strong>Fecha último avistamiento:</strong> " + formatoFecha(observation.obsDt) + "<br>" + "<strong>Cantidad de aves:</strong> " + observation.howMany + "<br>" + "<strong>Ubicación:</strong> " + observation.locName + "<br>" + "<strong>Coordenadas:</strong> <br> Latitud: " + observation.lat + ", Longitud: " + observation.lng + "<br>" + "<strong>Enlace:</strong> <a href='https://es.wikipedia.org/wiki/" + observation.sciName.split(" ")[0]+"_"+observation.sciName.split(" ")[1] + "' target='_blank'>Ver en Wikipedia</a>"; } else { // Especifico popupContent += "<strong>Fecha último avistamiento:</strong> " + formatoFecha(observation.obsDt) + "<br>" + "<strong>Cantidad de aves:</strong> " + observation.howMany + "<br>" + "<strong>Ubicación:</strong> " + observation.locName + "<br>" + "<strong>Coordenadas:</strong> <br> Latitud: " + observation.lat + ", Longitud: " + observation.lng; } puntoObservacion.bindPopup(popupContent); puntoObservacion.on("click", function() { puntoObservacion.openPopup(); }); markers.addLayer(puntoObservacion); map.addLayer(markers); } // Dibujar la escala del mapa function addLayerEscala(map){ var escala = new L.control.scale({ imperial: false, position: "bottomright" }).addTo(map); return escala; } // Dibujar la leyenda del mapa function addLayerLeyenda(map, marMenorJS, marMenor){ // Agregar la leyenda var leyenda = new L.control.Legend({ id: "leyenda", title: "Leyenda", position: "topright", collapsed: false, symbolWidth: 24, opacity: 1, column: 1, legends: [{ label: "Mar Menor", type: "rectangle", color: "#0074f0", fillColor: "#009ff0", weight: 2, layers: marMenorJS, marMenor }] }).addTo(map); // Agregar la ID "leyenda" al elemento HTML de la leyenda leyenda._container.setAttribute("id", "leyenda"); return leyenda; } // Agregar la guia de colores por numero de avistamientos function addRegistros() { document.getElementById("listadoAvistamientos").innerHTML += `<div class="avistamiento"> <div class="avistamientoItem rojo"></div> <div class="avistamientoLabel"> <div class="avistamientoTitulo">15+</div> </div> </div> <div class="avistamiento"> <div class="avistamientoItem naranja"></div> <div class="avistamientoLabel"> <div class="avistamientoTitulo">10 - 15</div> </div> </div> <div class="avistamiento"> <div class="avistamientoItem amarillo"></div> <div class="avistamientoLabel"> <div class="avistamientoTitulo">5 - 10</div> </div> </div> <div class="avistamiento"> <div class="avistamientoItem verde"></div> <div class="avistamientoLabel"> <div class="avistamientoTitulo">2 - 5</div> </div> </div> <div class="avistamiento"> <div class="avistamientoItem gris"></div> <div class="avistamientoLabel"> <div class="avistamientoTitulo">1 - 2</div> </div> </div>`; } // ---------------------------------------------------------------------------------------------------------------------------- // Mapa de calor // Desdibujar el mapa de calor al deseleccionarlo function deseleccionarMapaCalor(map) { document.getElementById("mapaCalor").checked = false; map.eachLayer(function(layer) { if (layer instanceof HeatmapOverlay) { map.removeLayer(layer); } }); } // Obtener las coordenadas de los lugares del mapa para representar el mapa de calor async function getCoordenadasMapaCalor(map, markers, regionCode, date, type) { var data = await obtenerObservacionesInfo(map, markers, regionCode, date); // Recorrer las especies seleccionadas y agregar sus observaciones correspondientes const total = {}; switch (type) { case "especifico": var speciesName = getNombreEspecie(); data.forEach(observation => { for (const region of regionCode) { if (observation.sciName === speciesName && observation.locId === region && observation.howMany > 0) { if (!total[region]) { total[region] = { total: 0, coordenadas: { lat: observation.lat, lng: observation.lng } }; } else { total[region].coordenadas.lat = observation.lat; total[region].coordenadas.lng = observation.lng; } total[region].total += observation.howMany; } } }); break; case "general": data.forEach(observation => { for (const region of regionCode) { if (observation.locId === region && observation.howMany > 0) { if (!total[region]) { total[region] = { total: 0, coordenadas: { lat: observation.lat, lng: observation.lng } }; } else { total[region].coordenadas.lat = observation.lat; total[region].coordenadas.lng = observation.lng; } total[region].total += observation.howMany; } } }); break; } return total; } // Dibujar mapa de calor async function addMapaCalor(map, markers, regionCode, date, type) { const totalCoordenadas = await getCoordenadasMapaCalor(map, markers, regionCode, date, type); let data = []; for (const coordenada in totalCoordenadas) { data.push({lat: totalCoordenadas[coordenada].coordenadas.lat, lng: totalCoordenadas[coordenada].coordenadas.lng, count: totalCoordenadas[coordenada].total}); } var coordenadas = { max: 200, min: 0, data: data, length: 11 }; var config = { // radius should be small ONLY if scaleRadius is true (or small radius is intended) // if scaleRadius is false it will be the constant radius used in pixels "radius": 0.03, "maxOpacity": .8, // scales the radius based on map zoom "scaleRadius": true, // if set to false the heatmap uses the global maximum for colorization // if activated: uses the data maximum within the current map boundaries // (there will always be a red spot with useLocalExtremas true) "useLocalExtrema": true, // which field name in your data represents the latitude - default "lat" latField: 'lat', // which field name in your data represents the longitude - default "lng" lngField: 'lng', // which field name in your data represents the data value - default "value" valueField: 'count' }; var heatmapLayer = new HeatmapOverlay(config); heatmapLayer.setData(coordenadas); heatmapLayer.addTo(map); } // ---------------------------------------------------------------------------------------------------------------------------- // Obtener avistamientos de aves // Obtener la URL segun la fecha para hacer las peticiones function getEbirdUrl(date, regionCode) { let url = ""; const fechaActual = new Date(); const dia = fechaActual.getDate(); const mes = fechaActual.getMonth() + 1; // El +1 es porque los meses empiezan en 0 const anyo = fechaActual.getFullYear(); switch (date) { case "hoy": url = `https://api.ebird.org/v2/data/obs/${regionCode}/recent?back=1`; //historic/${anyo}/${mes}/${dia} break; case "mes": url = `https://api.ebird.org/v2/data/obs/${regionCode}/recent`; break; case "semana": url = `https://api.ebird.org/v2/data/obs/${regionCode}/recent?back=7`; break; } return url; } // Obtener y dibujar las observaciones de las aves de todas las especies (funcion intermedia) async function obtenerObservaciones(map, markers, regionCode, date) { return new Promise((resolve, reject) => { getAllAves(map, markers, regionCode, date) .then(observations => { resolve(observations); }) .catch(error => { reject(error); }); }); } // Obtener las observaciones de las aves de todas las especies (funcion intermedia) async function obtenerObservacionesInfo(map, markers, regionCode, date) { return new Promise((resolve, reject) => { getAllAvesInfo(map, markers, regionCode, date) .then(observations => { resolve(observations); }) .catch(error => { reject(error); }); }); } // Obtener y dibujar avistamientos de una especie en específico function getAves(map, markers, regionCodes, date, speciesName){ var myHeaders = new Headers(); myHeaders.append("X-eBirdApiToken", "so7u5sv82cup"); var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; // Hago la peticion fetch una vez por cada ubicacion del array regionCode for (let i = 0; i < regionCodes.length; i++) { const regionCode = regionCodes[i]; let url = getEbirdUrl(date, regionCode); fetch(url, requestOptions) .then(response => response.text()) .then(result => { var data = JSON.parse(result); data.forEach(observation => { // Comprueba que sea la misma especie que la pasada por parámetro y que hayan avistamientos if(observation.sciName.toLowerCase() === speciesName.toLowerCase() && observation.howMany > 0){ addLayerPunto(map, markers, observation); } }); }) .catch(error => console.log('error', error)); } } // Obtener y dibujar avistamientos de todas las especies function getAllAves(map, markers, regionCodes, date) { var myHeaders = new Headers(); myHeaders.append("X-eBirdApiToken", "so7u5sv82cup"); var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; // Objeto para almacenar los avistamientos const allObservations = {}; // Hago la peticion fetch una vez por cada ubicacion del array regionCode const fetchObservations = (regionCode) => { let url = getEbirdUrl(date, regionCode); return fetch(url, requestOptions) .then(response => response.text()) .then(result => { var data = JSON.parse(result); data.forEach(observation => { // Comprueba que hayan habido avistamientos en la ubicacion if (observation.howMany > 0) { // Agrega la observación al objeto allObservations if (!allObservations[observation.sciName]) { allObservations[observation.sciName] = {}; } if (!allObservations[observation.sciName][regionCode]) { allObservations[observation.sciName][regionCode] = ""; } allObservations[observation.sciName][regionCode] += observation.howMany + "," + observation.locName; addLayerPunto(map, markers, observation); } }); }) .catch(error => console.log('error', error)); }; const fetchPromises = regionCodes.map(fetchObservations); return Promise.all(fetchPromises).then(() => allObservations); } // Obtener la informacion de los avistamientos de todas las especies function getAllAvesInfo(map, markers, regionCodes, date) { var myHeaders = new Headers(); myHeaders.append("X-eBirdApiToken", "so7u5sv82cup"); var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; const fetchObservations = (regionCode) => { let url = getEbirdUrl(date, regionCode); return fetch(url, requestOptions) .then(response => response.text()) .then(result => JSON.parse(result)) .catch(error => console.log('error', error)); }; const fetchPromises = regionCodes.map(fetchObservations); // Array de objetos que representan los datos de avistamientos de aves para cada ubicación en el array regionCodes. return Promise.all(fetchPromises).then(data => data.flat()); // para que los datos obtenidos de la API se aplanen en un solo arreglo } // ---------------------------------------------------------------------------------------------------------------------------- // Obtener datos abiertos sobre el estado del Mar Menor // Llamar a la funcion getEstadoMar al pulsar uno de los botones. Esta funcion se crea porque no funciona esto otro: <button class="estadoAgua" onclick="getEstadoMar('temperatura')">Temperatura</button> function llamarGetEstadoMar(){ const botones = document.getElementsByClassName("estadoAgua"); for (let i=0; i<botones.length; i++) { botones[i].addEventListener('click', async function() { await getEstadoMar(botones[i].value); }); } } // Una primera llamada para obtener el total de records para obtener todos los datos registrados async function getTotalRecords(id) { const response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=" + id); const data = await response.json(); const totalRecords = data.result.total; return totalRecords; } // Obtener array de datos por parametro async function getEstadoMar(parameter) { let totalRecords = ""; let response = ""; let data = ""; let results = ""; switch (parameter) { case "temperatura": totalRecords = await getTotalRecords("dbafcaf1-820c-4fee-9209-e7dd10560a8b"); response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=dbafcaf1-820c-4fee-9209-e7dd10560a8b&limit=" + totalRecords); data = await response.json(); results = data.result.records; break; case "oxigeno": totalRecords = await getTotalRecords("bd3c2fd1-c1dc-41ec-906b-34bc5ff33f98"); response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=bd3c2fd1-c1dc-41ec-906b-34bc5ff33f98&limit=" + totalRecords); data = await response.json(); results = data.result.records; break; case "salinidad": totalRecords = await getTotalRecords("194638ff-adcd-4980-99a1-1be3b8b7030d"); response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=194638ff-adcd-4980-99a1-1be3b8b7030d&limit=" + totalRecords); data = await response.json(); results = data.result.records; break; case "turbidez": totalRecords = await getTotalRecords("c6824049-7bad-4128-9cc0-ab099af17009"); response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=c6824049-7bad-4128-9cc0-ab099af17009&limit=" + totalRecords); data = await response.json(); results = data.result.records; break; case "transparencia": totalRecords = await getTotalRecords("93de5a09-aea4-4897-91f7-f79a4d39394a"); response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=93de5a09-aea4-4897-91f7-f79a4d39394a&limit=" + totalRecords); data = await response.json(); results = data.result.records; break; case "clorofila": totalRecords = await getTotalRecords("2125cefc-7e9a-44a3-8086-1815e33750f9"); response = await fetch("https://datosabiertos.regiondemurcia.es/catalogo/api/action/datastore_search?resource_id=2125cefc-7e9a-44a3-8086-1815e33750f9&limit=" + totalRecords); data = await response.json(); results = data.result.records; break; } showMensajeModal(results, parameter); } // Mostrar mensaje modal para las graficas function showMensajeModal(values, parameter) { if (parameter == "oxigeno") { parameter = "oxígeno"; } document.getElementById("grafica").innerHTML = `<div id="modalVentana" class="modal"> <div class="modalContenido"> <span class="modalCerrar">×</span> <h2>Gráfica con los niveles de ${parameter}</h2> <div id="graficaContenido" style="width:700px;height:400px;margin-top:20px;margin-bottom:20px;"></div> <a id="datosAbiertos" href="https://datosabiertos.regiondemurcia.es/" target="_blank">Datos abiertos Región de Murcia</a> </div> </div>`; // Ventana modal var modal = document.getElementById("modalVentana"); modal.style.display = "block"; // Hace referencia al elemento <span> que tiene la X que cierra la ventana var span = document.getElementsByClassName("modalCerrar")[0]; // Si el usuario hace clic en la x, la ventana se cierra span.addEventListener("click", function() { modal.style.display = "none"; }); // Si el usuario hace clic fuera de la ventana, se cierra. window.addEventListener("click", function(event) { if (event.target == modal) { modal.style.display = "none"; } }); addGrafica(values, parameter); } // Dibujar grafica function addGrafica(values, parameter) { // Se crea un array con las fechas, otro con las medias y otro con las desviaciones // El método map() itera sobre cada elemento del array original y aplica una función a cada uno de ellos. // En este caso, la función que se aplica a cada elemento del array original es una función flecha que simplemente extrae el valor de una propiedad del objeto y lo añade a un nuevo array. const fechas = values.map(d => d.Fecha.split("T")[0]); const medias = values.map(d => d.Medias); const desviaciones = values.map(d => d.Desviaciones); // Se obtiene el elemento donde se introduce la grafica const grafica = echarts.init(document.getElementById("graficaContenido")); // Se configura la grafica const option = { title: { text: 'Parámetros físico-químicos-biológicos del Mar Menor: ' + parameter, subtext: 'Fuente: Comunidad Autónoma de la Región de Murcia' }, grid: { top: '25%' // ajusta este valor según necesites, }, tooltip: {}, legend: { data: ['Media', 'Desviación'], top: 'bottom' }, xAxis: { type: 'category', data: fechas }, yAxis: [{ type: 'value', name: 'Temperatura (°C)', }, { type: 'value', name: 'Desviación (°C)', }], series: [{ data: medias, type: 'line', name: 'Media', smooth: true, yAxisIndex: 0, }, { data: desviaciones, type: 'line', name: 'Desviación', smooth: true, yAxisIndex: 1, }] }; grafica.setOption(option); } // ----------------------------------------------------------------------------------------------------------------------------