// ==================== // Helper // ==================== function $(id) { return document.getElementById(id); } const monthNames = ["Enero","Febrero","Marzo","Abril","Mayo","Junio", "Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"]; let selectedMonth = new Date().getMonth(); // mes actual let ciudadActual = "Madrid"; // ciudad por defecto // const BASE_API = "https://aplicacionesdevanguardia.es/eltiempo/servidor/api-weather-fechas.php"; const BASE_API = "https://tatvil.es/apis/api/weather/filter"; function buildApiUrl({ ciudad, desde, hasta }) { const params = new URLSearchParams(); params.append("ciudad", ciudad); params.append("desde", desde); params.append("hasta", hasta); console.log("Construyendo URL con parámetros:", { ciudad, desde, hasta }); console.log("URL API:", `${BASE_API}?${params.toString()}`); return `${BASE_API}?${params.toString()}`; } // ==================== // Actualizar nombre de mes // ==================== function updateMonthHeader() { $("mes-nombre").textContent = monthNames[selectedMonth]; } // ==================== // Cargar datos desde la API // ==================== async function loadStats(options = {}) { try { const url = buildApiUrl({ ciudad: ciudadActual, ...options }); const response = await fetch(url); if (!response.ok) throw new Error("Error cargando datos: " + response.status); let data = await response.json(); if (!data || !data.length) throw new Error("Datos vacíos"); // --- FILTRADO POR CIUDAD --- data = data.filter(d => d.ciudad === ciudadActual); // --------------------------- renderMonthStats(data); renderTrend(data); } catch (err) { console.error(err); $("stats-location").textContent = "Error cargando datos"; } } async function loadToday() { try { const ahora = new Date(); const y = ahora.getFullYear(); const m = String(ahora.getMonth() + 1).padStart(2, "0"); const d = String(ahora.getDate()).padStart(2, "0"); const hoy = `${y}-${m}-${d}`; const url = buildApiUrl({ ciudad: ciudadActual, desde: hoy, hasta: hoy }); const response = await fetch(url); if (!response.ok) throw new Error("Error cargando hoy: " + response.status); let data = await response.json(); data = data ? data.filter(d => d.ciudad === ciudadActual) : []; // Si no hay datos de hoy, buscar el último día disponible if (!data.length) { const hace30 = new Date(ahora); hace30.setDate(hace30.getDate() - 30); const y2 = hace30.getFullYear(); const m2 = String(hace30.getMonth() + 1).padStart(2, "0"); const d2 = String(hace30.getDate()).padStart(2, "0"); const urlFallback = buildApiUrl({ ciudad: ciudadActual, desde: `${y2}-${m2}-${d2}`, hasta: hoy }); const r2 = await fetch(urlFallback); let data2 = await r2.json(); data2 = data2 ? data2.filter(d => d.ciudad === ciudadActual) : []; if (!data2.length) throw new Error("Sin datos recientes"); // Ordenar por fecha y tomar el último día data2.sort((a, b) => a.dia.localeCompare(b.dia)); const ultimoDia = data2[data2.length - 1].dia; data = data2.filter(d => d.dia === ultimoDia); } renderLastData(data); } catch (err) { console.error(err); } } // ==================== // Último dato // ==================== function renderLastData(data) { const last = data[data.length - 1]; $("last-date").textContent = last.dia; $("last-temp").textContent = last.temp_max + "°C / " + last.temp_min + "°C"; $("last-humidity").textContent = last.humedad + " %"; $("last-rain").textContent = last.lluvia + " mm"; $("last-wind").textContent = last.viento_velocidad + " km/h"; $("last-sunrise").textContent = last.amanecer; $("last-sunset").textContent = last.anochecer; $("stats-location").textContent = `Estadisticas de ${ciudadActual}`; } // ==================== // FASES LUNARES // ==================== function getMoonPhase() { const now = new Date(); const year = now.getFullYear(); const month = now.getMonth() + 1; const day = now.getDate(); const c = Math.floor(365.25 * year); const e = Math.floor(30.6 * (month + 1)); const jd = c + e + day - 694039.09; const phase = (jd / 29.53) % 1; const age = phase * 29.53; let phaseName = "", icon = ""; if (age < 1.84566) { phaseName = "Luna Nueva"; icon = "🌑"; } else if (age < 5.53699) { phaseName = "Creciente Iluminante"; icon = "🌒"; } else if (age < 9.22831) { phaseName = "Cuarto Creciente"; icon = "🌓"; } else if (age < 12.91963) { phaseName = "Gibosa Creciente"; icon = "🌔"; } else if (age < 16.61096) { phaseName = "Luna Llena"; icon = "🌕"; } else if (age < 20.30228) { phaseName = "Gibosa Menguante"; icon = "🌖"; } else if (age < 23.99361) { phaseName = "Cuarto Menguante"; icon = "🌗"; } else if (age < 27.68493) { phaseName = "Creciente Menguante"; icon = "🌘"; } else { phaseName = "Luna Nueva"; icon = "🌑"; } $("moon-phase").textContent = phaseName; $("moon-icon").textContent = icon; const today = new Date(); $("stats-location").textContent += ` | Hoy ${today.getDate()} de ${monthNames[today.getMonth()]} de ${today.getFullYear()}`; } // ==================== // Estadísticas del mes seleccionado // ==================== function renderMonthStats(data) { // Esta es la clave: filtrar por el mes seleccionado antes de calcular const monthData = data.filter(d => { const fechaDato = new Date(d.dia); return fechaDato.getMonth() === selectedMonth; }); if (!monthData.length) { // Si no hay datos, ponemos a cero para que no salgan cosas raras $("month-days").textContent = 0; return; } // Agrupar por día (el cron guarda varios registros por día) const byDay = {}; monthData.forEach(d => { const key = d.dia; // YYYY-MM-DD if (!byDay[key]) byDay[key] = { maxTemps: [], minTemps: [], lluvia: [], humedad: [] }; byDay[key].maxTemps.push(d.temp_max); byDay[key].minTemps.push(d.temp_min); byDay[key].lluvia.push(parseFloat(d.lluvia)); byDay[key].humedad.push(parseFloat(d.humedad)); }); const days = Object.values(byDay); const maxTemps = days.map(d => Math.max(...d.maxTemps)); const minTemps = days.map(d => Math.min(...d.minTemps)); // La lluvia del día es el máximo registrado ese día (acumulado), no la suma de todas las lecturas const lluviaPorDia = days.map(d => Math.max(...d.lluvia)); const lluviaTotal = lluviaPorDia.reduce((sum, v) => sum + v, 0); const lluviaMedia = lluviaTotal / days.length; const humedad = (days.reduce((sum, d) => sum + d.humedad.reduce((a, b) => a + b, 0) / d.humedad.length, 0) / days.length).toFixed(1); $("month-days").textContent = days.length; $("month-max").textContent = Math.max(...maxTemps) + "°C"; $("month-min").textContent = Math.min(...minTemps) + "°C"; $("month-rain").textContent = lluviaTotal.toFixed(1) + " mm (total) / " + lluviaMedia.toFixed(1) + " mm (media diaria)"; $("month-humidity").textContent = humedad + " % (media diaria)"; } // ==================== // Tendencia histórica // ==================== function renderTrend(data) { const byYear = {}; console.log("Datos recibidos para tendencia histórica:", data); // Agrupar datos por año+día para el mes seleccionado (el cron guarda varios registros por día) const byYearDay = {}; data.forEach(d => { const date = new Date(d.dia); if (date.getMonth() === selectedMonth) { const year = date.getFullYear(); const dayKey = d.dia; // YYYY-MM-DD if (!byYearDay[year]) byYearDay[year] = {}; if (!byYearDay[year][dayKey]) byYearDay[year][dayKey] = { max: [], min: [], rain: [] }; byYearDay[year][dayKey].max.push(d.temp_max); byYearDay[year][dayKey].min.push(d.temp_min); byYearDay[year][dayKey].rain.push(parseFloat(d.lluvia)); } }); // Reducir por día antes de agrupar por año Object.keys(byYearDay).forEach(year => { byYear[year] = { max: [], min: [], rain: [] }; Object.values(byYearDay[year]).forEach(day => { byYear[year].max.push(Math.max(...day.max)); byYear[year].min.push(Math.min(...day.min)); byYear[year].rain.push(Math.max(...day.rain)); }); }); const container = $("trend-container"); console.log("Datos agrupados por año para tendencia:", byYear); if (Object.keys(byYear).length === 0) { container.innerHTML = "
No hay datos históricos para este mes.
"; return; } let html = "| Año | Máx | Mín | Lluvia |
|---|---|---|---|
| ${year} | ${maxAvg}°C | ${minAvg}°C | ${rainTotal} mm |