Skip to content

Instantly share code, notes, and snippets.

@Jcbertorello
Created December 29, 2025 00:16
Show Gist options
  • Select an option

  • Save Jcbertorello/336f5747b982c02786f9dd6c58283ef3 to your computer and use it in GitHub Desktop.

Select an option

Save Jcbertorello/336f5747b982c02786f9dd6c58283ef3 to your computer and use it in GitHub Desktop.
Dashboard Ajonjolí - 2025-12-29 00:16
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ocupación y Facturación por Sala - Septiembre 2025 - Cinexo</title>
<!-- Google Fonts para tipografía premium -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<!-- Chart.js + Plugin Datalabels -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script>
<!-- html2pdf.js for PDF export -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<style>
/* === VARIABLES === */
:root {
--color-primary: #60B99A;
--color-primary-light: #7FCDB2;
--color-primary-dark: #4A9D80;
--color-primary-glow: rgba(96, 185, 154, 0.3);
--color-secondary: #1F3B4D;
--color-secondary-light: #2D5066;
--color-boleteria: #60B99A;
--color-candy: #FFB74D;
--color-candy-dark: #F59E0B;
--color-success: #10B981;
--color-success-light: #D1FAE5;
--color-danger: #EF4444;
--color-danger-light: #FEE2E2;
--color-warning: #F59E0B;
--color-warning-light: #FEF3C7;
--ocupacion-alta: #10B981;
--ocupacion-media: #F59E0B;
--ocupacion-baja: #EF4444;
--bg-primary: #F8FAFC;
--bg-card: #FFFFFF;
--bg-hover: #F1F5F9;
--border-light: #E2E8F0;
--border-medium: #CBD5E1;
--text-primary: #1E293B;
--text-secondary: #475569;
--text-muted: #64748B;
--text-light: #94A3B8;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06);
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04);
--shadow-glow: 0 0 20px var(--color-primary-glow);
}
/* === RESET & BASE === */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: 'Inter', system-ui, sans-serif;
background: linear-gradient(180deg, var(--bg-primary) 0%, #EFF6FF 100%);
color: var(--text-primary);
line-height: 1.6;
min-height: 100vh;
}
/* === DASHBOARD CONTAINER === */
.dashboard {
max-width: 1400px;
margin: 0 auto;
padding: 32px 24px;
}
/* === HEADER PREMIUM === */
.header {
background: linear-gradient(135deg, var(--color-secondary) 0%, var(--color-secondary-light) 100%);
border-radius: 20px;
padding: 28px 32px;
margin-bottom: 32px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: var(--shadow-lg);
position: relative;
overflow: hidden;
}
.header::before {
content: '';
position: absolute;
top: -50%;
right: -20%;
width: 400px;
height: 400px;
background: radial-gradient(circle, rgba(96, 185, 154, 0.15) 0%, transparent 70%);
pointer-events: none;
}
.header-left { display: flex; align-items: center; gap: 16px; z-index: 1; }
.logo {
width: 56px;
height: 56px;
background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: 800;
color: white;
box-shadow: 0 8px 20px rgba(96, 185, 154, 0.4);
}
.header-title { color: white; font-size: 1.75rem; font-weight: 800; letter-spacing: -0.02em; }
.header-subtitle { color: rgba(255,255,255,0.8); font-size: 0.9rem; margin-top: 2px; }
.header-actions { display: flex; gap: 12px; z-index: 1; }
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 20px;
border-radius: 10px;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
border: none;
transition: all 0.2s ease;
}
.btn-primary {
background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
color: white;
box-shadow: 0 4px 12px rgba(96, 185, 154, 0.4);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(96, 185, 154, 0.5);
}
/* === KPI CARDS PREMIUM === */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 24px; margin-bottom: 32px; }
.kpi-card {
background: var(--bg-card);
border-radius: 16px;
padding: 24px;
position: relative;
overflow: hidden;
box-shadow: var(--shadow-md);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid var(--border-light);
}
.kpi-card::before {
content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px;
background: linear-gradient(90deg, var(--color-primary), var(--color-primary-light));
}
.kpi-card.secondary::before { background: linear-gradient(90deg, var(--color-secondary), var(--color-secondary-light)); }
.kpi-card.warning::before { background: linear-gradient(90deg, var(--color-candy), var(--color-candy-dark)); }
.kpi-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-xl), var(--shadow-glow); border-color: var(--color-primary); }
.kpi-icon {
width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center;
font-size: 1.5rem; margin-bottom: 16px; background: linear-gradient(135deg, rgba(96, 185, 154, 0.1), rgba(96, 185, 154, 0.2));
}
.kpi-card.secondary .kpi-icon { background: linear-gradient(135deg, rgba(31, 59, 77, 0.1), rgba(31, 59, 77, 0.2)); }
.kpi-card.warning .kpi-icon { background: linear-gradient(135deg, rgba(255, 183, 77, 0.1), rgba(255, 183, 77, 0.2)); }
.kpi-label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted); margin-bottom: 8px; }
.kpi-value { font-size: 2rem; font-weight: 800; color: var(--text-primary); line-height: 1.1; margin-bottom: 8px; font-feature-settings: 'tnum'; }
.kpi-trend { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border-radius: 20px; font-size: 0.75rem; font-weight: 700; }
.kpi-trend.up { background: var(--color-success-light); color: var(--color-success); }
.kpi-trend.down { background: var(--color-danger-light); color: var(--color-danger); }
/* === GRID LAYOUT === */
.grid-layout { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.col-span-2 { grid-column: span 2; }
.col-span-1 { grid-column: span 1; }
.col-span-3 { grid-column: span 3; }
/* === CHART CARD === */
.card {
background: var(--bg-card);
border-radius: 16px;
padding: 24px;
box-shadow: var(--shadow-md);
border: 1px solid var(--border-light);
display: flex;
flex-direction: column;
}
.card-header { padding-bottom: 16px; border-bottom: 1px solid var(--border-light); margin-bottom: 16px; }
.card-title { font-size: 1.1rem; font-weight: 700; color: var(--text-primary); }
.card-subtitle { font-size: 0.8rem; color: var(--text-muted); margin-top: 2px; }
.chart-container { position: relative; flex-grow: 1; }
.h-400 { height: 400px; }
.h-832 { height: 832px; }
/* === TABLE PREMIUM === */
.table-card {
background: var(--bg-card);
border-radius: 16px;
overflow: hidden;
box-shadow: var(--shadow-md);
border: 1px solid var(--border-light);
}
.data-table { width: 100%; border-collapse: collapse; }
.data-table thead { background: var(--bg-hover); }
.data-table th {
padding: 14px 20px; text-align: left; font-weight: 600; font-size: 0.7rem;
text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); border-bottom: 2px solid var(--border-light);
}
.data-table td { padding: 16px 20px; border-bottom: 1px solid var(--border-light); font-size: 0.9rem; color: var(--text-primary); transition: background 0.15s ease; }
.data-table tbody tr:hover td { background: rgba(96, 185, 154, 0.05); }
.data-table tbody tr:last-child td { border-bottom: none; }
.rank-medal { width: 32px; height: 32px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.85rem; }
.rank-1 { background: linear-gradient(135deg, #FFD700, #FFA500); color: white; box-shadow: 0 2px 8px rgba(255, 215, 0, 0.4); }
.rank-2 { background: linear-gradient(135deg, #E8E8E8, #B8B8B8); color: white; box-shadow: 0 2px 8px rgba(192, 192, 192, 0.4); }
.rank-3 { background: linear-gradient(135deg, #CD7F32, #8B4513); color: white; box-shadow: 0 2px 8px rgba(205, 127, 50, 0.4); }
.rank-other { background: var(--bg-hover); color: var(--text-muted); }
.progress-cell { display: flex; align-items: center; gap: 12px; }
.progress-bar-container { flex: 1; height: 8px; background: var(--border-light); border-radius: 4px; overflow: hidden; min-width: 80px; }
.progress-bar-fill { height: 100%; border-radius: 4px; transition: width 1s ease-out; }
.progress-bar-fill.high { background: linear-gradient(90deg, #10B981, #34D399); }
.progress-bar-fill.medium { background: linear-gradient(90deg, #F59E0B, #FBBF24); }
.progress-bar-fill.low { background: linear-gradient(90deg, #EF4444, #F87171); }
.progress-value { font-weight: 700; font-size: 0.85rem; min-width: 45px; text-align: right; }
.value-highlight { font-weight: 700; color: var(--text-primary); }
.value-currency { font-feature-settings: 'tnum'; }
/* === FOOTER PREMIUM === */
.footer { text-align: center; padding-top: 32px; color: var(--text-muted); font-size: 0.8rem; }
.footer a { color: var(--color-primary-dark); text-decoration: none; font-weight: 600; }
.footer a:hover { text-decoration: underline; }
/* === PRINT/PDF === */
@media print {
body { background: white !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.btn, .header-actions { display: none !important; }
.dashboard { padding: 16px !important; max-width: 100% !important; margin: 0 !important; }
.header, .card, .kpi-card, .table-card { box-shadow: none !important; border: 1px solid #ddd !important; break-inside: avoid; }
.grid-layout { display: block; } /* Stacks elements for printing */
.card, .kpi-card { margin-bottom: 20px; }
}
/* === RESPONSIVE === */
@media (max-width: 1200px) {
.grid-layout { grid-template-columns: 1fr 1fr; }
.col-span-3 { grid-column: span 2; }
.h-832 { height: auto; }
}
@media (max-width: 768px) {
.header { flex-direction: column; gap: 16px; text-align: center; }
.grid-layout { grid-template-columns: 1fr; }
.col-span-1, .col-span-2, .col-span-3 { grid-column: span 1; }
.h-400 { height: 300px; }
}
</style>
</head>
<body>
<div class="dashboard" id="dashboard-content">
<!-- Header -->
<header class="header">
<div class="header-left">
<div class="logo">CX</div>
<div>
<h1 class="header-title" id="dashboard-title"></h1>
<p class="header-subtitle" id="dashboard-subtitle"></p>
</div>
</div>
<div class="header-actions">
<button class="btn btn-primary" onclick="downloadPDF()">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/>
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/>
</svg>
Descargar PDF
</button>
</div>
</header>
<!-- KPIs -->
<div class="kpi-grid">
<div class="kpi-card">
<div class="kpi-icon">💰</div>
<div class="kpi-label">Recaudación Total</div>
<div class="kpi-value" id="kpi-recaudacion"></div>
<div class="kpi-trend up">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>
+8.2% vs mes anterior
</div>
</div>
<div class="kpi-card secondary">
<div class="kpi-icon">🎟️</div>
<div class="kpi-label">Total Espectadores</div>
<div class="kpi-value" id="kpi-espectadores"></div>
<div class="kpi-trend up">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>
+5.1% vs mes anterior
</div>
</div>
<div class="kpi-card warning">
<div class="kpi-icon">📊</div>
<div class="kpi-label">Ocupación Promedio</div>
<div class="kpi-value" id="kpi-ocupacion"></div>
<div class="kpi-trend down">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>
-1.5% vs mes anterior
</div>
</div>
<div class="kpi-card secondary">
<div class="kpi-icon">🎬</div>
<div class="kpi-label">Total Funciones</div>
<div class="kpi-value" id="kpi-funciones"></div>
<div class="kpi-trend up">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>
+2.8% vs mes anterior
</div>
</div>
</div>
<!-- Charts Grid -->
<div class="grid-layout">
<div class="card col-span-2">
<div class="card-header">
<h2 class="card-title">Ranking de Ocupación por Sala</h2>
<p class="card-subtitle">Porcentaje de butacas ocupadas sobre el total disponible.</p>
</div>
<div class="chart-container h-400">
<canvas id="ocupacionChart"></canvas>
</div>
</div>
<div class="card col-span-1">
<div class="card-header">
<h2 class="card-title">Distribución de Espectadores</h2>
<p class="card-subtitle">Aporte de cada sala al total de espectadores.</p>
</div>
<div class="chart-container h-400">
<canvas id="distribucionChart"></canvas>
</div>
</div>
<div class="card table-card col-span-3">
<div class="card-header">
<h2 class="card-title">Detalle de Rendimiento por Sala</h2>
<p class="card-subtitle">Análisis completo de todas las métricas por sala, ordenado por ocupación.</p>
</div>
<div style="overflow-x: auto;">
<table class="data-table">
<thead>
<tr>
<th>Rank</th>
<th>Sala</th>
<th>Capacidad</th>
<th>Funciones</th>
<th style="text-align: right;">Espectadores</th>
<th>Ocupación</th>
<th style="text-align: right;">Recaudación</th>
</tr>
</thead>
<tbody id="dataTableBody">
<!-- Rows will be injected by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Footer -->
<footer class="footer">
Dashboard generado por <a href="https://mostachia.com" target="_blank">MostachIA</a> para Cinexo. &copy; 2025
</footer>
</div>
<script>
const jsonData = {
"dashboardType": "ocupacion",
"dashboardTitle": "Ocupación y Facturación por Sala - Septiembre 2025",
"clientName": "Cinexo",
"periodo": {
"desde": "2025-09-01",
"hasta": "2025-09-30",
"descripcion": "Septiembre 2025"
},
"ocupacionPorSala": [
{"sala": 4,"nombreSala": "Sala 4","capacidad": 160,"funciones": 106,"espectadores": 3279,"ocupacion": 19.33,"recaudacion": 17861500},
{"sala": 6,"nombreSala": "Sala 6","capacidad": 160,"funciones": 95,"espectadores": 2371,"ocupacion": 15.60,"recaudacion": 13167500},
{"sala": 5,"nombreSala": "Sala 5","capacidad": 160,"funciones": 95,"espectadores": 2067,"ocupacion": 13.60,"recaudacion": 11380500},
{"sala": 8,"nombreSala": "Sala 8","capacidad": 327,"funciones": 81,"espectadores": 2621,"ocupacion": 9.90,"recaudacion": 12627000},
{"sala": 7,"nombreSala": "Sala 7","capacidad": 148,"funciones": 100,"espectadores": 1091,"ocupacion": 7.37,"recaudacion": 5440000},
{"sala": 3,"nombreSala": "Sala 3","capacidad": 160,"funciones": 92,"espectadores": 994,"ocupacion": 6.75,"recaudacion": 4824000},
{"sala": 1,"nombreSala": "Sala 1","capacidad": 194,"funciones": 112,"espectadores": 1425,"ocupacion": 6.56,"recaudacion": 6920000},
{"sala": 2,"nombreSala": "Sala 2","capacidad": 133,"funciones": 86,"espectadores": 714,"ocupacion": 6.24,"recaudacion": 3561000}
]
};
// === HELPERS ===
function formatCurrency(value) { return '$' + value.toLocaleString('es-AR', { minimumFractionDigits: 0, maximumFractionDigits: 0 }); }
function formatNumber(value) { return value.toLocaleString('es-AR'); }
function downloadPDF() {
const element = document.getElementById('dashboard-content');
const opt = {
margin: 0.5,
filename: `Cinexo_Dashboard_Ocupacion_${jsonData.periodo.descripcion.replace(' ','_')}.pdf`,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, useCORS: true },
jsPDF: { unit: 'in', format: 'letter', orientation: 'landscape' }
};
html2pdf().from(element).set(opt).save();
}
document.addEventListener('DOMContentLoaded', () => {
// === DATA PROCESSING ===
const data = jsonData.ocupacionPorSala.sort((a, b) => b.ocupacion - a.ocupacion);
// === FILL HEADER & KPIs ===
document.getElementById('dashboard-title').textContent = jsonData.dashboardTitle;
document.getElementById('dashboard-subtitle').textContent = `Reporte del período: ${jsonData.periodo.descripcion}`;
const totalRecaudacion = data.reduce((sum, item) => sum + item.recaudacion, 0);
const totalEspectadores = data.reduce((sum, item) => sum + item.espectadores, 0);
const totalFunciones = data.reduce((sum, item) => sum + item.funciones, 0);
const totalCapacidadOfertada = data.reduce((sum, item) => sum + (item.capacidad * item.funciones), 0);
const avgOcupacion = (totalEspectadores / totalCapacidadOfertada) * 100;
document.getElementById('kpi-recaudacion').textContent = formatCurrency(totalRecaudacion);
document.getElementById('kpi-espectadores').textContent = formatNumber(totalEspectadores);
document.getElementById('kpi-ocupacion').textContent = `${avgOcupacion.toFixed(1)}%`;
document.getElementById('kpi-funciones').textContent = formatNumber(totalFunciones);
// === CHART.JS GLOBAL CONFIG ===
Chart.register(ChartDataLabels);
Chart.defaults.font.family = "'Inter', 'Segoe UI', system-ui, sans-serif";
Chart.defaults.font.size = 12;
Chart.defaults.color = '#64748B';
Chart.defaults.plugins.legend.labels.usePointStyle = true;
Chart.defaults.plugins.legend.labels.padding = 20;
Chart.defaults.plugins.legend.labels.font = { size: 11, weight: '500' };
Chart.defaults.plugins.tooltip.backgroundColor = 'rgba(30, 41, 59, 0.95)';
Chart.defaults.plugins.tooltip.titleFont = { size: 13, weight: '600' };
Chart.defaults.plugins.tooltip.bodyFont = { size: 12 };
Chart.defaults.plugins.tooltip.padding = 12;
Chart.defaults.plugins.tooltip.cornerRadius = 8;
Chart.defaults.plugins.tooltip.displayColors = true;
Chart.defaults.plugins.tooltip.boxPadding = 6;
Chart.defaults.animation.duration = 1000;
Chart.defaults.animation.easing = 'easeOutQuart';
const chartColors = {
primary: '#60B99A',
primaryLight: '#7FCDB2',
secondary: '#1F3B4D',
palette: ['#60B99A', '#1F3B4D', '#FFB74D', '#8B5CF6', '#EC4899', '#06B6D4', '#84CC16', '#F59E0B'],
ocupacionAlta: '#10B981',
ocupacionMedia: '#F59E0B',
ocupacionBaja: '#EF4444',
};
// === OCUPACION BAR CHART ===
const ocupacionCtx = document.getElementById('ocupacionChart').getContext('2d');
new Chart(ocupacionCtx, {
type: 'bar',
data: {
labels: data.map(d => d.nombreSala),
datasets: [{
label: 'Ocupación (%)',
data: data.map(d => d.ocupacion),
backgroundColor: function(context) {
const value = context.raw;
if (value > 15) return chartColors.ocupacionAlta;
if (value > 8) return chartColors.ocupacionMedia;
return chartColors.ocupacionBaja;
},
borderRadius: 6,
borderSkipped: false,
barThickness: 25,
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
datalabels: {
anchor: 'end',
align: 'end',
offset: 4,
color: '#1E293B',
font: { weight: 'bold', size: 12 },
formatter: (value) => `${value.toFixed(1)}%`
},
tooltip: {
callbacks: {
label: (ctx) => `${ctx.dataset.label}: ${ctx.raw.toFixed(2)}%`
}
}
},
scales: {
x: {
beginAtZero: true,
grid: { color: 'rgba(0,0,0,0.05)', drawBorder: false },
ticks: { callback: (value) => `${value}%` }
},
y: {
grid: { display: false },
ticks: { font: { weight: '500' } }
}
}
}
});
// === DISTRIBUCION DOUGHNUT CHART ===
const distribucionCtx = document.getElementById('distribucionChart').getContext('2d');
new Chart(distribucionCtx, {
type: 'doughnut',
data: {
labels: data.map(d => d.nombreSala),
datasets: [{
data: data.map(d => d.espectadores),
backgroundColor: chartColors.palette,
borderWidth: 0,
hoverOffset: 15,
hoverBorderWidth: 4,
hoverBorderColor: '#fff'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
cutout: '60%',
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 15,
font: { size: 10 }
}
},
datalabels: {
color: '#fff',
font: { weight: 'bold', size: 14 },
formatter: (value, ctx) => {
const total = ctx.chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
const percentage = ((value / total) * 100);
return percentage > 7 ? percentage.toFixed(0) + '%' : '';
},
},
tooltip: {
callbacks: {
label: function(context) {
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const value = context.raw;
const percentage = ((value / total) * 100).toFixed(1);
return `${context.label}: ${formatNumber(value)} (${percentage}%)`;
}
}
}
}
}
});
// === FILL DETAILED TABLE ===
const tableBody = document.getElementById('dataTableBody');
data.forEach((item, index) => {
const rank = index + 1;
let rankHtml = '';
if (rank === 1) rankHtml = `<span class="rank-medal rank-1">1</span>`;
else if (rank === 2) rankHtml = `<span class="rank-medal rank-2">2</span>`;
else if (rank === 3) rankHtml = `<span class="rank-medal rank-3">3</span>`;
else rankHtml = `<span class="rank-medal rank-other">${rank}</span>`;
let ocupacionClass = 'low';
if (item.ocupacion > 15) ocupacionClass = 'high';
else if (item.ocupacion > 8) ocupacionClass = 'medium';
const row = `
<tr>
<td>${rankHtml}</td>
<td class="value-highlight">${item.nombreSala}</td>
<td>${formatNumber(item.capacidad)}</td>
<td>${formatNumber(item.funciones)}</td>
<td style="text-align: right;">${formatNumber(item.espectadores)}</td>
<td>
<div class="progress-cell">
<div class="progress-bar-container">
<div class="progress-bar-fill ${ocupacionClass}" style="width: ${item.ocupacion * 4}%"></div>
</div>
<span class="progress-value">${item.ocupacion.toFixed(1)}%</span>
</div>
</td>
<td class="value-highlight value-currency" style="text-align: right;">${formatCurrency(item.recaudacion)}</td>
</tr>
`;
tableBody.innerHTML += row;
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment