Cho phép chỉnh sửa tọa độ của điểm quay lại cho chính xác với hướng nhìn

This commit is contained in:
2026-06-12 15:48:17 +07:00
parent 2e5fef229f
commit 133a8721bb
2 changed files with 107 additions and 18 deletions
+27 -3
View File
@@ -518,16 +518,40 @@
<div id="hotspot-modal" class="modal-overlay" style="display: none; z-index: 3000;"> <div id="hotspot-modal" class="modal-overlay" style="display: none; z-index: 3000;">
<div class="modal-content action-modal-content logout-modal-dark" style="max-width: 500px; border-top: 4px solid #ffc107;"> <div class="modal-content action-modal-content logout-modal-dark" style="max-width: 500px; border-top: 4px solid #ffc107;">
<div class="modal-header"> <div class="modal-header">
<h3 id="hotspot-modal-title">Biên tập điểm điều hướng</h3> <h3 id="hotspot-modal-title">Thêm/sửa điểm điều hướng</h3>
<span class="close-btn" onclick="closeHotspotModal()">&times;</span> <span class="close-btn" onclick="closeHotspotModal()">&times;</span>
</div> </div>
<form id="hotspot-form"> <form id="hotspot-form">
<!-- Tọa độ ẩn để xử lý GPS và vị trí --> <!-- Tọa độ ẩn để xử lý GPS và vị trí -->
<input type="hidden" id="hs-pitch"> <div class="form-group" style="background: rgba(255,193,7,0.05); padding: 10px; border-radius: 6px; border: 1px dashed #ffc107; margin-bottom: 15px;">
<input type="hidden" id="hs-yaw"> <label style="color: #ffc107; font-size: 12px; margin-bottom: 8px;">Vị trí hiển thị (Pitch/Yaw):</label>
<div style="display: flex; gap: 10px; align-items: center;">
<input type="text" id="hs-pitch" readonly style="flex: 1; background: #222; border: 1px solid #444; color: #fff; text-align: center; font-family: monospace;">
<input type="text" id="hs-yaw" readonly style="flex: 1; background: #222; border: 1px solid #444; color: #fff; text-align: center; font-family: monospace;">
<button type="button" onclick="updateHotspotCoordsFromView()" class="edit-btn-small" style="background: #007bff; white-space: nowrap; height: 34px; padding: 0 10px;">
<i class="fas fa-crosshairs"></i> Lấy tọa độ hiện tại
</button>
</div>
<small style="display: block; color: #888; font-size: 10px; margin-top: 5px;">* Xoay ảnh đến vị trí mong muốn rồi nhấn nút để cập nhật điểm đặt bong bóng.</small>
</div>
<input type="hidden" id="hs-id"> <input type="hidden" id="hs-id">
<div class="form-group divider">
<label>Hành động:</label>
<div class="radio-group">
<label class="radio-item"><input type="radio" name="hsActionMode" value="create" checked onclick="toggleHSActionMode('create')"> Thêm mới</label>
<label class="radio-item"><input type="radio" name="hsActionMode" value="edit" onclick="toggleHSActionMode('edit')"> Sửa điểm có sẵn</label>
</div>
</div>
<div id="hs-edit-select-container" class="form-group" style="display: none; background: rgba(0, 123, 255, 0.1); padding: 10px; border-radius: 6px; border: 1px solid #007bff;">
<label for="hs-to-edit-id" style="color: #00d4ff;">Chọn điểm để sửa:</label>
<select id="hs-to-edit-id" onchange="onSelectHotspotToEdit(this.value)" style="background: #111; color: #fff; border: 1px solid #007bff;">
<option value="">-- Chọn điểm trong Viewer --</option>
</select>
</div>
<div class="form-group"> <div class="form-group">
<label for="hs-title">Tiêu đề (Label)</label> <label for="hs-title">Tiêu đề (Label)</label>
<input type="text" id="hs-title" name="title" placeholder="Ví dụ: Cổng vào, Phòng khách..." required> <input type="text" id="hs-title" name="title" placeholder="Ví dụ: Cổng vào, Phòng khách..." required>
+80 -15
View File
@@ -1467,6 +1467,24 @@ function restoreActiveScene() {
} }
} }
/**
* Cập nhật tọa độ Pitch/Yaw cho hotspot từ góc nhìn trung tâm hiện tại của Viewer
*/
window.updateHotspotCoordsFromView = function() {
// activeViewer được quản lý trong viewer360.js
if (typeof activeViewer !== 'undefined' && activeViewer) {
const pitch = activeViewer.getPitch();
const yaw = activeViewer.getYaw();
document.getElementById('hs-pitch').value = pitch.toFixed(2);
document.getElementById('hs-yaw').value = yaw.toFixed(2);
showNotification(`Đã ghi nhận vị trí mới: Pitch ${pitch.toFixed(2)}, Yaw ${yaw.toFixed(2)}`, 'success');
} else {
showNotification("Viewer không hoạt động, không thể lấy tọa độ.", "error");
}
};
/** /**
* Xử lý việc tạo hotspot sau khi click chuột phải trong trình xem 360 * Xử lý việc tạo hotspot sau khi click chuột phải trong trình xem 360
* @param {number} pitch - Tọa độ dọc (-90 đến 90) * @param {number} pitch - Tọa độ dọc (-90 đến 90)
@@ -1486,14 +1504,34 @@ window.handleHotspotCreation = async function(pitch, yaw, existingHotspot = null
// Hiển thị Modal TRƯỚC để các logic UI (như Mini Map) tính toán được kích thước // Hiển thị Modal TRƯỚC để các logic UI (như Mini Map) tính toán được kích thước
modal.style.display = 'flex'; modal.style.display = 'flex';
// Reset form và gán tọa độ // Reset form và gán tọa độ click ban đầu
form.reset(); form.reset();
document.getElementById('hs-pitch').value = pitch; document.getElementById('hs-pitch').value = pitch;
document.getElementById('hs-yaw').value = yaw; document.getElementById('hs-yaw').value = yaw;
document.getElementById('hs-id').value = existingHotspot ? existingHotspot._id : ''; document.getElementById('hs-id').value = existingHotspot ? existingHotspot._id : '';
document.getElementById('hotspot-modal-title').innerText = existingHotspot ? 'Cập nhật điểm điều hướng' : 'Thêm điểm điều hướng mới'; document.getElementById('hotspot-modal-title').innerText = 'Thêm/sửa điểm điều hướng';
// Nạp danh sách hotspot hiện có trong Viewer vào dropdown chỉnh sửa
const editSelect = document.getElementById('hs-to-edit-id');
editSelect.innerHTML = '<option value="">-- Chọn điểm trong Viewer --</option>';
if (typeof currentHotspots !== 'undefined' && currentHotspots.length > 0) {
currentHotspots.forEach(h => {
editSelect.innerHTML += `<option value="${h._id}">${h.title || 'Không tiêu đề'} (ID: ...${h._id.slice(-4)})</option>`;
});
}
// Reset UI states // Reset UI states
if (existingHotspot) {
document.querySelector('input[name="hsActionMode"][value="edit"]').checked = true;
toggleHSActionMode('edit');
editSelect.value = existingHotspot._id;
// Điền dữ liệu của hotspot được click vào form
onSelectHotspotToEdit(existingHotspot._id);
} else {
document.querySelector('input[name="hsActionMode"][value="create"]').checked = true;
toggleHSActionMode('create');
}
document.querySelector('input[name="hsLinkType"][value="existing"]').checked = true; document.querySelector('input[name="hsLinkType"][value="existing"]').checked = true;
window.toggleHSLinkType('existing'); window.toggleHSLinkType('existing');
document.querySelector('input[name="hsGPSMode"][value="map"]').checked = true; document.querySelector('input[name="hsGPSMode"][value="map"]').checked = true;
@@ -1536,17 +1574,6 @@ window.handleHotspotCreation = async function(pitch, yaw, existingHotspot = null
if (existingNotice) existingNotice.style.opacity = '1'; if (existingNotice) existingNotice.style.opacity = '1';
} }
}; };
// QUAN TRỌNG: Chỉ điền dữ liệu hotspot cũ SAU KHI dropdown đã được nạp đầy đủ options
if (existingHotspot) {
document.getElementById('hs-title').value = existingHotspot.title || '';
document.getElementById('hs-desc').value = existingHotspot.description || '';
if (existingHotspot.target_scene_id) {
select.value = existingHotspot.target_scene_id;
// Kích hoạt logic hiển thị thông báo ngay khi mở modal nếu đang sửa
if (typeof select.onchange === 'function') select.onchange();
}
}
} catch (e) { console.error("Lỗi nạp danh sách scene:", e); } } catch (e) { console.error("Lỗi nạp danh sách scene:", e); }
// Xử lý sự kiện submit form // Xử lý sự kiện submit form
@@ -1554,6 +1581,7 @@ window.handleHotspotCreation = async function(pitch, yaw, existingHotspot = null
e.preventDefault(); e.preventDefault();
const formData = new FormData(form); const formData = new FormData(form);
const linkType = formData.get('hsLinkType'); const linkType = formData.get('hsLinkType');
const hotspotId = document.getElementById('hs-id').value;
if (linkType === 'upload') { if (linkType === 'upload') {
const file = document.getElementById('hs-panorama-file').files[0]; const file = document.getElementById('hs-panorama-file').files[0];
@@ -1592,7 +1620,7 @@ window.handleHotspotCreation = async function(pitch, yaw, existingHotspot = null
if (activeTourId) sceneData.append('tourId', activeTourId); if (activeTourId) sceneData.append('tourId', activeTourId);
uploadWithProgress(`${API_BASE_URL}/scenes`, 'POST', sceneData, token, 'hs', async (sceneRes) => { uploadWithProgress(`${API_BASE_URL}/scenes`, 'POST', sceneData, token, 'hs', async (sceneRes) => {
await saveHotspotToDB(pitch, yaw, formData.get('title'), formData.get('description'), sceneRes.scene._id, existingHotspot?._id); await saveHotspotToDB(pitch, yaw, formData.get('title'), formData.get('description'), sceneRes.scene._id, hotspotId);
closeHotspotModal(); closeHotspotModal();
}); });
return; return;
@@ -1603,11 +1631,48 @@ window.handleHotspotCreation = async function(pitch, yaw, existingHotspot = null
showNotification('Vui lòng chọn cảnh để liên kết.', 'warning'); showNotification('Vui lòng chọn cảnh để liên kết.', 'warning');
return; return;
} }
await saveHotspotToDB(pitch, yaw, formData.get('title'), formData.get('description'), finalTargetId, existingHotspot?._id); await saveHotspotToDB(pitch, yaw, formData.get('title'), formData.get('description'), finalTargetId, hotspotId);
closeHotspotModal(); closeHotspotModal();
}; };
}; };
/**
* Chuyển đổi giữa chế độ Thêm mới và Sửa điểm có sẵn
*/
window.toggleHSActionMode = function(mode) {
const selectContainer = document.getElementById('hs-edit-select-container');
selectContainer.style.display = mode === 'edit' ? 'block' : 'none';
if (mode === 'create') {
document.getElementById('hs-id').value = '';
// Giữ nguyên pitch/yaw vừa click, chỉ reset text
document.getElementById('hs-title').value = '';
document.getElementById('hs-desc').value = '';
}
};
/**
* Điền thông tin khi người dùng chọn một hotspot từ danh sách để sửa
*/
window.onSelectHotspotToEdit = function(id) {
if (!id) return;
// currentHotspots được quản lý trong viewer360.js
const hs = currentHotspots.find(h => h._id === id);
if (hs) {
document.getElementById('hs-id').value = hs._id;
document.getElementById('hs-title').value = hs.title || '';
document.getElementById('hs-desc').value = hs.description || '';
// Giữ nguyên tọa độ pitch/yaw từ điểm vừa click chuột phải
// Không ghi đè bằng tọa độ cũ của hotspot để thực hiện việc di chuyển vị trí
if (hs.target_scene_id) {
const targetId = hs.target_scene_id._id || hs.target_scene_id;
document.getElementById('hs-target-id').value = targetId;
}
}
};
/** /**
* Đóng Modal biên tập Hotspot * Đóng Modal biên tập Hotspot
*/ */