let activeViewer = null; let currentHotspots = []; let securityApplied = false; let currentSceneOwnerId = null; /** * Initializes and shows the Pannellum 360° panorama viewer with security overlays. * @param {string} imageUrl - Authorized URL to fetch the secure image stream * @param {Array} hotspots - List of hotspots from the database * @param {string} ownerId - ID of the scene owner */ function initPanoramaViewer(imageUrl, hotspots = [], ownerId = null) { currentHotspots = hotspots; currentSceneOwnerId = ownerId; const container = document.getElementById('viewer-container'); container.style.display = 'block'; if (activeViewer) { try { activeViewer.destroy(); } catch (e) {} } // Chuyển đổi dữ liệu hotspots từ DB sang định dạng Pannellum const pannellumHotspots = hotspots.map(h => ({ pitch: h.coordinates?.pitch || h.pitch, yaw: h.coordinates?.yaw || h.yaw, type: "info", text: h.title || "Điểm điều hướng", id: h._id, clickHandlerFunc: () => { if (h.target_scene_id || h.targetSceneId) { // Gọi hàm openScene từ main_map.js openScene(h.target_scene_id || h.targetSceneId); } } })); // Initialize Pannellum Equirectangular viewer activeViewer = pannellum.viewer('panorama-viewer', { "type": "equirectangular", "panorama": imageUrl, "autoLoad": true, "showControls": true, "compass": false, "mouseZoom": true, "keyboardZoom": true, "crossOrigin": "anonymous", "hotSpots": pannellumHotspots }); // Security constraints inside the viewer applyViewerSecurity(); } /** * Closes and destroys the active panorama viewer. */ function closeViewer() { document.getElementById('viewer-container').style.display = 'none'; // Xóa trạng thái Scene đang hoạt động khi đóng viewer localStorage.removeItem('activeSceneId'); localStorage.removeItem('activeScenePrivacy'); localStorage.removeItem('activeSceneToken'); if (activeViewer) { try { activeViewer.destroy(); } catch (e) {} activeViewer = null; } } /** * Appends event listeners to block right-clicks and common image saving shortcuts. */ function applyViewerSecurity() { if (securityApplied) return; // Chỉ gán sự kiện một lần duy nhất securityApplied = true; // Target the actual viewer element where Pannellum renders const container = document.getElementById('viewer-container'); const panoramaViewer = document.getElementById('panorama-viewer'); const handleContextMenu = (e) => { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); // Nếu viewer đang hoạt động, lấy tọa độ Pitch/Yaw tại điểm click if (activeViewer) { // Kiểm tra phân quyền trước khi cho phép tương tác chuột phải const userRole = localStorage.getItem('role'); const currentUserId = localStorage.getItem('userId'); // Phân quyền: Admin (Chủ sở hữu) hoặc Người tạo ra Scene này const isAdmin = userRole === 'Chủ sở hữu' || userRole === 'admin'; const isAuthorized = isAdmin || (currentUserId && currentSceneOwnerId && currentUserId.toString() === currentSceneOwnerId.toString()); // Lấy tọa độ cầu (Pitch/Yaw) từ điểm click chuột const coords = activeViewer.mouseEventToCoords(e); if (!coords) return false; const pitch = coords[0]; const yaw = coords[1]; // Kiểm tra xem có hotspot nào gần điểm click không (ngưỡng 2 độ) const existing = currentHotspots.find(h => Math.abs((h.coordinates?.pitch || h.pitch) - pitch) < 2 && Math.abs((h.coordinates?.yaw || h.yaw) - yaw) < 2 ); // Nếu không được phép, dừng xử lý và chặn menu mặc định if (!isAuthorized) return false; if (existing) { // ĐÃ CÓ Hotspot -> Hiện Menu: [Sửa Hotspot] / [Xóa Hotspot] if (typeof window.openHotspotMenu === 'function') { window.openHotspotMenu(existing); } } else { // CHƯA CÓ Hotspot -> Hiện Form: [Tạo mới Hotspot] if (typeof window.handleHotspotCreation === 'function') { window.handleHotspotCreation(pitch, yaw, null); } } console.log(`Coordinates captured: Pitch ${pitch}, Yaw ${yaw}`); } return false; }; // Sử dụng capture phase (true) để bắt sự kiện trước khi nó chạm đến Pannellum container.addEventListener('contextmenu', handleContextMenu, true); panoramaViewer.addEventListener('contextmenu', handleContextMenu, true); // Block drag and drop container.addEventListener('dragstart', (e) => { e.preventDefault(); }); } // Global safety shortcut listeners (Ctrl+S, Ctrl+U) - Tạm thời cho phép F12 và Ctrl+Shift+I để debug 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'); if (isCtrlS || isCtrlU) { e.preventDefault(); console.warn('Security Alert: Inspection and saving functions are restricted.'); return false; } } });