Files
caravels-community-simulation/js/panels.js
rafaeldpsilva adbbf6bf50 first commit
2025-12-10 12:32:12 +00:00

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;
}
}