let activeViewer = null; /** * Initializes and shows the Pannellum 360° panorama viewer with security overlays. * @param {string} imageUrl - Authorized URL to fetch the secure image stream */ function initPanoramaViewer(imageUrl) { const container = document.getElementById('viewer-container'); container.style.display = 'block'; if (activeViewer) { try { activeViewer.destroy(); } catch (e) {} } // Initialize Pannellum Equirectangular viewer activeViewer = pannellum.viewer('panorama-viewer', { "type": "equirectangular", "panorama": imageUrl, "autoLoad": true, "showControls": true, "compass": false, "mouseZoom": true, "keyboardZoom": true }); // Security constraints inside the viewer applyViewerSecurity(); } /** * Closes and destroys the active panorama viewer. */ function closeViewer() { document.getElementById('viewer-container').style.display = 'none'; if (activeViewer) { try { activeViewer.destroy(); } catch (e) {} activeViewer = null; } } /** * Appends event listeners to block right-clicks and common image saving shortcuts. */ function applyViewerSecurity() { const viewer = document.getElementById('viewer-container'); // Block right-clicks inside the 3D Viewer Container viewer.addEventListener('contextmenu', (e) => { e.preventDefault(); alert('Security Alert: Direct image downloading or copying is disabled on this asset.'); }); // Block drag and drop viewer.addEventListener('dragstart', (e) => { e.preventDefault(); }); } // Global safety shortcut listeners (F12, Ctrl+S, Ctrl+U, Ctrl+Shift+I) document.addEventListener('keydown', (e) => { // Only enforce when viewer is active if (document.getElementById('viewer-container').style.display === 'block') { const isCtrlS = e.ctrlKey && (e.key === 's' || e.key === 'S'); const isCtrlU = e.ctrlKey && (e.key === 'u' || e.key === 'U'); const isF12 = e.key === 'F12'; const isCtrlShiftI = e.ctrlKey && e.shiftKey && (e.key === 'i' || e.key === 'I'); if (isCtrlS || isCtrlU || isF12 || isCtrlShiftI) { e.preventDefault(); alert('Security Alert: Inspection and saving functions are restricted on this viewer.'); return false; } } });