263 lines
9.6 KiB
JavaScript
263 lines
9.6 KiB
JavaScript
const debugPanel = document.getElementById('debug-panel');
|
|
const infoPanel = document.getElementById('info-panel');
|
|
const infoButton = document.getElementById('info-button');
|
|
const moveButton = document.getElementById('move-button');
|
|
const toolPalette = document.getElementById('tool-palette');
|
|
|
|
let infoPanelPinned = false;
|
|
let pinnedBuildingData = null;
|
|
let debugOn = true;
|
|
let interactableObjects = [];
|
|
let INTERSECTED;
|
|
|
|
// Add these variables at the top of your file (outside any function)
|
|
let lastFpsUpdate = performance.now();
|
|
let frameCount = 0;
|
|
let currentFps = 0;
|
|
|
|
// Call this in your animation loop (e.g., in animate() in main.js)
|
|
function updateFps() {
|
|
frameCount++;
|
|
const now = performance.now();
|
|
if (now - lastFpsUpdate > 500) { // Update every 0.5s
|
|
currentFps = (frameCount * 1000) / (now - lastFpsUpdate);
|
|
lastFpsUpdate = now;
|
|
frameCount = 0;
|
|
}
|
|
}
|
|
|
|
function initPanels(){
|
|
window.addEventListener('keydown', function(event) {
|
|
if (event.key === 'h') {
|
|
console.log('H');
|
|
hideDebugPanel()
|
|
debugOn = !debugOn;
|
|
}
|
|
});
|
|
/* renderer.domElement.addEventListener('pointerdown', function(event) {
|
|
// Calculate mouse position in normalized device coordinates
|
|
const rect = renderer.domElement.getBoundingClientRect();
|
|
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
|
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
|
|
|
raycaster.setFromCamera(mouse, camera);
|
|
const intersects = raycaster.intersectObjects(interactableObjects);
|
|
|
|
if (intersects.length > 0) {
|
|
console.log(intersects[0].object);
|
|
// Pin the info panel to this building
|
|
infoPanelPinned = true;
|
|
const selected = intersects[0].object.userData.parentGroup || intersects[0].object;
|
|
pinnedBuildingData = selected.userData;
|
|
displayInfo(pinnedBuildingData);
|
|
} else {
|
|
// Unpin if clicking empty space
|
|
infoPanelPinned = false;
|
|
pinnedBuildingData = null;
|
|
hideInfo();
|
|
}
|
|
}); */
|
|
document.addEventListener('mousemove', onMouseMove, false);
|
|
|
|
toolPalette.addEventListener('mouseup', (event) => event.stopPropagation(), false);
|
|
|
|
// Tool Palette Button Listeners
|
|
infoButton.addEventListener('click', showInfoPanelForSelected);
|
|
moveButton.addEventListener('click', () => {
|
|
if (selectedObject) {
|
|
console.log("Move tool clicked for:", selectedObject.userData.description);
|
|
// Add move logic here later
|
|
hideToolPalette(); // Hide palette after action (optional)
|
|
}
|
|
});
|
|
}
|
|
|
|
function onMouseMove(event) {
|
|
if (infoPanelPinned) return;
|
|
// Calculate mouse position (Unchanged)
|
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
|
|
|
// --- Info Panel Positioning (Adjusted for bottom-left) ---
|
|
const panelRect = infoPanel.getBoundingClientRect();
|
|
let panelX = event.clientX + 15;
|
|
let panelY = event.clientY - panelRect.height - 15; // Position above cursor
|
|
|
|
// Basic boundary checks (adjust as needed)
|
|
if (panelX + panelRect.width > window.innerWidth - 10) {
|
|
panelX = event.clientX - panelRect.width - 15;
|
|
}
|
|
if (panelY < 10) { // Check top boundary
|
|
panelY = event.clientY + 15; // Move below cursor if too high
|
|
}
|
|
if (panelX < 10) panelX = 10; // Prevent going off left
|
|
|
|
infoPanel.style.left = `${panelX}px`;
|
|
infoPanel.style.top = `${panelY}px`;
|
|
}
|
|
|
|
// --- Debug Panel ---
|
|
function displaySunDebug() {
|
|
const pos = directionalLight.position;
|
|
debugPanel.innerHTML = `<h3>Debug Info</h3>
|
|
<p><strong>Position:</strong> (${pos.x.toFixed(2)}, ${pos.y.toFixed(2)}, ${pos.z.toFixed(2)})</p>`;
|
|
debugPanel.style.display = 'block';
|
|
}
|
|
|
|
function displayDebugPanel(object) {
|
|
if (!object || !object.position) {
|
|
debugPanel.style.display = 'none';
|
|
return;
|
|
}
|
|
const pos = object.position;
|
|
debugPanel.innerHTML = `<h3>Debug Info</h3>
|
|
<p><strong>ID:</strong> ${object.userData?.id ?? 'N/A'}</p>
|
|
<p><strong>Position:</strong> (${pos.x.toFixed(2)}, ${pos.y.toFixed(2)}, ${pos.z.toFixed(2)})</p>`;
|
|
debugPanel.style.display = 'block';
|
|
}
|
|
|
|
function hideDebugPanel() {
|
|
debugPanel.style.display = 'none';
|
|
}
|
|
|
|
function showToolPalette(targetObject) {
|
|
if (!targetObject) return;
|
|
|
|
// Calculate screen position of the object
|
|
const screenPos = toScreenPosition(targetObject, camera);
|
|
|
|
// Position palette slightly above and to the right of the object's center
|
|
toolPalette.style.left = `${screenPos.x + 10}px`;
|
|
toolPalette.style.top = `${screenPos.y - toolPalette.offsetHeight - 10}px`; // Offset by palette height
|
|
|
|
// Basic boundary check (prevent going off screen) - needs improvement
|
|
const paletteRect = toolPalette.getBoundingClientRect(); // Get actual size after potential content change
|
|
if (parseInt(toolPalette.style.left) + paletteRect.width > window.innerWidth - 10) {
|
|
toolPalette.style.left = `${window.innerWidth - paletteRect.width - 10}px`;
|
|
}
|
|
if (parseInt(toolPalette.style.top) < 10) {
|
|
toolPalette.style.top = '10px';
|
|
}
|
|
if (parseInt(toolPalette.style.left) < 10) {
|
|
toolPalette.style.left = '10px';
|
|
}
|
|
|
|
|
|
toolPalette.style.display = 'flex'; // Use flex to show it
|
|
}
|
|
|
|
function hideToolPalette() {
|
|
toolPalette.style.display = 'none';
|
|
}
|
|
|
|
function showInfoPanelForSelected() {
|
|
if (selectedObject && selectedObject.userData) {
|
|
displayInfo(selectedObject.userData);
|
|
} else {
|
|
hideInfoPanel();
|
|
}
|
|
// Optionally hide palette after clicking info
|
|
// hideToolPalette();
|
|
}
|
|
|
|
function displayInfo(buildingData) {
|
|
document.getElementById('info-title').textContent = buildingData.description;
|
|
document.getElementById('info-consumption').textContent = buildingData.consumption;
|
|
document.getElementById('info-generation').textContent = buildingData.generation;
|
|
document.getElementById('info-iot').textContent = buildingData.iot;
|
|
infoPanel.style.display = 'block'; // Show the panel
|
|
}
|
|
|
|
function hideInfoPanel() {
|
|
infoPanel.style.display = 'none'; // Hide the panel
|
|
}
|
|
|
|
// --- Info Panel ---
|
|
function displayInfo(buildingData) {
|
|
if (infoPanelPinned && pinnedBuildingData && pinnedBuildingData !== buildingData) return;
|
|
if (infoPanelPinned && !pinnedBuildingData) pinnedBuildingData = buildingData;
|
|
|
|
document.getElementById('info-title').textContent = buildingData.id;
|
|
document.getElementById('info-consumption').textContent = buildingData.consumption + ' kWh';
|
|
document.getElementById('info-generation').textContent = buildingData.generation + ' kWh';
|
|
// Dynamically show IoT/device consumption
|
|
let iotHtml = '';
|
|
if (buildingData.devices) {
|
|
for (const [key, value] of Object.entries(buildingData.devices)) {
|
|
iotHtml += `<strong>${key}:</strong> ${value ?? 'N/A'}<br>`;
|
|
}
|
|
} else {
|
|
iotHtml = 'N/A';
|
|
}
|
|
document.getElementById('info-iot').innerHTML = iotHtml;
|
|
|
|
infoPanel.style.display = 'block';
|
|
}
|
|
|
|
function hideInfo() {
|
|
if (!infoPanelPinned) {
|
|
infoPanel.style.display = 'none';
|
|
pinnedBuildingData = null;
|
|
}
|
|
}
|
|
|
|
function displayDebugPanelWithCamera(object) {
|
|
let html = `<h3>Debug Info</h3>`;
|
|
if (object && object.position) {
|
|
html += `<p><strong>ID:</strong> ${object.userData?.id ?? 'N/A'}</p>
|
|
<p><strong>Object Position:</strong> (${object.position.x.toFixed(2)}, ${object.position.y.toFixed(2)}, ${object.position.z.toFixed(2)})</p>`;
|
|
}
|
|
html += `<p><strong>FPS:</strong> ${currentFps.toFixed(1)}</p>`;
|
|
html += `<p><strong>Camera Position:</strong> (${camera.position.x.toFixed(2)}, ${camera.position.y.toFixed(2)}, ${camera.position.z.toFixed(2)})</p>`;
|
|
html += `<p><strong>Controls Target:</strong> (${controls.target.x.toFixed(2)}, ${controls.target.y.toFixed(2)}, ${controls.target.z.toFixed(2)})</p>`;
|
|
html += `<p><strong>Sun Position:</strong> (${directionalLight.position.x.toFixed(2)}, ${directionalLight.position.y.toFixed(2)}, ${directionalLight.position.z.toFixed(2)})</p>`;
|
|
debugPanel.innerHTML = html;
|
|
debugPanel.style.display = 'block';
|
|
}
|
|
|
|
function updatePanels(){
|
|
|
|
if (infoPanelPinned && pinnedBuildingData) {
|
|
displayInfo(pinnedBuildingData);
|
|
}
|
|
|
|
// --- Raycasting Logic ---
|
|
raycaster.setFromCamera(mouse, camera);
|
|
const intersects = raycaster.intersectObjects(interactableObjects);
|
|
|
|
let debugTarget = null;
|
|
if (infoPanelPinned && pinnedBuildingData) {
|
|
debugTarget = interactableObjects.find(obj => obj.userData === pinnedBuildingData);
|
|
} else if (intersects.length > 0) {
|
|
debugTarget = intersects[0].object.userData.parentGroup || intersects[0].object;
|
|
}
|
|
|
|
if (debugOn){
|
|
displayDebugPanelWithCamera(debugTarget);
|
|
//displaySunDebug();
|
|
}
|
|
|
|
|
|
if (intersects.length > 0) {
|
|
if (INTERSECTED != intersects[0].object) {
|
|
if (INTERSECTED) { /* Optional: Revert highlight */ }
|
|
//INTERSECTED = intersects[0].object.userData.parentGroup || intersects[0].object;
|
|
INTERSECTED = intersects[0].object;
|
|
if (INTERSECTED.userData) {
|
|
//console.log('Pinned building data:', INTERSECTED.userData);
|
|
if (INTERSECTED.userData.id){
|
|
displayInfo(INTERSECTED.userData);
|
|
} else{
|
|
displayInfo(INTERSECTED.userData.parentGroup.userData);
|
|
}
|
|
} else {
|
|
hideInfo();
|
|
}
|
|
}
|
|
} else {
|
|
if (INTERSECTED) {
|
|
hideInfo();
|
|
}
|
|
INTERSECTED = null;
|
|
}
|
|
} |