Created
December 29, 2025 02:50
-
-
Save Jcbertorello/854aa8d1b7859f866ea251678a263d74 to your computer and use it in GitHub Desktop.
Dashboard Ajonjolí - 2025-12-29 02:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="es"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Reporte Top Películas Agosto 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> | |
| <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 === */ | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| 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: 24px; | |
| 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); | |
| } | |
| /* === INFO BAR === */ | |
| .info-bar { | |
| background: var(--bg-card); | |
| border-radius: 12px; | |
| padding: 16px 24px; | |
| margin-bottom: 24px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| box-shadow: var(--shadow-md); | |
| border-left: 4px solid var(--color-primary); | |
| } | |
| .info-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| font-size: 0.875rem; | |
| color: var(--text-muted); | |
| } | |
| .info-item strong { | |
| color: var(--text-primary); | |
| font-weight: 600; | |
| } | |
| .kpi-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
| gap: 20px; | |
| 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.candy::before { | |
| background: linear-gradient(90deg, var(--color-candy), var(--color-candy-dark)); | |
| } | |
| .kpi-card.total::before { | |
| background: linear-gradient(90deg, var(--color-secondary), var(--color-secondary-light)); | |
| } | |
| .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)); | |
| color: var(--color-primary-dark); | |
| } | |
| .kpi-card.total .kpi-icon { | |
| background: linear-gradient(135deg, rgba(31, 59, 77, 0.1), rgba(31, 59, 77, 0.2)); | |
| color: var(--color-secondary); | |
| } | |
| .kpi-card.candy .kpi-icon { | |
| background: linear-gradient(135deg, rgba(255, 183, 77, 0.1), rgba(255, 183, 77, 0.2)); | |
| color: var(--color-candy-dark); | |
| } | |
| .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-detail { | |
| font-size: 0.85rem; | |
| color: var(--text-secondary); | |
| margin-bottom: 8px; | |
| } | |
| .grid-container { | |
| display: grid; | |
| grid-template-columns: 2fr 1fr; | |
| gap: 24px; | |
| margin-bottom: 32px; | |
| } | |
| .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 { | |
| margin-bottom: 20px; | |
| } | |
| .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; | |
| } | |
| .doughnut-container { | |
| position: relative; | |
| height: 250px; | |
| } | |
| .table-card { | |
| background: var(--bg-card); | |
| border-radius: 16px; | |
| overflow: hidden; | |
| box-shadow: var(--shadow-md); | |
| border: 1px solid var(--border-light); | |
| } | |
| .table-header { | |
| padding: 20px 24px; | |
| border-bottom: 1px solid var(--border-light); | |
| } | |
| .table-title { | |
| font-size: 1.1rem; | |
| font-weight: 700; | |
| color: var(--text-primary); | |
| } | |
| .table-subtitle { | |
| font-size: 0.8rem; | |
| color: var(--text-muted); | |
| margin-top: 2px; | |
| } | |
| .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 th.right, .data-table td.right { | |
| text-align: right; | |
| } | |
| .data-table td { | |
| padding: 16px 20px; | |
| border-bottom: 1px solid var(--border-light); | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| transition: background 0.15s ease; | |
| } | |
| .data-table td .value-highlight { | |
| font-weight: 600; | |
| color: var(--text-primary); | |
| } | |
| .data-table td .value-currency { | |
| font-feature-settings: 'tnum'; | |
| } | |
| .data-table tbody tr:hover td { | |
| background: rgba(96, 185, 154, 0.05); | |
| } | |
| .data-table tbody tr:last-child td { | |
| border-bottom: none; | |
| } | |
| .rank-cell { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| .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; | |
| flex-shrink: 0; | |
| } | |
| .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: #475569; | |
| 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); | |
| } | |
| .format-badge { | |
| display: inline-flex; | |
| align-items: center; | |
| padding: 4px 10px; | |
| border-radius: 6px; | |
| font-size: 0.7rem; | |
| font-weight: 700; | |
| text-transform: uppercase; | |
| letter-spacing: 0.03em; | |
| margin-left: 8px; | |
| } | |
| .badge-2D { background: #DBEAFE; color: #1E40AF; } | |
| .badge-3D { background: #FEF3C7; color: #B45309; } | |
| .badge-4D { background: #FCE7F3; color: #BE185D; } | |
| .badge-IMAX { background: #EDE9FE; color: #7C3AED; } | |
| /* === FOOTER PREMIUM === */ | |
| .footer { | |
| margin-top: 40px; | |
| padding: 24px; | |
| text-align: center; | |
| } | |
| .mostachia-brand { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 12px; | |
| text-decoration: none; | |
| } | |
| .mostachia-logo { | |
| width: 40px; | |
| height: 40px; | |
| background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark)); | |
| border-radius: 10px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: 800; | |
| font-size: 1.1rem; | |
| } | |
| .mostachia-text { | |
| font-size: 0.85rem; | |
| color: var(--text-muted); | |
| text-align: left; | |
| } | |
| .mostachia-text strong { | |
| display: block; | |
| color: var(--text-primary); | |
| font-weight: 700; | |
| } | |
| /* === 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; } | |
| .header, .kpi-card, .card, .table-card { box-shadow: none !important; border: 1px solid #ddd !important; } | |
| .grid-container { grid-template-columns: 2fr 1fr !important; } | |
| } | |
| /* === RESPONSIVE === */ | |
| @media (max-width: 1200px) { | |
| .grid-container { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .header { flex-direction: column; gap: 16px; text-align: center; } | |
| .kpi-grid { grid-template-columns: 1fr; } | |
| .info-bar { flex-direction: column; gap: 8px; } | |
| } | |
| </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">Reporte de Performance para Cinexo</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> | |
| <!-- Info Bar --> | |
| <div class="info-bar"> | |
| <div class="info-item"> | |
| <span>🗓️</span> Período: <strong id="periodo-descripcion"></strong> | |
| </div> | |
| <div class="info-item"> | |
| <span>📍</span> Complejo: <strong>Cinexo Central</strong> | |
| </div> | |
| <div class="info-item"> | |
| <span>📊</span> Reporte: <strong>Top Películas</strong> | |
| </div> | |
| </div> | |
| <!-- KPI Grid --> | |
| <div class="kpi-grid" id="kpi-container"> | |
| <!-- KPIs will be injected here by JavaScript --> | |
| </div> | |
| <!-- Charts Grid --> | |
| <div class="grid-container"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h2 class="card-title">Top 5 Películas por Espectadores</h2> | |
| <p class="card-subtitle">Ranking de las películas más vistas en el período.</p> | |
| </div> | |
| <div class="chart-container" style="height: 400px;"> | |
| <canvas id="chartTopPeliculas"></canvas> | |
| </div> | |
| </div> | |
| <div style="display: flex; flex-direction: column; gap: 24px;"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h3 class="card-title">Asistentes por Formato</h3> | |
| <p class="card-subtitle">Distribución de espectadores.</p> | |
| </div> | |
| <div class="doughnut-container"> | |
| <canvas id="chartFormatos"></canvas> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h3 class="card-title">Market Share por Distribuidora</h3> | |
| <p class="card-subtitle">Asistentes por empresa.</p> | |
| </div> | |
| <div class="doughnut-container"> | |
| <canvas id="chartDistribuidoras"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Table --> | |
| <div class="table-card"> | |
| <div class="table-header"> | |
| <h2 class="table-title">Detalle de Performance por Película</h2> | |
| <p class="table-subtitle">Ranking completo de las 10 películas más vistas.</p> | |
| </div> | |
| <table class="data-table"> | |
| <thead> | |
| <tr> | |
| <th>Rank</th> | |
| <th>Película</th> | |
| <th>Distribuidora</th> | |
| <th class="right">Espectadores</th> | |
| <th class="right">Recaudación</th> | |
| </tr> | |
| </thead> | |
| <tbody id="peliculas-table-body"> | |
| <!-- Table rows will be injected here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <!-- Footer --> | |
| <footer class="footer"> | |
| <a href="https://mostachia.com" target="_blank" class="mostachia-brand"> | |
| <div class="mostachia-logo">M</div> | |
| <div class="mostachia-text"> | |
| <strong>Generado por MostachIA</strong> | |
| Inteligencia de Negocios para Cines | |
| </div> | |
| </a> | |
| </footer> | |
| </div> | |
| <script> | |
| // Data from JSON | |
| const data = { | |
| "dashboardType": "pelicula", | |
| "dashboardTitle": "Top Películas Agosto 2025 - Asistentes y Facturación", | |
| "clientName": "Cinexo", | |
| "periodo": { | |
| "desde": "2025-08-01", | |
| "hasta": "2025-08-31", | |
| "descripcion": "Agosto 2025" | |
| }, | |
| "topPeliculas": [ | |
| { "pelicula": "Homo argentum", "formato": "2D", "distribuidora": "THE WALT DISNEY COMPANY SA", "espectadores": 8180, "recaudacion": 39308000 }, | |
| { "pelicula": "F1 2D+4D", "formato": "4D", "distribuidora": "WARNER BROS", "espectadores": 2490, "recaudacion": 13926000 }, | |
| { "pelicula": "Otro viernes de locos", "formato": "2D", "distribuidora": "THE WALT DISNEY COMPANY SA", "espectadores": 1863, "recaudacion": 8882000 }, | |
| { "pelicula": "Los 4 Fantásticos: Primeros pasos 3D+4D", "formato": "4D", "distribuidora": "THE WALT DISNEY COMPANY SA", "espectadores": 1707, "recaudacion": 9835000 }, | |
| { "pelicula": "La hora de la desaparición 2D+4D", "formato": "4D", "distribuidora": "WARNER BROS", "espectadores": 1395, "recaudacion": 7459500 }, | |
| { "pelicula": "Jurassic World: Renace 3D+4D", "formato": "4D", "distribuidora": "UNITED INTERNATIONAL PICTURES SRL", "espectadores": 1064, "recaudacion": 6235000 }, | |
| { "pelicula": "Los 4 Fantásticos: Primeros pasos 2D+4D", "formato": "4D", "distribuidora": "THE WALT DISNEY COMPANY SA", "espectadores": 1015, "recaudacion": 5307000 }, | |
| { "pelicula": "Jurassic World: Renace 2D+4D", "formato": "4D", "distribuidora": "UNITED INTERNATIONAL PICTURES SRL", "espectadores": 582, "recaudacion": 3280000 }, | |
| { "pelicula": "Los tipos malos 2", "formato": "2D", "distribuidora": "UNITED INTERNATIONAL PICTURES SRL", "espectadores": 487, "recaudacion": 2300000 }, | |
| { "pelicula": "Los tipos malos 2 3D", "formato": "3D", "distribuidora": "UNITED INTERNATIONAL PICTURES SRL", "espectadores": 474, "recaudacion": 2467000 } | |
| ], | |
| "distribucionPorFormato": { | |
| "labels": ["2D", "3D", "4D"], | |
| "datasets": [{ "label": "Asistentes", "data": [10530, 474, 8153] }] | |
| }, | |
| "distribucionPorDistribuidora": { | |
| "labels": ["THE WALT DISNEY COMPANY SA", "WARNER BROS", "UNITED INTERNATIONAL PICTURES SRL"], | |
| "datasets": [{ "label": "Asistentes", "data": [12765, 3885, 2607] }] | |
| } | |
| }; | |
| // Helper functions | |
| const formatCurrency = (value) => new Intl.NumberFormat('es-AR', { style: 'currency', currency: 'ARS', minimumFractionDigits: 0 }).format(value); | |
| const formatNumber = (value) => new Intl.NumberFormat('es-AR').format(value); | |
| // Download as PDF function | |
| function downloadPDF() { | |
| const element = document.getElementById('dashboard-content'); | |
| const opt = { | |
| margin: [0.5, 0.2, 0.5, 0.2], | |
| filename: `Reporte_Cinexo_${data.periodo.descripcion.replace(' ', '_')}.pdf`, | |
| image: { type: 'jpeg', quality: 0.98 }, | |
| html2canvas: { scale: 2, useCORS: true }, | |
| jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' } | |
| }; | |
| html2pdf().from(element).set(opt).save(); | |
| } | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Populate header and info | |
| document.getElementById('dashboard-title').textContent = data.dashboardTitle; | |
| document.getElementById('periodo-descripcion').textContent = data.periodo.descripcion; | |
| // Calculate KPIs | |
| const totalEspectadores = data.topPeliculas.reduce((sum, p) => sum + p.espectadores, 0); | |
| const totalRecaudacion = data.topPeliculas.reduce((sum, p) => sum + p.recaudacion, 0); | |
| const ticketPromedio = totalEspectadores > 0 ? totalRecaudacion / totalEspectadores : 0; | |
| const peliculaTop = data.topPeliculas[0]; | |
| // Render KPIs | |
| const kpiContainer = document.getElementById('kpi-container'); | |
| kpiContainer.innerHTML = ` | |
| <div class="kpi-card total"> | |
| <div class="kpi-icon">💰</div> | |
| <div class="kpi-label">Recaudación Total</div> | |
| <div class="kpi-value">${formatCurrency(totalRecaudacion)}</div> | |
| <div class="kpi-detail">${formatNumber(data.topPeliculas.length)} títulos en cartelera</div> | |
| </div> | |
| <div class="kpi-card"> | |
| <div class="kpi-icon">🎟️</div> | |
| <div class="kpi-label">Espectadores Totales</div> | |
| <div class="kpi-value">${formatNumber(totalEspectadores)}</div> | |
| <div class="kpi-detail">En todas las funciones del período</div> | |
| </div> | |
| <div class="kpi-card candy"> | |
| <div class="kpi-icon">📈</div> | |
| <div class="kpi-label">Ticket Promedio</div> | |
| <div class="kpi-value">${formatCurrency(ticketPromedio)}</div> | |
| <div class="kpi-detail">Ingreso promedio por espectador</div> | |
| </div> | |
| <div class="kpi-card"> | |
| <div class="kpi-icon">🏆</div> | |
| <div class="kpi-label">Película #1</div> | |
| <div class="kpi-value" style="font-size: 1.5rem;">${peliculaTop.pelicula}</div> | |
| <div class="kpi-detail">${formatNumber(peliculaTop.espectadores)} espectadores</div> | |
| </div> | |
| `; | |
| // Render Table | |
| const tableBody = document.getElementById('peliculas-table-body'); | |
| let tableHTML = ''; | |
| data.topPeliculas.forEach((p, index) => { | |
| const rank = index + 1; | |
| let rankClass = 'rank-other'; | |
| if (rank === 1) rankClass = 'rank-1'; | |
| if (rank === 2) rankClass = 'rank-2'; | |
| if (rank === 3) rankClass = 'rank-3'; | |
| tableHTML += ` | |
| <tr> | |
| <td> | |
| <div class="rank-cell"> | |
| <span class="rank-medal ${rankClass}">${rank}</span> | |
| </div> | |
| </td> | |
| <td> | |
| <span class="value-highlight">${p.pelicula}</span> | |
| <span class="format-badge badge-${p.formato}">${p.formato}</span> | |
| </td> | |
| <td>${p.distribuidora}</td> | |
| <td class="right value-highlight">${formatNumber(p.espectadores)}</td> | |
| <td class="right value-currency">${formatCurrency(p.recaudacion)}</td> | |
| </tr> | |
| `; | |
| }); | |
| tableBody.innerHTML = tableHTML; | |
| // Chart.js Configuration | |
| 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.position = 'bottom'; | |
| 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', | |
| primaryDark: '#4A9D80', | |
| secondary: '#1F3B4D', | |
| secondaryLight: '#2D5066', | |
| palette: ['#60B99A', '#1F3B4D', '#FFB74D', '#7FCDB2', '#2D5066', '#F59E0B', '#8B5CF6', '#EC4899'] | |
| }; | |
| // Bar Chart: Top Peliculas | |
| const top5Peliculas = data.topPeliculas.slice(0, 5); | |
| new Chart(document.getElementById('chartTopPeliculas'), { | |
| type: 'bar', | |
| data: { | |
| labels: top5Peliculas.map(p => p.pelicula), | |
| datasets: [{ | |
| label: 'Espectadores', | |
| data: top5Peliculas.map(p => p.espectadores), | |
| backgroundColor: function(context) { | |
| const chart = context.chart; | |
| const {ctx, chartArea} = chart; | |
| if (!chartArea) return chartColors.primary; | |
| const gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top); | |
| gradient.addColorStop(0, chartColors.primaryLight); | |
| gradient.addColorStop(1, chartColors.primary); | |
| return gradient; | |
| }, | |
| borderRadius: 8, | |
| borderSkipped: false, | |
| barThickness: 30, | |
| maxBarThickness: 40 | |
| }] | |
| }, | |
| 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) => formatNumber(value) | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: (ctx) => `${formatNumber(ctx.raw)} espectadores` | |
| } | |
| } | |
| }, | |
| scales: { | |
| x: { | |
| beginAtZero: true, | |
| grid: { color: 'rgba(0,0,0,0.05)', drawBorder: false }, | |
| ticks: { | |
| callback: (value) => value >= 1000 ? (value/1000) + 'K' : value | |
| } | |
| }, | |
| y: { | |
| grid: { display: false }, | |
| ticks: { font: { weight: '500' } } | |
| } | |
| } | |
| } | |
| }); | |
| // Doughnut Chart: Formatos | |
| new Chart(document.getElementById('chartFormatos'), { | |
| type: 'doughnut', | |
| data: { | |
| labels: data.distribucionPorFormato.labels, | |
| datasets: [{ | |
| data: data.distribucionPorFormato.datasets[0].data, | |
| backgroundColor: chartColors.palette, | |
| borderWidth: 0, | |
| hoverOffset: 15, | |
| hoverBorderWidth: 4, | |
| hoverBorderColor: '#fff' | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| cutout: '60%', | |
| plugins: { | |
| legend: { position: 'right' }, | |
| 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).toFixed(0); | |
| return percentage > 5 ? percentage + '%' : ''; | |
| } | |
| }, | |
| 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}%)`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Doughnut Chart: Distribuidoras | |
| new Chart(document.getElementById('chartDistribuidoras'), { | |
| type: 'doughnut', | |
| data: { | |
| labels: data.distribucionPorDistribuidora.labels.map(l => l.split(' ')[0]), | |
| datasets: [{ | |
| data: data.distribucionPorDistribuidora.datasets[0].data, | |
| backgroundColor: chartColors.palette, | |
| borderWidth: 0, | |
| hoverOffset: 15, | |
| hoverBorderWidth: 4, | |
| hoverBorderColor: '#fff' | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| cutout: '60%', | |
| plugins: { | |
| legend: { position: 'right' }, | |
| 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).toFixed(0); | |
| return percentage > 5 ? percentage + '%' : ''; | |
| } | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const originalLabel = data.distribucionPorDistribuidora.labels[context.dataIndex]; | |
| const total = context.dataset.data.reduce((a, b) => a + b, 0); | |
| const value = context.raw; | |
| const percentage = ((value / total) * 100).toFixed(1); | |
| return `${originalLabel}: ${formatNumber(value)} (${percentage}%)`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment