// controls.js - Zoom, rotate and toggle controls import { CONFIG } from './constants.js'; import { updateZoomDisplay, showStatusMessage } from './ui.js'; import { toggleTerrain } from './earth.js'; export let autoRotate = true; export let zoomLevel = 1.0; export let showTerrain = false; export let isDragging = false; let earthObj = null; export function setupControls(camera, renderer, scene, earth) { earthObj = earth; setupZoomControls(camera); setupWheelZoom(camera, renderer); setupRotateControls(camera, earth); setupTerrainControls(); } function setupZoomControls(camera) { document.getElementById('zoom-in').addEventListener('click', () => { zoomLevel = Math.min(zoomLevel + 0.5, CONFIG.maxZoom); applyZoom(camera); }); document.getElementById('zoom-out').addEventListener('click', () => { zoomLevel = Math.max(zoomLevel - 0.5, CONFIG.minZoom); applyZoom(camera); }); document.getElementById('zoom-reset').addEventListener('click', () => { zoomLevel = 1.0; applyZoom(camera); showStatusMessage('缩放已重置', 'info'); }); const slider = document.getElementById('zoom-slider'); slider?.addEventListener('input', (e) => { zoomLevel = parseFloat(e.target.value); applyZoom(camera); }); } function setupWheelZoom(camera, renderer) { renderer.domElement.addEventListener('wheel', (e) => { e.preventDefault(); if (e.deltaY < 0) { zoomLevel = Math.min(zoomLevel + 0.1, CONFIG.maxZoom); } else { zoomLevel = Math.max(zoomLevel - 0.1, CONFIG.minZoom); } applyZoom(camera); }, { passive: false }); } function applyZoom(camera) { camera.position.z = CONFIG.defaultCameraZ / zoomLevel; const distance = camera.position.z.toFixed(0); updateZoomDisplay(zoomLevel, distance); } function animateValue(start, end, duration, onUpdate, onComplete) { const startTime = performance.now(); function update(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const easeProgress = 1 - Math.pow(1 - progress, 3); const current = start + (end - start) * easeProgress; onUpdate(current); if (progress < 1) { requestAnimationFrame(update); } else if (onComplete) { onComplete(); } } requestAnimationFrame(update); } export function resetView(camera) { if (!earthObj) return; const startRotX = earthObj.rotation.x; const startRotY = earthObj.rotation.y; const startZoom = zoomLevel; const targetRotX = 23.5 * Math.PI / 180; const targetRotY = 0; const targetZoom = 1.0; animateValue(0, 1, 800, (progress) => { const ease = 1 - Math.pow(1 - progress, 3); earthObj.rotation.x = startRotX + (targetRotX - startRotX) * ease; earthObj.rotation.y = startRotY + (targetRotY - startRotY) * ease; zoomLevel = startZoom + (targetZoom - startZoom) * ease; camera.position.z = CONFIG.defaultCameraZ / zoomLevel; updateZoomDisplay(zoomLevel, camera.position.z.toFixed(0)); }, () => { zoomLevel = 1.0; showStatusMessage('视图已重置', 'info'); }); if (typeof window.clearLockedCable === 'function') { window.clearLockedCable(); } } function setupRotateControls(camera, earth) { document.getElementById('rotate-toggle').addEventListener('click', () => { toggleAutoRotate(); const isOn = autoRotate; showStatusMessage(isOn ? '自动旋转已开启' : '自动旋转已暂停', 'info'); }); document.getElementById('reset-view').addEventListener('click', () => { if (!earthObj) return; const startRotX = earthObj.rotation.x; const startRotY = earthObj.rotation.y; const startZoom = zoomLevel; const targetRotX = 23.5 * Math.PI / 180; const targetRotY = 0; const targetZoom = 1.0; animateValue(0, 1, 800, (progress) => { const ease = 1 - Math.pow(1 - progress, 3); earthObj.rotation.x = startRotX + (targetRotX - startRotX) * ease; earthObj.rotation.y = startRotY + (targetRotY - startRotY) * ease; zoomLevel = startZoom + (targetZoom - startZoom) * ease; camera.position.z = CONFIG.defaultCameraZ / zoomLevel; updateZoomDisplay(zoomLevel, camera.position.z.toFixed(0)); }, () => { zoomLevel = 1.0; showStatusMessage('视图已重置', 'info'); }); }); } function setupTerrainControls() { document.getElementById('toggle-terrain').addEventListener('click', () => { showTerrain = !showTerrain; toggleTerrain(showTerrain); const btn = document.getElementById('toggle-terrain'); btn.textContent = showTerrain ? '隐藏地形' : '显示地形'; showStatusMessage(showTerrain ? '地形已显示' : '地形已隐藏', 'info'); }); document.getElementById('reload-data').addEventListener('click', () => { showStatusMessage('重新加载数据...', 'info'); window.location.reload(); }); } function setupMouseControls(camera, renderer) { let previousMousePosition = { x: 0, y: 0 }; renderer.domElement.addEventListener('mousedown', (e) => { isDragging = true; previousMousePosition = { x: e.clientX, y: e.clientY }; }); renderer.domElement.addEventListener('mouseup', () => { isDragging = false; }); renderer.domElement.addEventListener('mousemove', (e) => { if (isDragging) { const deltaX = e.clientX - previousMousePosition.x; const deltaY = e.clientY - previousMousePosition.y; if (earth) { earth.rotation.y += deltaX * 0.005; earth.rotation.x += deltaY * 0.005; } previousMousePosition = { x: e.clientX, y: e.clientY }; } }); } export function getAutoRotate() { return autoRotate; } export function setAutoRotate(value) { autoRotate = value; const btn = document.getElementById('rotate-toggle'); if (btn) { btn.textContent = autoRotate ? '暂停旋转' : '开始旋转'; } } export function toggleAutoRotate() { autoRotate = !autoRotate; const btn = document.getElementById('rotate-toggle'); if (btn) { btn.textContent = autoRotate ? '暂停旋转' : '开始旋转'; } if (window.clearLockedCable) { window.clearLockedCable(); } return autoRotate; } export function getZoomLevel() { return zoomLevel; } export function getShowTerrain() { return showTerrain; }