Spaces:
Sleeping
Sleeping
| <html lang="es"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Resultado del Panorama</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <style> | |
| .panorama-container { | |
| position: relative; | |
| width: 100%; | |
| max-height: 70vh; | |
| overflow: hidden; | |
| margin-bottom: 20px; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 8px rgba(0,0,0,0.1); | |
| } | |
| .panorama-image { | |
| width: 100%; | |
| height: auto; | |
| display: block; | |
| } | |
| .action-buttons { | |
| margin-top: 20px; | |
| display: flex; | |
| gap: 10px; | |
| justify-content: center; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-light"> | |
| <div class="container py-5"> | |
| <h1 class="text-center mb-4">¡Tu Panorama está Listo!</h1> | |
| {% with messages = get_flashed_messages() %} | |
| {% if messages %} | |
| {% for message in messages %} | |
| <div class="alert alert-info alert-dismissible fade show" role="alert"> | |
| {{ message }} | |
| <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | |
| </div> | |
| {% endfor %} | |
| {% endif %} | |
| {% endwith %} | |
| <div class="card"> | |
| <div class="card-body"> | |
| <div class="panorama-container"> | |
| <img src="{{ url_for('static', filename=result_image) }}" | |
| class="panorama-image" | |
| alt="Panorama generado"> | |
| </div> | |
| <div class="action-buttons"> | |
| <a href="{{ url_for('download_file', filename=filename) }}" | |
| class="btn btn-primary"> | |
| <i class="bi bi-download"></i> Descargar Panorama | |
| </a> | |
| <button type="button" class="btn btn-info" onclick="openViewer()"> | |
| <i class="bi bi-eye"></i> Vista Cilíndrica | |
| </button> | |
| <form action="{{ url_for('share_panorama') }}" method="post" style="display: inline;"> | |
| <input type="hidden" name="result_path" value="{{ result_image }}"> | |
| <button type="submit" class="btn btn-success"> | |
| <i class="bi bi-share"></i> Compartir con la Comunidad | |
| </button> | |
| </form> | |
| <a href="{{ url_for('index') }}" class="btn btn-outline-secondary"> | |
| <i class="bi bi-plus-circle"></i> Crear Otro Panorama | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> | |
| <script> | |
| function openViewer() { | |
| // Crear modal para vista cilíndrica | |
| const modal = document.createElement('div'); | |
| modal.className = 'modal fade'; | |
| modal.setAttribute('tabindex', '-1'); | |
| modal.setAttribute('role', 'dialog'); | |
| modal.setAttribute('aria-hidden', 'true'); | |
| modal.innerHTML = ` | |
| <div class="modal-dialog modal-xl"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h5 class="modal-title">Vista Panorámica Cilíndrica</h5> | |
| <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
| </div> | |
| <div class="modal-body p-0"> | |
| <div id="panoramaViewer" style="height: 500px; width: 100%;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(modal); | |
| const modalInstance = new bootstrap.Modal(modal); | |
| // Cargar el visor panorámico después de que el modal se muestre completamente | |
| modal.addEventListener('shown.bs.modal', function() { | |
| loadPanoramaViewer(); | |
| }); | |
| modalInstance.show(); | |
| modal.addEventListener('hidden.bs.modal', function () { | |
| document.body.removeChild(modal); | |
| }); | |
| } | |
| function loadPanoramaViewer() { | |
| const viewer = document.getElementById('panoramaViewer'); | |
| const imageUrl = '{{ url_for("static", filename=result_image) }}'; | |
| // Crear canvas para el visor panorámico | |
| const canvas = document.createElement('canvas'); | |
| canvas.width = viewer.offsetWidth; | |
| canvas.height = viewer.offsetHeight; | |
| canvas.style.cursor = 'grab'; | |
| viewer.appendChild(canvas); | |
| const ctx = canvas.getContext('2d'); | |
| const img = new Image(); | |
| let isDragging = false; | |
| let lastX = 0; | |
| let offsetX = 0; | |
| img.onload = function() { | |
| drawPanorama(); | |
| }; | |
| function drawPanorama() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Calcular escala para ajustar la imagen al canvas | |
| const scale = canvas.height / img.height; | |
| const scaledWidth = img.width * scale; | |
| // Dibujar la imagen con offset para simular rotación | |
| ctx.drawImage(img, offsetX, 0, scaledWidth, canvas.height); | |
| // Si la imagen no cubre todo el ancho, repetir | |
| if (scaledWidth + offsetX < canvas.width) { | |
| ctx.drawImage(img, offsetX + scaledWidth, 0, scaledWidth, canvas.height); | |
| } | |
| if (offsetX > 0) { | |
| ctx.drawImage(img, offsetX - scaledWidth, 0, scaledWidth, canvas.height); | |
| } | |
| } | |
| // Eventos de mouse para arrastrar | |
| canvas.addEventListener('mousedown', (e) => { | |
| isDragging = true; | |
| lastX = e.clientX; | |
| canvas.style.cursor = 'grabbing'; | |
| }); | |
| canvas.addEventListener('mousemove', (e) => { | |
| if (isDragging) { | |
| const deltaX = e.clientX - lastX; | |
| offsetX += deltaX; | |
| // Mantener el offset en un rango válido | |
| const scale = canvas.height / img.height; | |
| const scaledWidth = img.width * scale; | |
| if (offsetX > scaledWidth) offsetX -= scaledWidth; | |
| if (offsetX < -scaledWidth) offsetX += scaledWidth; | |
| drawPanorama(); | |
| lastX = e.clientX; | |
| } | |
| }); | |
| canvas.addEventListener('mouseup', () => { | |
| isDragging = false; | |
| canvas.style.cursor = 'grab'; | |
| }); | |
| canvas.addEventListener('mouseleave', () => { | |
| isDragging = false; | |
| canvas.style.cursor = 'grab'; | |
| }); | |
| img.src = imageUrl; | |
| } | |
| </script> | |
| </body> | |
| </html> |