From d6c9f5e781674b5a12f5066c90d451b20b25010b Mon Sep 17 00:00:00 2001 From: Tatiana Villa Ema Date: Mon, 27 Apr 2026 01:11:48 +0200 Subject: [PATCH] fix: wind rose usa vientoDireccion camelCase, muestra vel. media por sector --- frontend/index.html | 1 + frontend/js/estadisticas.js | 94 +++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index c0a0bd0..92b6a5c 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -126,6 +126,7 @@
+

diff --git a/frontend/js/estadisticas.js b/frontend/js/estadisticas.js index 839cebc..31211f0 100644 --- a/frontend/js/estadisticas.js +++ b/frontend/js/estadisticas.js @@ -260,48 +260,71 @@ function renderTrend(data) { let windRoseChart = null; function renderWindRose(data) { - const sectors = [ - { label: "N", min: 337.5, max: 360 }, - { label: "N", min: 0, max: 22.5 }, - { label: "NE", min: 22.5, max: 67.5 }, - { label: "E", min: 67.5, max: 112.5 }, - { label: "SE", min: 112.5, max: 157.5 }, - { label: "S", min: 157.5, max: 202.5 }, - { label: "SO", min: 202.5, max: 247.5 }, - { label: "O", min: 247.5, max: 292.5 }, - { label: "NO", min: 292.5, max: 337.5 } + const sectorDefs = [ + { label: "N", min: 337.5, max: 360 }, + { label: "N", min: 0, max: 22.5 }, + { label: "NE", min: 22.5, max: 67.5 }, + { label: "E", min: 67.5, max: 112.5 }, + { label: "SE", min: 112.5, max: 157.5 }, + { label: "S", min: 157.5, max: 202.5 }, + { label: "SO", min: 202.5, max: 247.5 }, + { label: "O", min: 247.5, max: 292.5 }, + { label: "NO", min: 292.5, max: 337.5 } ]; - // Filtrar por mes seleccionado y agrupar por día para no contar duplicados horarios + const labels = ["N", "NE", "E", "SE", "S", "SO", "O", "NO"]; + + // Agrupar lecturas por día y mes seleccionado + // vientoDireccion viene en camelCase desde Spring Boot (sin @JsonProperty) const byDay = {}; data.forEach(d => { const date = new Date(d.dia); - if (date.getMonth() === selectedMonth) { - if (!byDay[d.dia]) byDay[d.dia] = []; - byDay[d.dia].push(parseFloat(d.viento_direccion)); - } + if (date.getMonth() !== selectedMonth) return; + if (!byDay[d.dia]) byDay[d.dia] = { dirs: [], speeds: [] }; + const dir = parseFloat(d.vientoDireccion ?? d.viento_direccion ?? 0); + const spd = parseFloat(d.viento_velocidad ?? 0); + byDay[d.dia].dirs.push(dir); + byDay[d.dia].speeds.push(spd); }); - // Por cada día usar la dirección media del día - const direcciones = Object.values(byDay).map(dirs => { - return dirs.reduce((a, b) => a + b, 0) / dirs.length; - }); + // Por cada día: dirección media y velocidad media + const readings = Object.values(byDay).map(day => ({ + dir: day.dirs.reduce((a, b) => a + b, 0) / day.dirs.length, + spd: day.speeds.reduce((a, b) => a + b, 0) / day.speeds.length + })); - // Contar frecuencia por sector (N agrupa los dos rangos) - const counts = { N: 0, NE: 0, E: 0, SE: 0, S: 0, SO: 0, O: 0, NO: 0 }; - direcciones.forEach(deg => { - for (const s of sectors) { - if (deg >= s.min && deg < s.max) { + // Acumular frecuencia y velocidad media por sector + const counts = {}; + const speedSum = {}; + labels.forEach(l => { counts[l] = 0; speedSum[l] = 0; }); + + readings.forEach(({ dir, spd }) => { + for (const s of sectorDefs) { + if (dir >= s.min && dir < s.max) { counts[s.label]++; + speedSum[s.label] += spd; break; } } }); - const labels = ["N", "NE", "E", "SE", "S", "SO", "O", "NO"]; - const values = labels.map(l => counts[l]); - const accent = "rgba(164, 215, 244, 0.75)"; - const border = "rgba(164, 215, 244, 1)"; + const values = labels.map(l => counts[l]); + const avgSpeed = labels.map(l => counts[l] ? (speedSum[l] / counts[l]).toFixed(1) : 0); + + // Dirección dominante + const dominant = labels.reduce((best, l) => counts[l] > counts[best] ? l : best, labels[0]); + const totalDays = readings.length; + const globalAvgSpeed = totalDays + ? (readings.reduce((s, r) => s + r.spd, 0) / totalDays).toFixed(1) + : 0; + + // Actualizar subtítulo bajo la gráfica + const infoEl = $("wind-rose-info"); + if (infoEl) { + infoEl.textContent = totalDays + ? `Dominante: ${dominant} · Vel. media: ${globalAvgSpeed} km/h` + : "Sin datos"; + } const canvas = $("wind-rose"); if (!canvas) return; @@ -314,8 +337,8 @@ function renderWindRose(data) { labels, datasets: [{ data: values, - backgroundColor: labels.map(() => accent), - borderColor: labels.map(() => border), + backgroundColor: "rgba(164, 215, 244, 0.65)", + borderColor: "rgba(164, 215, 244, 1)", borderWidth: 1 }] }, @@ -325,15 +348,18 @@ function renderWindRose(data) { legend: { display: false }, tooltip: { callbacks: { - label: ctx => ` ${ctx.label}: ${ctx.raw} días` + label: ctx => { + const l = ctx.label; + return ` ${l}: ${ctx.raw} días · vel. media ${avgSpeed[ctx.dataIndex]} km/h`; + } } } }, scales: { r: { - ticks: { color: "#888", font: { size: 10 }, backdropColor: "transparent" }, - grid: { color: "rgba(255,255,255,0.1)" }, - pointLabels: { color: "#a4d7f4", font: { size: 12 } } + ticks: { color: "#666", font: { size: 10 }, backdropColor: "transparent" }, + grid: { color: "rgba(255,255,255,0.08)" }, + pointLabels: { color: "#a4d7f4", font: { size: 13, weight: "bold" } } } } }