feat(earth): Modularize 3D Earth page with ES Modules

## Changelog

### New Features
- Modularized 3D earth HTML page from single 1918-line file into ES Modules
- Split CSS into separate module files (base, info-panel, coordinates-display, legend, earth-stats)
- Split JS into separate modules (constants, utils, ui, earth, cables, controls, main)

### 3D Earth Rendering
- Use Three.js r128 (via esm.sh CDN) for color consistency with original
- Earth with 8K satellite texture and proper material settings
- Cloud layer with transparency and additive blending
- Starfield background (8000 stars)
- Latitude/longitude grid lines that rotate with Earth

### Cable System
- Load cable data from geo.json with great circle path calculation
- Support for MultiLineString and LineString geometry types
- Cable color from geo.json properties.color field
- Landing points loading from landing-point-geo.geojson

### User Interactions
- Mouse hover: highlight cable and show details
- Mouse click: lock cable with pulsing glow effect
- Click cable to pause rotation, click elsewhere to resume
- Click rotation toggle button to resume rotation and clear highlight
- Reset view with smooth animation (800ms cubic ease-out)
- Mouse wheel zoom support
- Drag to rotate Earth

### UI/UX Improvements
- Tooltip shows latitude, longitude, and altitude
- Prevent tooltip text selection during drag
- Hide tooltip during drag operation
- Blue border tooltip styling matching original
- Cursor changes to grabbing during drag
- Front-facing cable detection (only detect cables facing camera)

### Bug Fixes
- Grid lines now rotate with Earth (added as Earth child)
- Reset view button now works correctly
- Fixed camera reference in reset view
- Fixed autoRotate state management when clearing locked cable

### Original HTML
- Copied original 3dearthmult.html to public folder for reference
This commit is contained in:
rayd1o
2026-03-11 15:54:50 +08:00
parent 4ada75ca14
commit 6cb4398f3a
15 changed files with 1805 additions and 44 deletions

View File

@@ -0,0 +1,55 @@
// utils.js - Utility functions for coordinate conversion
import * as THREE from 'three';
import { CONFIG } from './constants.js';
// Convert latitude/longitude to 3D vector
export function latLonToVector3(lat, lon, radius = CONFIG.earthRadius) {
const phi = (90 - lat) * (Math.PI / 180);
const theta = (lon + 180) * (Math.PI / 180);
const x = -(radius * Math.sin(phi) * Math.cos(theta));
const z = radius * Math.sin(phi) * Math.sin(theta);
const y = radius * Math.cos(phi);
return new THREE.Vector3(x, y, z);
}
// Convert 3D vector to latitude/longitude
export function vector3ToLatLon(vector) {
const radius = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
const lat = 90 - (Math.acos(vector.y / radius) * 180 / Math.PI);
const lon = (Math.atan2(vector.z, -vector.x) * 180 / Math.PI) - 180;
return {
lat: parseFloat(lat.toFixed(4)),
lon: parseFloat(lon.toFixed(4)),
alt: radius - CONFIG.earthRadius
};
}
// Convert screen coordinates to Earth surface 3D coordinates
export function screenToEarthCoords(x, y, camera, earth) {
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2(
(x / window.innerWidth) * 2 - 1,
-(y / window.innerHeight) * 2 + 1
);
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(earth);
if (intersects.length > 0) {
return intersects[0].point;
}
return null;
}
// Calculate simplified distance between two points
export function calculateDistance(lat1, lon1, lat2, lon2) {
const dx = lon2 - lon1;
const dy = lat2 - lat1;
return Math.sqrt(dx * dx + dy * dy);
}