PageSourceSearch

https://lunarapp-urania-production.up.railway.app/static/js/luna-realista.js

js lunarapp-urania-production.up.railway.app collected 2026-10-03 12:12:55 UTC 5,596 bytes, 165 lines download raw bytes

1/**
2 * Sistema de renderizado de fases lunares usando fotos reales de NASA
3 * Versión 5.0 - Fotos Estáticas
4 */
5
6class LunaRealista {
7    constructor() {
8        this.imagenesCargadas = {};
9        this.cargando = new Set();
10    }
11    
12    /**
13     * Carga una imagen de fase lunar
14     */
15    async cargarImagen(diaCiclo) {
16        // Si ya está cargada, retornarla
17        if (this.imagenesCargadas[diaCiclo]) {
18            return this.imagenesCargadas[diaCiclo];
19        }
20        
21        // Si ya se está cargando, esperar
22        if (this.cargando.has(diaCiclo)) {
23            return new Promise((resolve) => {
24                const checkInterval = setInterval(() => {
25                    if (this.imagenesCargadas[diaCiclo]) {
26                        clearInterval(checkInterval);
27                        resolve(this.imagenesCargadas[diaCiclo]);
28                    }
29                }, 50);
30            });
31        }
32        
33        // Marcar como cargando
34        this.cargando.add(diaCiclo);
35        
36        return new Promise((resolve, reject) => {
37            const img = new Image();
38            const numeroFase = String(diaCiclo).padStart(2, '0');
39            
40            img.onload = () => {
41                this.imagenesCargadas[diaCiclo] = img;
42                this.cargando.delete(diaCiclo);
43                resolve(img);
44            };
45            
46            img.onerror = () => {
47                this.cargando.delete(diaCiclo);
48                console.error(`❌ Error cargando fase_${numeroFase}.jpg`);
49                reject(new Error(`No se pudo cargar fase_${numeroFase}.jpg`));
50            };
51            
52            img.src = `/static/images/fases/fase_${numeroFase}.jpg`;
53        });
54    }
55    
56    /**
57     * Crea un placeholder mientras carga la imagen
58     */
59    crearPlaceholder(size) {
60        const canvas = document.createElement('canvas');
61        canvas.width = size;
62        canvas.height = size;
63        const ctx = canvas.getContext('2d');
64        
65        // Círculo gris simple
66        ctx.fillStyle = '#555';
67        ctx.beginPath();
68        ctx.arc(size/2, size/2, size/2, 0, Math.PI * 2);
69        ctx.fill();
70        
71        return canvas;
72    }
73    
74    /**
75     * Renderiza la Luna en un elemento del DOM
76     * 
77     * @param {HTMLElement} elemento - Elemento donde renderizar
78     * @param {number} diaCiclo - Día del ciclo lunar (1-30)
79     * @param {number} size - Tamaño del canvas en píxeles
80     */
81    async renderizar(elemento, diaCiclo, size = 200) {
82        try {
83            // Validar diaCiclo
84            if (!diaCiclo || diaCiclo < 1 || diaCiclo > 30) {
85                console.warn(`⚠️ Día de ciclo inválido: ${diaCiclo}, usando 1`);
86                diaCiclo = 1;
87            }
88            
89            // Mostrar placeholder mientras carga
90            const placeholder = this.crearPlaceholder(size);
91            elemento.innerHTML = '';
92            placeholder.style.width = '100%';
93            placeholder.style.height = 'auto';
94            elemento.appendChild(placeholder);
95            
96            // Cargar imagen real
97            const img = await this.cargarImagen(diaCiclo);
98            
99            // Crear canvas final
100            const canvas = document.createElement('canvas');
101            canvas.width = size;
102            canvas.height = size;
103            const ctx = canvas.getContext('2d');
104            
105            // ===== APLICAR MÁSCARA CIRCULAR (quita el fondo negro) =====
106            // 1. Crear clip circular exacto al tamaño de la luna
107            // Medido: la luna en las fotos NASA ocupa el 87% del tamaño
108            ctx.save();
109            ctx.beginPath();
110            const radio = (size / 2) * 0.87; // Radio exacto de la luna
111            ctx.arc(size/2, size/2, radio, 0, Math.PI * 2);
112            ctx.clip();
113            
114            // 2. Dibujar imagen (solo se verá dentro del círculo)
115            ctx.drawImage(img, 0, 0, size, size);
116            
117            // 3. Restaurar contexto
118            ctx.restore();
119            // ============================================================
120            
121            // Reemplazar placeholder con imagen real
122            elemento.innerHTML = '';
123            canvas.style.width = '100%';
124            canvas.style.height = 'auto';
125            canvas.style.filter = 'drop-shadow(0 2px 10px rgba(212, 175, 55, 0.3))';
126            elemento.appendChild(canvas);
127            
128        } catch (error) {
129            console.error('Error renderizando luna:', error);
130            // Dejar el placeholder en caso de error
131        }
132    }
133    
134    /**
135     * Precarga todas las imágenes (opcional, para mejor performance)
136     */
137    async precargarTodas() {
138        console.log('📥 Precargando 30 fases lunares...');
139        const promesas = [];
140        
141        for (let dia = 1; dia <= 30; dia++) {
142            promesas.push(this.cargarImagen(dia));
143        }
144        
145        try {
146            await Promise.all(promesas);
147            console.log('✅ 30 fases lunares precargadas');
148        } catch (error) {
149            console.error('❌ Error precargando fases:', error);
150        }
151    }
152}
153
154// Exportar instancia global
155window.lunaRealista = new LunaRealista();
156
157// Precargar imágenes cuando el DOM esté listo
158if (document.readyState === 'loading') {
159    document.addEventListener('DOMContentLoaded', () => {
160        // Precargar en segundo plano (no bloquea la UI)
161        setTimeout(() => window.lunaRealista.precargarTodas(), 500);
162    });
163} else {
164    setTimeout(() => window.lunaRealista.precargarTodas(), 500);
165}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.