Migra dal codice salvato in locale al codice condiviso

This commit is contained in:
Giuseppe Raffa
2026-01-06 17:36:58 +01:00
parent 8a88c31c75
commit ff1566d36b
30 changed files with 8985 additions and 0 deletions

386
plugin/public/graphs.html Normal file
View File

@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Previsioni - 7 giorni</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
color: #fff;
}
.header {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
padding: 20px 30px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.header h1 {
font-size: 24px;
font-weight: 600;
}
.header .status {
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
}
.status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #4ade80;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.controls {
padding: 20px 30px;
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.control-btn {
padding: 10px 20px;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
color: #fff;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
}
.control-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
}
.control-btn.active {
background: #3b82f6;
border-color: #3b82f6;
}
.dashboard {
padding: 20px 30px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
gap: 25px;
}
.chart-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 25px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.chart-card h3 {
margin-bottom: 20px;
font-weight: 500;
color: rgba(255, 255, 255, 0.9);
display: flex;
align-items: center;
gap: 10px;
}
.chart-card .icon {
font-size: 20px;
}
.chart-container {
position: relative;
height: 250px;
}
.stats-grid {
padding: 20px 30px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.stat-card .label {
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.stat-card .value {
font-size: 28px;
font-weight: 600;
margin-top: 5px;
}
.stat-card .unit {
font-size: 14px;
color: rgba(255, 255, 255, 0.5);
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
color: rgba(255, 255, 255, 0.5);
}
.no-data {
text-align: center;
padding: 40px;
color: rgba(255, 255, 255, 0.5);
}
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
.chart-card {
padding: 15px;
}
}
</style>
</head>
<body>
<div class="header">
<h1>📊 MEB Grafici Meteo</h1>
<div class="status">
<div class="status-dot"></div>
<span id="last-update">Aggiornamento...</span>
</div>
</div>
<div class="controls">
<button class="control-btn active" data-hours="24">24 Ore</button>
<button class="control-btn" data-hours="48">48 Ore</button>
<button class="control-btn" data-hours="168">7 Giorni</button>
<button class="control-btn" onclick="refreshData()">🔄 Aggiorna</button>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="label">🌡️ Temperatura Attuale</div>
<div class="value" id="current-temp">--</div>
<div class="unit" id="unit-temp">°C</div>
</div>
<div class="stat-card">
<div class="label">🌬️ Vento</div>
<div class="value" id="current-wind">--</div>
<div class="unit" id="unit-wind">km/h</div>
</div>
<div class="stat-card">
<div class="label">🌊 Altezza Onde</div>
<div class="value" id="current-waves">--</div>
<div class="unit" id="unit-waves">m</div>
</div>
<div class="stat-card">
<div class="label">💧 Umidità</div>
<div class="value" id="current-humidity">--</div>
<div class="unit" id="unit-humidity">%</div>
</div>
</div>
<div class="dashboard">
<div class="chart-card">
<h3><span class="icon">🌡️</span> Temperatura</h3>
<div class="chart-container">
<canvas id="temperatureChart"></canvas>
</div>
</div>
<div class="chart-card">
<h3><span class="icon">🌬️</span> Velocità Vento</h3>
<div class="chart-container">
<canvas id="windChart"></canvas>
</div>
</div>
<div class="chart-card">
<h3><span class="icon">🌊</span> Altezza Onde</h3>
<div class="chart-container">
<canvas id="waveChart"></canvas>
</div>
</div>
<div class="chart-card">
<h3><span class="icon">💧</span> Umidità</h3>
<div class="chart-container">
<canvas id="humidityChart"></canvas>
</div>
</div>
</div>
<script>
// Configurazione globale Chart.js
Chart.defaults.color = 'rgba(255, 255, 255, 0.7)';
Chart.defaults.borderColor = 'rgba(255, 255, 255, 0.1)';
let charts = {};
let selectedHours = 24;
// Opzioni comuni per i grafici
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false }
},
scales: {
x: {
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: { maxTicksLimit: 8 }
},
y: {
grid: { color: 'rgba(255, 255, 255, 0.05)' },
beginAtZero: false
}
},
elements: {
point: { radius: 2, hoverRadius: 5 },
line: { borderWidth: 2 }
}
};
// Inizializza grafici
function initCharts() {
const tempCtx = document.getElementById('temperatureChart').getContext('2d');
charts.temperature = new Chart(tempCtx, {
type: 'line',
data: { labels: [], datasets: [] },
options: chartOptions
});
const windCtx = document.getElementById('windChart').getContext('2d');
charts.wind = new Chart(windCtx, {
type: 'line',
data: { labels: [], datasets: [] },
options: chartOptions
});
const waveCtx = document.getElementById('waveChart').getContext('2d');
charts.wave = new Chart(waveCtx, {
type: 'line',
data: { labels: [], datasets: [] },
options: chartOptions
});
const humidityCtx = document.getElementById('humidityChart').getContext('2d');
charts.humidity = new Chart(humidityCtx, {
type: 'line',
data: { labels: [], datasets: [] },
options: chartOptions
});
}
// Aggiorna dati dai grafici
async function refreshData() {
try {
const response = await fetch(`/plugins/meb/api/graphs?hours=${selectedHours}`);
const data = await response.json();
if (data.temperature) {
charts.temperature.data = data.temperature;
charts.temperature.update('none');
}
if (data.windSpeed) {
charts.wind.data = data.windSpeed;
charts.wind.update('none');
}
if (data.waveHeight) {
charts.wave.data = data.waveHeight;
charts.wave.update('none');
}
if (data.humidity) {
charts.humidity.data = data.humidity;
charts.humidity.update('none');
}
// Aggiorna valori attuali
if (data.current) {
document.getElementById('current-temp').textContent =
data.current.temperature?.toFixed(1) ?? '--';
document.getElementById('current-wind').textContent =
data.current.windSpeed?.toFixed(1) ?? '--';
document.getElementById('current-waves').textContent =
data.current.waveHeight?.toFixed(2) ?? '--';
document.getElementById('current-humidity').textContent =
data.current.humidity?.toFixed(0) ?? '--';
}
// Aggiorna unità dinamiche
if (data.units) {
const { forecast, waves } = data.units;
if (forecast) {
document.getElementById('unit-temp').textContent = forecast.temperature || '°C';
document.getElementById('unit-wind').textContent = forecast.windSpeed || 'km/h';
document.getElementById('unit-humidity').textContent = forecast.humidity || '%';
}
if (waves) {
document.getElementById('unit-waves').textContent = waves.waveHeight || 'm';
}
}
document.getElementById('last-update').textContent =
`Ultimo aggiornamento: ${new Date().toLocaleTimeString('it-IT')}`;
} catch (error) {
console.error('Errore caricamento dati:', error);
document.getElementById('last-update').textContent = 'Errore connessione';
}
}
// Gestione pulsanti periodo
document.querySelectorAll('.control-btn[data-hours]').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.control-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
selectedHours = parseInt(btn.dataset.hours);
refreshData();
});
});
// Inizializzazione
document.addEventListener('DOMContentLoaded', () => {
initCharts();
refreshData();
// Aggiorna ogni 2 minuti
setInterval(refreshData, 2 * 60 * 1000);
});
</script>
</body>
</html>