Sửa callout của hotspot hiển thị thumbnail và tooltip

This commit is contained in:
2026-06-08 17:35:40 +07:00
parent 3dbf2f2bbf
commit 306d95009f
5 changed files with 170 additions and 13 deletions
+1
View File
@@ -745,6 +745,7 @@ async function openScene(sceneId, privacy, shareToken, force = false) {
const scene = await sceneRes.json();
const hotspots = await hotspotsRes.json();
console.log("DEBUG: Hotspots raw data from API:", hotspots);
if (!sceneRes.ok) throw new Error(scene.message || 'Failed to fetch scene details');
+69 -12
View File
@@ -3,6 +3,40 @@ let currentHotspots = [];
let securityApplied = false;
let currentSceneOwnerId = null;
/**
* Hàm render tùy chỉnh cho hotspot để hiển thị bong bóng callout kèm ảnh thumbnail.
* Thay thế icon mặc định của Pannellum bằng cấu trúc HTML mới.
*/
function renderCustomHotspot(hotSpotDiv, args) {
// DỌN DẸP: Xóa sạch các ký tự mặc định (+ - []) của Pannellum
hotSpotDiv.innerHTML = '';
hotSpotDiv.classList.add('pnlm-custom-hotspot');
// Tạo container chính cho bong bóng
const callout = document.createElement('div');
callout.className = 'hotspot-callout-bubble';
// Tạo khung ảnh thumbnail (Luôn tạo để tránh bong bóng bị rỗng)
const imgWrapper = document.createElement('div');
imgWrapper.className = 'hotspot-thumb-frame';
if (args.thumbUrl) {
const img = document.createElement('img');
img.src = args.thumbUrl;
imgWrapper.appendChild(img);
}
callout.appendChild(imgWrapper);
// Thêm nhãn tiêu đề (tên cảnh đích)
const title = document.createElement('div');
title.className = 'hotspot-callout-title';
title.innerText = args.title;
callout.appendChild(title);
hotSpotDiv.appendChild(callout);
}
/**
* Initializes and shows the Pannellum 360° panorama viewer with security overlays.
* @param {string} imageUrl - Authorized URL to fetch the secure image stream
@@ -22,19 +56,42 @@ function initPanoramaViewer(imageUrl, hotspots = [], ownerId = null) {
}
// 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);
}
const token = localStorage.getItem('jwt');
const pannellumHotspots = hotspots.map(h => {
const target = h.target_scene_id;
let thumbUrl = '';
// Kiểm tra target phải là Object đã được populate thành công
if (target && typeof target === 'object' && target.assetId) {
const assetId = target.assetId._id || target.assetId;
thumbUrl = `/api/assets/view/${assetId}`;
// Đính kèm token để vượt qua kiểm tra quyền truy cập của middleware
if (token) thumbUrl += `?token=${token}`;
else if (target.privacy === 'shared' && target.shareToken) thumbUrl += `?token=${target.shareToken}`;
}
}));
return {
pitch: h.coordinates?.pitch || h.pitch,
yaw: h.coordinates?.yaw || h.yaw,
type: "custom",
createTooltipFunc: renderCustomHotspot,
createTooltipArgs: {
title: h.title || target?.name || target?.title || "Điểm điều hướng",
thumbUrl: thumbUrl
},
id: h._id,
clickHandlerFunc: () => {
if (target) {
const targetId = target._id || target;
const privacy = target.privacy || '';
const shareToken = target.shareToken || '';
// Chuyển cảnh với đầy đủ thông tin bảo mật
openScene(targetId, privacy, shareToken);
}
}
};
});
// Initialize Pannellum Equirectangular viewer
activeViewer = pannellum.viewer('panorama-viewer', {