Files
3dtours/frontend/js/viewer360.js
T

133 lines
4.5 KiB
JavaScript

let activeViewer = null;
let currentHotspots = [];
/**
* 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
*/
function initPanoramaViewer(imageUrl, hotspots = []) {
currentHotspots = hotspots;
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.pitch,
yaw: h.yaw,
type: "info",
text: h.text || "Điểm điều hướng",
id: h._id,
clickHandlerFunc: () => {
if (h.targetSceneId) {
// Gọi hàm openScene từ main_map.js
openScene(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() {
// 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) {
// Lấy tọa độ cầu (Pitch/Yaw) từ điểm click chuột
const coords = activeViewer.mouseEventToCoords(e);
if (!coords) return;
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.pitch - pitch) < 2 && Math.abs(h.yaw - yaw) < 2
);
if (typeof window.handleHotspotCreation === 'function') {
window.handleHotspotCreation(pitch, yaw, existing);
} else {
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 (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;
}
}
});