// Shared JavaScript for GeoScatter 3D Application // DOM Elements let canvasContainer; let loadingOverlay; let modelSelectBtn; let modelDropdown; let resetViewBtn; let toggleGridBtn; let rayCountSlider; let rayValueSpan; let visualizeRaysCheckbox; let densityButtons; let modeRadios; let startSamplingBtn; let clearRaysBtn; let zoomInBtn; let zoomOutBtn; let activeRaysSpan; // Sample Distribution Data (mock data) const sampleData = { sphere: [65, 42, 38, 28, 17], cylinder: [42, 56, 45, 32, 15], organic: [38, 52, 48, 41, 22], torus: [28, 46, 52, 47, 31] }; // Current Selected Model let currentModel = 'sphere'; // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', function() { // Get DOM Elements canvasContainer = document.getElementById('canvasContainer'); loadingOverlay = document.getElementById('loadingOverlay'); modelSelectBtn = document.getElementById('modelSelectBtn'); modelDropdown = document.getElementById('modelDropdown'); resetViewBtn = document.getElementById('resetView'); toggleGridBtn = document.getElementById('toggleGrid'); rayCountSlider = document.getElementById('rayCount'); rayValueSpan = document.getElementById('rayValue'); visualizeRaysCheckbox = document.getElementById('visualizeRays'); densityButtons = document.querySelectorAll('.density-btn'); modeRadios = document.querySelectorAll('input[name="mode"]'); startSamplingBtn = document.getElementById('startSampling'); clearRaysBtn = document.getElementById('clearRays'); zoomInBtn = document.getElementById('zoomIn'); zoomOutBtn = document.getElementById('zoomOut'); activeRaysSpan = document.getElementById('activeRays'); // Get coordinate display elements const coordX = document.getElementById('coordX'); const coordY = document.getElementById('coordY'); const coordZ = document.getElementById('coordZ'); // Model Selection Logic const modelOptions = document.querySelectorAll('.model-option'); modelOptions.forEach(option => { option.addEventListener('click', function() { const model = this.getAttribute('data-model'); selectModel(model); // Close dropdown modelDropdown.style.display = 'none'; // Update UI this.classList.add('bg-primary', 'text-white'); this.classList.remove('hover:bg-gray-700'); modelOptions.forEach(opt => { if (opt !== this) { opt.classList.remove('bg-primary', 'text-white'); opt.classList.add('hover:bg-gray-700'); } }); }); }); // Toggle model dropdown if (modelSelectBtn) { modelSelectBtn.addEventListener('click', function() { modelDropdown.style.display = modelDropdown.style.display === 'block' ? 'none' : 'block'; }); } // Ray Count Slider if (rayCountSlider) { rayCountSlider.addEventListener('input', function() { const value = this.value; if (rayValueSpan) { rayValueSpan.textContent = value; } if (activeRaysSpan) { activeRaysSpan.textContent = value; } // Update visualization in scene (simulate) if (window.sceneManager) { window.sceneManager.updateRayCount(value); } }); } // Density Buttons if (densityButtons) { densityButtons.forEach(btn => { btn.addEventListener('click', function() { const density = this.getAttribute('data-density'); selectDensity(density); // Update UI densityButtons.forEach(b => { b.classList.remove('bg-primary', 'text-white'); b.classList.add('bg-gray-100', 'dark:bg-gray-800', 'hover:bg-gray-200', 'dark:hover:bg-gray-700'); }); this.classList.add('bg-primary', 'text-white'); this.classList.remove('hover:bg-gray-200', 'dark:hover:bg-gray-700'); }); }); } // Algorithm Mode Selection if (modeRadios) { modeRadios.forEach(radio => { radio.addEventListener('change', function() { selectMode(this.value); }); }); } // Start Sampling Button if (startSamplingBtn) { startSamplingBtn.addEventListener('click', function() { startSampling(); }); } // Clear Rays Button if (clearRaysBtn) { clearRaysBtn.addEventListener('click', function() { clearRays(); }); } // Toggle Grid Button if (toggleGridBtn) { toggleGridBtn.addEventListener('click', function() { toggleGridVisibility(); }); } // Reset View Button if (resetViewBtn) { resetViewBtn.addEventListener('click', function() { resetCameraView(); }); } // Zoom Controls if (zoomInBtn) { zoomInBtn.addEventListener('click', function() { zoomCamera('in'); }); } if (zoomOutBtn) { zoomOutBtn.addEventListener('click', function() { zoomCamera('out'); }); } // Visualize Rays Checkbox if (visualizeRaysCheckbox) { visualizeRaysCheckbox.addEventListener('change', function() { toggleRayVisualization(this.checked); }); } // Update sample chart based on model updateSampleChart(currentModel); // Hide loading overlay after 2 seconds (simulate loading) setTimeout(() => { if (loadingOverlay) { loadingOverlay.style.opacity = '0'; setTimeout(() => { loadingOverlay.style.display = 'none'; }, 300); } }, 1500); // Update coordinates display (simulate 3D interaction) if (coordX && coordY && coordZ) { simulateCameraMovement(coordX, coordY, coordZ); } // Event Listeners for Ray Visualization document.addEventListener('rayCreated', function(e) { if (e.detail && e.detail.count) { updateRayStats(e.detail.count); } }); }); // Model Selection Function function selectModel(model) { currentModel = model; console.log(`Selected model: ${model}`); // Update UI const modelIcon = document.querySelector('#modelSelectBtn i'); if (modelIcon) { modelIcon.setAttribute('data-feather', getModelIcon(model)); feather.replace(); } // Update sample chart updateSampleChart(model); // Update Three.js scene if (window.sceneManager) { window.sceneManager.changeModel(model); } // Dispatch event const event = new CustomEvent('modelChanged', { detail: { model: model } }); document.dispatchEvent(event); } // Get icon name based on model function getModelIcon(model) { const icons = { sphere: 'circle', cylinder: 'square', organic: 'hexagon', torus: 'triangle' }; return icons[model] || 'circle'; } // Density Selection Function function selectDensity(density) { console.log(`Selected density: ${density}`); // Update UI const densityValueSpan = document.getElementById('densityValue'); if (densityValueSpan) { densityValueSpan.textContent = density.charAt(0).toUpperCase() + density.slice(1); } // Dispatch event const event = new CustomEvent('densityChanged', { detail: { density: density } }); document.dispatchEvent(event); } // Mode Selection Function function selectMode(mode) { console.log(`Selected mode: ${mode}`); // Dispatch event const event = new CustomEvent('modeChanged', { detail: { mode: mode } }); document.dispatchEvent(event); } // Start Sampling Function function startSampling() { console.log('Starting outside-in ray sampling...'); // Show visual feedback if (startSamplingBtn) { startSamplingBtn.innerHTML = 'Sampling...'; feather.replace(); setTimeout(() => { startSamplingBtn.innerHTML = 'Sampling Complete'; feather.replace(); }, 2000); } // Dispatch event const event = new CustomEvent('samplingStarted'); document.dispatchEvent(event); } // Clear Rays Function function clearRays() { console.log('Clearing all ray visualizations...'); // Dispatch event const event = new CustomEvent('raysCleared'); document.dispatchEvent(event); } // Grid Visibility Toggle function toggleGridVisibility() { console.log('Toggling grid visibility...'); // Dispatch event const event = new CustomEvent('gridToggled'); document.dispatchEvent(event); } // Camera Reset Function function resetCameraView() { console.log('Resetting camera view...'); // Dispatch event const event = new CustomEvent('cameraReset'); document.dispatchEvent(event); } // Camera Zoom Function function zoomCamera(direction) { console.log(`Zooming camera ${direction}...`); // Dispatch event const event = new CustomEvent('cameraZoomed', { detail: { direction: direction } }); document.dispatchEvent(event); } // Ray Visualization Toggle function toggleRayVisualization(visible) { console.log(`Ray visualization ${visible ? 'enabled' : 'disabled'}`); // Dispatch event const event = new CustomEvent('rayVisualizationToggled', { detail: { visible: visible } }); document.dispatchEvent(event); } // Update Sample Chart Function function updateSampleChart(model) { if (window.updateSampleChart) { window.updateSampleChart(model); } } // Simulate Camera Movement for Coordinates Display function simulateCameraMovement(coordX, coordY, coordZ) { let x = 0, y = 0, z = 0; let increment = 0.01; function updateCoordinates() { x += (Math.random() - 0.5) * increment; y += (Math.random() - 0.5) * increment; z += (Math.random() - 0.5) * increment; // Apply some damping x *= 0.99; y *= 0.99; z *= 0.99; if (coordX) coordX.textContent = x.toFixed(2); if (coordY) coordY.textContent = y.toFixed(2); if (coordZ) coordZ.textContent = z.toFixed(2); requestAnimationFrame(updateCoordinates); } updateCoordinates(); } // Update Ray Statistics function updateRayStats(count) { const totalSamples = document.getElementById('totalSamples'); const rayCollisions = document.getElementById('rayCollisions'); const shellAccuracy = document.getElementById('shellAccuracy'); const avgDistance = document.getElementById('avgDistance'); if (totalSamples) { totalSamples.textContent = count * 4; } if (rayCollisions) { const collisions = Math.floor(count * 3.8); rayCollisions.textContent = collisions; } if (shellAccuracy) { const accuracy = 90 + Math.floor(Math.random() * 10); shellAccuracy.textContent = `${accuracy}.${Math.floor(Math.random() * 10)}%`; } if (avgDistance) { const distance = 0.8 + Math.random() * 0.4; avgDistance.textContent = `${distance.toFixed(2)}m`; } } // Add event listeners for custom events document.addEventListener('modelChanged', function(e) { console.log(`Model changed to: ${e.detail.model}`); }); document.addEventListener('densityChanged', function(e) { console.log(`Density changed to: ${e.detail.density}`); }); document.addEventListener('modeChanged', function(e) { console.log(`Mode changed to: ${e.detail.mode}`); }); document.addEventListener('samplingStarted', function() { console.log('Sampling process started.'); }); document.addEventListener('raysCleared', function() { console.log('All rays cleared.'); }); document.addEventListener('gridToggled', function() { console.log('Grid toggled.'); }); document.addEventListener('cameraReset', function() { console.log('Camera view reset.'); }); document.addEventListener('cameraZoomed', function(e) { console.log(`Camera zoomed ${e.detail.direction}`); }); document.addEventListener('rayVisualizationToggled', function(e) { console.log(`Ray visualization toggled: ${e.detail.visible}`); }); // Export Functions for Use in Other Scripts window.updateSampleChart = function(model) { console.log(`Sample chart updated for model: ${model}`); // Update UI elements const sampleChartBars = document.querySelectorAll('#sampleChart div div'); if (sampleChartBars.length >= 5) { const data = sampleData[model] || sampleData.sphere; for (let i = 0; i < data.length; i++) { const height = data[i]; if (sampleChartBars[i]) { sampleChartBars[i].style.height = `${height * 0.2}px`; } } } };