MatrixMAP_monthly / index.html
JPLTedCas's picture
Update index.html
c8c725b verified
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Boston Scientific Dashboard</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
/* [MISMO CSS QUE ANTES - OMITIDO POR BREVEDAD] */
/* Paleta de colores corporativa */
:root {
--primary-blue: #0057b8;
--secondary-blue: #003f7f;
--light-gray: #f4f4f4;
--dark-gray: #333;
--highlight-yellow: #FFD700;
--danger-red: #FF0000;
--success-green: #008000;
}
/* Estilos generales */
body {
font-family: Arial, sans-serif;
background-color: var(--light-gray);
color: var(--dark-gray);
margin: 0;
padding: 0;
}
h1 {
text-align: center;
color: var(--primary-blue);
margin: 20px 0;
}
/*CAMBIO COLUMNAS*/
/* Contenedor principal con grid */
.dashboard {
display: grid;
grid-template-columns: 1fr 2fr 1fr;/*1fr;*/
grid-template-rows: auto auto auto;
gap: 20px;
padding: 20px;
}
/* Controles */
#controls {
grid-column: 1 / -1; /* Hacer que los controles ocupen todo el ancho */
display: flex;
justify-content: center;
align-items: center;
background: white;
padding: 15px; /* Aumentado padding */
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 20px; /* Añadido margen inferior */
flex-wrap: wrap; /* Permitir que los controles pasen a la siguiente línea si no caben */
}
#controls label {
margin: 0 5px 0 15px; /* Ajuste de margen para etiquetas */
}
#controls select {
padding: 8px;
font-size: 16px;
border: 2px solid var(--primary-blue);
border-radius: 5px;
background: white;
color: var(--dark-gray);
cursor: pointer;
margin: 5px; /* Añadido margen alrededor de los selectores */
}
/* Estilos del mapa */
#map {
height: 500px;
width: 100%;
border-radius: 10px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
}
/* Contenedor de gráficos */
.chart-container { /* Este contenedor ya no se usa directamente para los gráficos principales */
/* display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px; */
}
.chart-box {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
/* Los canvas dentro del chart-box se manejarán individualmente o por defecto */
}
canvas {
width: 100%;
/* Altura ajustada para mejor visualización cuando hay varios */
height: auto; /* Permitir que el contenedor defina la altura o usar ratio */
max-height: 250px; /* Limitar altura máxima si es necesario */
margin-bottom: 15px; /* Espacio entre gráficos dentro del mismo chart-box */
}
.chart-box canvas:last-child {
margin-bottom: 0; /* Quitar margen inferior al último canvas */
}
/* Responsive */
@media (max-width: 1200px) { /* Ajuste para pantallas medianas/grandes */
.dashboard {
grid-template-columns: 1fr 1fr; /* 2 columnas */
grid-template-rows: auto auto auto;
}
#map {
grid-column: 1 / -1; /* Mapa ocupa todo el ancho */
grid-row: 2; /* Mapa en la segunda fila */
}
.chart-box:nth-of-type(1) { /* Primer contenedor de gráficos */
grid-column: 1 / 2;
grid-row: 3;
}
.chart-box:nth-of-type(2) { /* Segundo contenedor de gráficos */
grid-column: 2 / 3;
grid-row: 3;
}
#controls {
grid-row: 1; /* Controles en la primera fila */
}
}
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr; /* 1 columna */
grid-template-rows: auto auto auto auto; /* Una fila para cada elemento principal */
}
#map, .chart-box, #controls {
grid-column: 1 / -1; /* Todos ocupan el ancho completo */
}
#controls { grid-row: 1; }
#map { grid-row: 2; }
.chart-box:nth-of-type(1) { grid-row: 3; } /* Primer chart-box */
.chart-box:nth-of-type(2) { grid-row: 4; } /* Segundo chart-box */
#controls {
flex-direction: column; /* Apilar controles verticalmente */
align-items: stretch; /* Estirar elementos */
}
#controls label {
margin: 10px 0 5px 0; /* Ajustar margen para layout vertical */
}
#controls select {
width: 100%; /* Ocupar todo el ancho disponible */
box-sizing: border-box; /* Incluir padding/border en el ancho */
}
}
</style>
</head>
<body>
<h1>Matrix - Dashboard</h1>
<!-- Controles -->
<div id="controls">
<label for="category">Status:</label>
<select id="category" onchange="updateMarkers()">
<option value="all">All</option>
<option value="assessment">Assessment</option>
<option value="deployment">In Deployment</option>
<option value="operative">Operative</option>
<option value="paused">Paused</option>
<option value="maintenance">Maintenance</option>
<option value="removed">Removed</option>
</select>
  
<label for="monthFrom">From:</label>
<select id="monthFrom" onchange="updateMarkers()">
<option value="1">Jan</option>
<option value="2">Feb</option>
<option value="3">Mar</option>
<!-- Podrías añadir más meses si creas más variables de datos -->
<option value="4">Apr</option>
</select>
  
<label for="monthTo">To:</label>
<select id="monthTo" onchange="updateMarkers()">
<option value="1">Jan</option>
<option value="2">Feb</option>
<option value="3" selected>Mar</option> <!-- Seleccionado por defecto -->
<!-- Podrías añadir más meses si creas más variables de datos -->
<option value="4">Apr</option>
</select>
</div>
<!-- Dashboard Grid -->
<div class="dashboard">
<div class="chart-box">
<canvas id="connectionsChart"></canvas>
<canvas id="webinarChart"></canvas>
<canvas id="recordingChart"></canvas>
</div>
<div id="map"></div>
<div class="chart-box">
<canvas id="supportTimeChart"></canvas>
<canvas id="webinarTime"></canvas>
<canvas id="recordingTime"></canvas>
</div>
</div>
<script>
// --- DATOS MENSUALES DE EJEMPLO ---
/*const locationsJan = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 11, avgSupportTime: 12, webinars: 1, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 7, avgSupportTime: 2, webinars: 1, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 1, avgSupportTime: 3, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 0, avgSupportTime: 0.5, webinars: 13, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "deployment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0} // Cambiado a deployment
];
const locationsFeb = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 21, avgSupportTime: 12, webinars: 3, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 5, avgSupportTime: 2, webinars: 6, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 13, avgSupportTime: 3, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 13, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Cambiado a maintenance
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Cambiado a deployment
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}
];
const locationsMar = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 13, avgSupportTime: 12, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0.5}, // Añadida grabación
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 5, avgSupportTime: 2, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 3, avgSupportTime: 3, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 1, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0}, // Cambiado a paused
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 3, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Vuelve a operative
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0} // Pasa a operative con datos
];*/
const locationsJan = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 11, avgSupportTime: 1, webinars: 1, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 7, avgSupportTime: 0.5, webinars: 1, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 1, avgSupportTime: 3, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 0, avgSupportTime: 0.5, webinars: 13, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 17, avgSupportTime: 1.50, webinars: 5, avgWebinarTime: 1 , recordings: 1, avgRecordingTime: 0.05},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "deployment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0} // Cambiado a deployment
];
const locationsFeb = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 21, avgSupportTime: 2, webinars: 3, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 5, avgSupportTime: 0.5, webinars: 6, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 13, avgSupportTime: 3, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 13, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Cambiado a maintenance
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 25, avgSupportTime: 0.23, webinars: 1, avgWebinarTime: 1 , recordings: 1, avgRecordingTime: 0.10},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Cambiado a deployment
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}
];
const locationsMar = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 13, avgSupportTime: 1, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0.5}, // Añadida grabación
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 5, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 3, avgSupportTime: 1, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 1, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0}, // Cambiado a paused
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 3, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Vuelve a operative
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 17, avgSupportTime: 0.32, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0} // Pasa a operative con datos
];
const locationsApr = [
{ name: "Ragusa", coords: [36.9257, 14.7244], category: "operative", connections: 8, avgSupportTime: 4, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0.5}, // Añadida grabación
{ name: "Seville", coords: [37.3886, -5.9823], category: "operative", connections: 4, avgSupportTime: 1.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Groningen", coords: [53.2194, 6.5665], category: "operative", connections: 5, avgSupportTime: 1.7, webinars: 4, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0},
{ name: "Cape Town", coords: [-33.9249, 18.4241], category: "operative", connections: 4, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 1 , recordings: 0, avgRecordingTime: 0}, // Cambiado a paused
{ name: "Bern", coords: [46.9481, 7.4474], category: "operative", connections: 3, avgSupportTime: 1, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Vuelve a operative
{ name: "Madrid", coords: [40.4165, -3.70256], category: "operative", connections: 12, avgSupportTime: 0.5, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kiel", coords: [54.3233, 10.1228], category: "removed", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Le Mans", coords: [48.0077, 0.1996], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Gdansk", coords: [54.3520, 18.6466], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Prague", coords: [50.0755, 14.4378], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0},
{ name: "Kuwait", coords: [29.3759, 47.9774], category: "assessment", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0}, // Pasa a operative con datos
{ name: "Şalālah", coords: [17.01505, 54.09237], category: "operative", connections: 0, avgSupportTime: 0, webinars: 0, avgWebinarTime: 0 , recordings: 0, avgRecordingTime: 0} // Pasa a operative con datos
];
// Mapa y colores (sin cambios)
var map = L.map('map').setView([50.0755, 14.4378], 3);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var categoryColors = { /* ... Mismos colores ... */
"assessment": "#0057b8",
"deployment": "#ff8c00", // Naranja para deployment
"operative": "#008000",
"paused": "#FFD700",
"maintenance": "#FFA500",
"removed": "#FF0000"
};
var markers = [];
var chart1 = null, chart2 = null, chart3 = null, chart4 = null, chart5 = null, chart6 = null;
/**
* Agrega datos de múltiples datasets mensuales.
* @param {Array<Array<Object>>} datasets - Array de datasets (ej: [locationsJan, locationsFeb]).
* @returns {Array<Object>} - Un único dataset con valores agregados.
*/
function aggregateMonthlyData(datasets) {
const aggregated = {}; // Usar objeto para agrupar por nombre
datasets.forEach(monthlyData => {
monthlyData.forEach(location => {
const name = location.name;
if (!aggregated[name]) {
// Si es la primera vez que vemos esta ubicación, inicializarla
aggregated[name] = {
...location, // Copia coords, category (la del primer mes encontrado)
totalConnections: 0,
totalSupportTime: 0,
totalWebinars: 0,
totalWebinarTime: 0,
totalRecordings: 0,
totalRecordingTime: 0,
};
// Usar la categoría del *último* mes en el rango como la representativa
if (datasets.length > 0) {
const lastMonthData = datasets[datasets.length - 1];
const lastLocationState = lastMonthData.find(loc => loc.name === name);
if (lastLocationState) {
aggregated[name].category = lastLocationState.category;
}
}
}
// Acumular totales
aggregated[name].totalConnections += location.connections;
aggregated[name].totalSupportTime += location.connections * location.avgSupportTime; // Tiempo total = conexiones * promedio
aggregated[name].totalWebinars += location.webinars;
aggregated[name].totalWebinarTime += location.webinars * location.avgWebinarTime;
aggregated[name].totalRecordings += location.recordings;
aggregated[name].totalRecordingTime += location.recordings * location.avgRecordingTime;
});
});
// Calcular promedios finales y formatear salida
const finalData = Object.values(aggregated).map(loc => {
// Evitar división por cero
const avgSupportTime = loc.totalConnections > 0 ? (loc.totalSupportTime / loc.totalConnections) : 0;
const avgWebinarTime = loc.totalWebinars > 0 ? (loc.totalWebinarTime / loc.totalWebinars) : 0;
const avgRecordingTime = loc.totalRecordings > 0 ? (loc.totalRecordingTime / loc.totalRecordings) : 0;
return {
...loc, // Mantiene name, coords, category
connections: loc.totalConnections,
avgSupportTime: parseFloat(avgSupportTime.toFixed(2)), // Redondear a 2 decimales
webinars: loc.totalWebinars,
avgWebinarTime: parseFloat(avgWebinarTime.toFixed(2)),
recordings: loc.totalRecordings,
avgRecordingTime: parseFloat(avgRecordingTime.toFixed(2)),
// Eliminar propiedades temporales si se desea
// totalConnections, totalSupportTime, etc. ya no son necesarias
};
});
return finalData;
}
function updateMarkers() {
var selectedCategory = document.getElementById("category").value;
var selectedMonthFrom = parseInt(document.getElementById("monthFrom").value, 10);
var selectedMonthTo = parseInt(document.getElementById("monthTo").value, 10);
let datasetsToCombine = [];
// Validar rango básico
//if (selectedMonthFrom > selectedMonthTo) {
// console.warn("El mes 'From' no puede ser posterior al mes 'To'. Mostrando datos solo para 'From'.");
// selectedMonthTo = selectedMonthFrom; // O mostrar un error/nada
//}
if (selectedMonthFrom > selectedMonthTo) {
alert("Error: El mes 'From' no puede ser posterior al mes 'To'. Por favor, corrija la selección.");
return; // Detiene la ejecución de la función aquí
}
// Determinar qué datasets incluir basándose en el rango (solo para meses 1, 2, 3)
if (selectedMonthFrom <= 1 && selectedMonthTo >= 1) datasetsToCombine.push(locationsJan);
if (selectedMonthFrom <= 2 && selectedMonthTo >= 2) datasetsToCombine.push(locationsFeb);
if (selectedMonthFrom <= 3 && selectedMonthTo >= 3) datasetsToCombine.push(locationsMar);
if (selectedMonthFrom <= 4 && selectedMonthTo >= 4) datasetsToCombine.push(locationsApr);
// Añadir más 'if' si se crean locationsApr, locationsMay, etc.
let dataToDisplay = [];
if (datasetsToCombine.length > 0) {
// Si hay más de un mes, agregar. Si solo hay uno, aggregateMonthlyData lo manejará.
dataToDisplay = aggregateMonthlyData(datasetsToCombine);
} else {
console.log("No hay datos disponibles para el rango de meses seleccionado (1-3).");
}
// --- Filtrado por Categoría (se aplica DESPUÉS de agregar por mes) ---
let filteredLocations = dataToDisplay.filter(location =>
selectedCategory === "all" || location.category === selectedCategory
);
console.log(`Mostrando datos agregados de Mes ${selectedMonthFrom} a ${selectedMonthTo}. Categoría: ${selectedCategory}. Ubicaciones filtradas: ${filteredLocations.length}`);
// --- Actualización de Mapa y Gráficos (sin cambios internos, solo usan filteredLocations) ---
markers.forEach(marker => map.removeLayer(marker));
markers = [];
filteredLocations.forEach(location => {
// Usar la categoría (posiblemente actualizada por la agregación)
const color = categoryColors[location.category] || '#CCCCCC';
var marker = L.circleMarker(location.coords, {
color: color,
fillColor: color,
fillOpacity: 0.8,
radius: 8
}).bindPopup(`<b>${location.name}</b><br>Categoría: ${location.category}<br>Conexiones: ${location.connections}<br>Soporte: ${location.avgSupportTime} hrs`);
marker.addTo(map);
markers.push(marker);
});
// Ajustar vista del mapa
if (markers.length > 1) {
var group = new L.featureGroup(markers);
try { map.fitBounds(group.getBounds().pad(0.3)); } catch (e) { /*...*/ }
} else if (markers.length === 1) {
map.setView(markers[0].getLatLng(), 6);
} else {
map.setView([48, 15], 4);
}
// Actualizar gráficos
updateCharts(filteredLocations);
}
// --- La función updateCharts permanece sin cambios ---
function updateCharts(filteredLocations) {
// ... (código idéntico al de la versión anterior para crear/actualizar los 6 gráficos) ...
var cityNames = filteredLocations.map(location => location.name);
var connectionsData = filteredLocations.map(location => location.connections);
var avgSupportTimeData = filteredLocations.map(location => location.avgSupportTime);
var webinarData = filteredLocations.map(location => location.webinars);
var avgWebinarTimeData = filteredLocations.map(location => location.avgWebinarTime);
var recordingData = filteredLocations.map(location => location.recordings);
var avgRecordingTimeData = filteredLocations.map(location => location.avgRecordingTime);
// Usar el color de la categoría final (después de la agregación)
var categoryColorsData = filteredLocations.map(location => categoryColors[location.category] || '#CCCCCC');
// Destruir gráficos existentes
if (chart1) chart1.destroy();
if (chart2) chart2.destroy();
if (chart3) chart3.destroy();
if (chart4) chart4.destroy();
if (chart5) chart5.destroy();
if (chart6) chart6.destroy();
// --- Opciones comunes para gráficos (reutilizadas de la versión anterior) ---
var commonOptions = (titleText) => ({
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false }, title: { display: true, text: titleText, font: { size: 14 }, color: '#333', padding: { top: 5, bottom: 15 } } },
scales: { x: { ticks: { color: '#333', font: {size: 10} }, grid: { display: false } }, y: { beginAtZero: true, ticks: { color: '#333' }, grid: { color: 'rgba(0,0,0,0.05)' } } },
animation: { duration: 800, easing: 'easeOutQuad' }
});
var commonDatasetOptions = (data, colors) => ({
data: data, backgroundColor: colors, borderColor: 'rgba(51, 51, 51, 0.5)', borderWidth: 1, borderRadius: 5, hoverBackgroundColor: 'rgba(0, 0, 0, 0.2)'
});
// --- Creación de Gráficos ---
var ctx1 = document.getElementById('connectionsChart').getContext('2d');
chart1 = new Chart(ctx1, { type: 'bar', data: { labels: cityNames, datasets: [commonDatasetOptions(connectionsData, categoryColorsData)] }, options: commonOptions('Total Remote connections (Selected Period)') });
var ctx2 = document.getElementById('supportTimeChart').getContext('2d');
chart2 = new Chart(ctx2, { type: 'bar', data: { labels: cityNames, datasets: [commonDatasetOptions(avgSupportTimeData, categoryColorsData)] }, options: commonOptions('Average Support Time (hrs/connection, Selected Period)') }); // Título ajustado
var ctx3 = document.getElementById('webinarChart').getContext('2d');
chart3 = new Chart(ctx3, { type: 'bar', data: { labels: cityNames, datasets: [commonDatasetOptions(webinarData, categoryColorsData)] }, options: commonOptions('Total Webinar Connections (Selected Period)') });
var ctx4 = document.getElementById('webinarTime').getContext('2d');
chart4 = new Chart(ctx4, { type: 'bar', data: { labels: cityNames, datasets: [commonDatasetOptions(avgWebinarTimeData, categoryColorsData)] }, options: commonOptions('Average Webinar Time (hrs/session, Selected Period)') }); // Título ajustado
var ctx5 = document.getElementById('recordingChart').getContext('2d');
chart5 = new Chart(ctx5, { type: 'bar', data: { labels: cityNames, datasets: [commonDatasetOptions(recordingData, categoryColorsData)] }, options: commonOptions('Total Recordings (Selected Period)') });
var ctx6 = document.getElementById('recordingTime').getContext('2d');
chart6 = new Chart(ctx6, { type: 'bar', data: { labels: cityNames, datasets: [commonDatasetOptions(avgRecordingTimeData, categoryColorsData)] }, options: commonOptions('Average Recording Time (hrs/recording, Selected Period)') }); // Título ajustado
}
// Llamada inicial
document.addEventListener('DOMContentLoaded', function() {
// Establecer mes 'To' por defecto (ej: Marzo = 3)
const monthToSelect = document.getElementById('monthTo');
monthToSelect.value = 3;
// Establecer mes 'From' por defecto (ej: Enero = 1)
const monthFromSelect = document.getElementById('monthFrom');
monthFromSelect.value = 1;
updateMarkers(); // Carga inicial con el rango por defecto (Jan-Mar)
});
</script>
</body>
</html>