chore: add earth hud backup and icon assets
435
frontend/public/earth/_backup/dock-centered-20260326/base.css
Normal file
@@ -0,0 +1,435 @@
|
||||
/* base.css - 公共基础样式 */
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: #0a0a1a;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#container.dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* Bottom Dock */
|
||||
#right-toolbar-group {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
#right-toolbar-group,
|
||||
#info-panel,
|
||||
#coordinates-display,
|
||||
#legend,
|
||||
#earth-stats {
|
||||
transition:
|
||||
top 0.45s ease,
|
||||
right 0.45s ease,
|
||||
bottom 0.45s ease,
|
||||
left 0.45s ease,
|
||||
transform 0.45s ease,
|
||||
box-shadow 0.45s ease;
|
||||
}
|
||||
|
||||
/* Zoom Toolbar - Right side, vertical */
|
||||
#zoom-toolbar {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
right: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#zoom-toolbar .zoom-percent {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: #4db8ff;
|
||||
min-width: 30px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
#zoom-toolbar .zoom-percent:hover {
|
||||
background: rgba(77, 184, 255, 0.2);
|
||||
box-shadow: 0 0 10px rgba(77, 184, 255, 0.3);
|
||||
}
|
||||
|
||||
#zoom-toolbar .zoom-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
min-width: 28px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: rgba(77, 184, 255, 0.2);
|
||||
color: #4db8ff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex: 0 0 auto;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#zoom-toolbar .zoom-btn:hover {
|
||||
background: rgba(77, 184, 255, 0.4);
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 0 10px rgba(77, 184, 255, 0.5);
|
||||
}
|
||||
|
||||
#zoom-toolbar #reset-view svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.8;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
#zoom-toolbar .zoom-percent {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#zoom-toolbar .tooltip {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 12px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(10, 10, 30, 0.95);
|
||||
color: #fff;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid rgba(77, 184, 255, 0.4);
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#zoom-toolbar .zoom-btn:hover .tooltip,
|
||||
#zoom-toolbar .zoom-percent:hover .tooltip {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#zoom-toolbar .tooltip::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border: 6px solid transparent;
|
||||
border-top-color: rgba(77, 184, 255, 0.4);
|
||||
}
|
||||
|
||||
#loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 1.2rem;
|
||||
color: #4db8ff;
|
||||
z-index: 100;
|
||||
text-align: center;
|
||||
background-color: rgba(10, 10, 30, 0.95);
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #4db8ff;
|
||||
box-shadow: 0 0 30px rgba(77,184,255,0.3);
|
||||
}
|
||||
|
||||
#loading-spinner {
|
||||
border: 4px solid rgba(77, 184, 255, 0.3);
|
||||
border-top: 4px solid #4db8ff;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 15px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ff4444;
|
||||
margin-top: 10px;
|
||||
font-size: 0.9rem;
|
||||
display: none;
|
||||
padding: 10px;
|
||||
background-color: rgba(255, 68, 68, 0.1);
|
||||
border-radius: 5px;
|
||||
border-left: 3px solid #ff4444;
|
||||
}
|
||||
|
||||
.terrain-controls {
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.slider-container {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.slider-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
-webkit-appearance: none;
|
||||
background: rgba(0, 102, 204, 0.3);
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: #4db8ff;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 10px #4db8ff;
|
||||
}
|
||||
|
||||
.status-message {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 260px;
|
||||
background-color: rgba(10, 10, 30, 0.85);
|
||||
border-radius: 10px;
|
||||
padding: 10px 15px;
|
||||
z-index: 10;
|
||||
box-shadow: 0 0 20px rgba(0, 150, 255, 0.3);
|
||||
border: 1px solid rgba(0, 150, 255, 0.2);
|
||||
font-size: 0.9rem;
|
||||
display: none;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.status-message.success {
|
||||
color: #44ff44;
|
||||
border-left: 3px solid #44ff44;
|
||||
}
|
||||
|
||||
.status-message.warning {
|
||||
color: #ffff44;
|
||||
border-left: 3px solid #ffff44;
|
||||
}
|
||||
|
||||
.status-message.error {
|
||||
color: #ff4444;
|
||||
border-left: 3px solid #ff4444;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
background-color: rgba(10, 10, 30, 0.95);
|
||||
border: 1px solid #4db8ff;
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px;
|
||||
font-size: 0.8rem;
|
||||
color: #fff;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
box-shadow: 0 0 10px rgba(77, 184, 255, 0.3);
|
||||
display: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Control Toolbar - Stellarium/Star Walk style */
|
||||
#control-toolbar {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
right: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
background: rgba(10, 10, 30, 0.9);
|
||||
border-radius: 999px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid rgba(77, 184, 255, 0.3);
|
||||
box-shadow: 0 0 20px rgba(77, 184, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.toolbar-items {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.toolbar-divider {
|
||||
width: 1px;
|
||||
height: 28px;
|
||||
background: rgba(77, 184, 255, 0.28);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.toolbar-btn {
|
||||
position: relative;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: rgba(77, 184, 255, 0.15);
|
||||
color: #4db8ff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toolbar-btn:hover {
|
||||
background: rgba(77, 184, 255, 0.35);
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 0 15px rgba(77, 184, 255, 0.5);
|
||||
}
|
||||
|
||||
.toolbar-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.toolbar-btn.active {
|
||||
background: rgba(77, 184, 255, 0.4);
|
||||
box-shadow: 0 0 10px rgba(77, 184, 255, 0.4) inset;
|
||||
}
|
||||
|
||||
.toolbar-btn .icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.toolbar-btn svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2.1;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
#rotate-toggle .icon-play,
|
||||
#rotate-toggle.is-stopped .icon-pause {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#rotate-toggle.is-stopped .icon-play {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
#container.layout-expanded #info-panel {
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
transform: translate(calc(-100% + 20px), calc(-100% + 20px));
|
||||
}
|
||||
|
||||
#container.layout-expanded #coordinates-display {
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
transform: translate(calc(100% - 20px), calc(-100% + 20px));
|
||||
}
|
||||
|
||||
#container.layout-expanded #legend {
|
||||
left: 20px;
|
||||
bottom: 20px;
|
||||
transform: translate(calc(-100% + 20px), calc(100% - 20px));
|
||||
}
|
||||
|
||||
#container.layout-expanded #earth-stats {
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
transform: translate(calc(100% - 20px), calc(100% - 20px));
|
||||
}
|
||||
|
||||
#container.layout-expanded #right-toolbar-group {
|
||||
bottom: 20px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.toolbar-btn .tooltip {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(10, 10, 30, 0.95);
|
||||
color: #fff;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid rgba(77, 184, 255, 0.4);
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.toolbar-btn:hover .tooltip {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
bottom: 52px;
|
||||
}
|
||||
|
||||
.toolbar-btn .tooltip::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border: 6px solid transparent;
|
||||
border-top-color: rgba(77, 184, 255, 0.4);
|
||||
}
|
||||
421
frontend/public/earth/_backup/dock-centered-20260326/controls.js
vendored
Normal file
@@ -0,0 +1,421 @@
|
||||
// controls.js - Zoom, rotate and toggle controls
|
||||
|
||||
import { CONFIG, EARTH_CONFIG } from "./constants.js";
|
||||
import { updateZoomDisplay, showStatusMessage } from "./ui.js";
|
||||
import { toggleTerrain } from "./earth.js";
|
||||
import { reloadData, clearLockedObject } from "./main.js";
|
||||
import {
|
||||
toggleSatellites,
|
||||
toggleTrails,
|
||||
getShowSatellites,
|
||||
getSatelliteCount,
|
||||
} from "./satellites.js";
|
||||
import { toggleCables, getShowCables } from "./cables.js";
|
||||
|
||||
export let autoRotate = true;
|
||||
export let zoomLevel = 1.0;
|
||||
export let showTerrain = false;
|
||||
export let isDragging = false;
|
||||
export let layoutExpanded = false;
|
||||
|
||||
let earthObj = null;
|
||||
let listeners = [];
|
||||
let cleanupFns = [];
|
||||
|
||||
function bindListener(element, eventName, handler, options) {
|
||||
if (!element) return;
|
||||
element.addEventListener(eventName, handler, options);
|
||||
listeners.push(() =>
|
||||
element.removeEventListener(eventName, handler, options),
|
||||
);
|
||||
}
|
||||
|
||||
function resetCleanup() {
|
||||
cleanupFns.forEach((cleanup) => cleanup());
|
||||
cleanupFns = [];
|
||||
listeners.forEach((cleanup) => cleanup());
|
||||
listeners = [];
|
||||
}
|
||||
|
||||
export function setupControls(camera, renderer, scene, earth) {
|
||||
resetCleanup();
|
||||
earthObj = earth;
|
||||
setupZoomControls(camera);
|
||||
setupWheelZoom(camera, renderer);
|
||||
setupRotateControls(camera, earth);
|
||||
setupTerrainControls();
|
||||
}
|
||||
|
||||
function setupZoomControls(camera) {
|
||||
let zoomInterval = null;
|
||||
let holdTimeout = null;
|
||||
let startTime = 0;
|
||||
const HOLD_THRESHOLD = 150;
|
||||
const LONG_PRESS_TICK = 50;
|
||||
const CLICK_STEP = 10;
|
||||
|
||||
const MIN_PERCENT = CONFIG.minZoom * 100;
|
||||
const MAX_PERCENT = CONFIG.maxZoom * 100;
|
||||
|
||||
function doZoomStep(direction) {
|
||||
let currentPercent = Math.round(zoomLevel * 100);
|
||||
let newPercent =
|
||||
direction > 0 ? currentPercent + CLICK_STEP : currentPercent - CLICK_STEP;
|
||||
|
||||
if (newPercent > MAX_PERCENT) newPercent = MAX_PERCENT;
|
||||
if (newPercent < MIN_PERCENT) newPercent = MIN_PERCENT;
|
||||
|
||||
zoomLevel = newPercent / 100;
|
||||
applyZoom(camera);
|
||||
}
|
||||
|
||||
function doContinuousZoom(direction) {
|
||||
let currentPercent = Math.round(zoomLevel * 100);
|
||||
let newPercent = direction > 0 ? currentPercent + 1 : currentPercent - 1;
|
||||
|
||||
if (newPercent > MAX_PERCENT) newPercent = MAX_PERCENT;
|
||||
if (newPercent < MIN_PERCENT) newPercent = MIN_PERCENT;
|
||||
|
||||
zoomLevel = newPercent / 100;
|
||||
applyZoom(camera);
|
||||
}
|
||||
|
||||
function startContinuousZoom(direction) {
|
||||
doContinuousZoom(direction);
|
||||
zoomInterval = window.setInterval(() => {
|
||||
doContinuousZoom(direction);
|
||||
}, LONG_PRESS_TICK);
|
||||
}
|
||||
|
||||
function stopZoom() {
|
||||
if (zoomInterval) {
|
||||
clearInterval(zoomInterval);
|
||||
zoomInterval = null;
|
||||
}
|
||||
if (holdTimeout) {
|
||||
clearTimeout(holdTimeout);
|
||||
holdTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseDown(direction) {
|
||||
startTime = Date.now();
|
||||
stopZoom();
|
||||
holdTimeout = window.setTimeout(() => {
|
||||
startContinuousZoom(direction);
|
||||
}, HOLD_THRESHOLD);
|
||||
}
|
||||
|
||||
function handleMouseUp(direction) {
|
||||
const heldTime = Date.now() - startTime;
|
||||
stopZoom();
|
||||
if (heldTime < HOLD_THRESHOLD) {
|
||||
doZoomStep(direction);
|
||||
}
|
||||
}
|
||||
|
||||
cleanupFns.push(stopZoom);
|
||||
|
||||
const zoomIn = document.getElementById("zoom-in");
|
||||
const zoomOut = document.getElementById("zoom-out");
|
||||
const zoomValue = document.getElementById("zoom-value");
|
||||
|
||||
bindListener(zoomIn, "mousedown", () => handleMouseDown(1));
|
||||
bindListener(zoomIn, "mouseup", () => handleMouseUp(1));
|
||||
bindListener(zoomIn, "mouseleave", stopZoom);
|
||||
bindListener(zoomIn, "touchstart", (e) => {
|
||||
e.preventDefault();
|
||||
handleMouseDown(1);
|
||||
});
|
||||
bindListener(zoomIn, "touchend", () => handleMouseUp(1));
|
||||
|
||||
bindListener(zoomOut, "mousedown", () => handleMouseDown(-1));
|
||||
bindListener(zoomOut, "mouseup", () => handleMouseUp(-1));
|
||||
bindListener(zoomOut, "mouseleave", stopZoom);
|
||||
bindListener(zoomOut, "touchstart", (e) => {
|
||||
e.preventDefault();
|
||||
handleMouseDown(-1);
|
||||
});
|
||||
bindListener(zoomOut, "touchend", () => handleMouseUp(-1));
|
||||
|
||||
bindListener(zoomValue, "click", () => {
|
||||
const startZoomVal = zoomLevel;
|
||||
const targetZoom = 1.0;
|
||||
const startDistance = CONFIG.defaultCameraZ / startZoomVal;
|
||||
const targetDistance = CONFIG.defaultCameraZ / targetZoom;
|
||||
|
||||
animateValue(
|
||||
0,
|
||||
1,
|
||||
600,
|
||||
(progress) => {
|
||||
const ease = 1 - Math.pow(1 - progress, 3);
|
||||
zoomLevel = startZoomVal + (targetZoom - startZoomVal) * ease;
|
||||
camera.position.z = CONFIG.defaultCameraZ / zoomLevel;
|
||||
const distance =
|
||||
startDistance + (targetDistance - startDistance) * ease;
|
||||
updateZoomDisplay(zoomLevel, distance.toFixed(0));
|
||||
},
|
||||
() => {
|
||||
zoomLevel = 1.0;
|
||||
showStatusMessage("缩放已重置到100%", "info");
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function setupWheelZoom(camera, renderer) {
|
||||
bindListener(
|
||||
renderer?.domElement,
|
||||
"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;
|
||||
|
||||
function animateToView(targetLat, targetLon, targetRotLon) {
|
||||
const latRot = (targetLat * Math.PI) / 180;
|
||||
const targetRotX =
|
||||
EARTH_CONFIG.tiltRad + latRot * EARTH_CONFIG.latCoefficient;
|
||||
const targetRotY = -((targetRotLon * Math.PI) / 180);
|
||||
|
||||
const startRotX = earthObj.rotation.x;
|
||||
const startRotY = earthObj.rotation.y;
|
||||
const startZoom = zoomLevel;
|
||||
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 (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) =>
|
||||
animateToView(
|
||||
pos.coords.latitude,
|
||||
pos.coords.longitude,
|
||||
-pos.coords.longitude,
|
||||
),
|
||||
() =>
|
||||
animateToView(
|
||||
EARTH_CONFIG.chinaLat,
|
||||
EARTH_CONFIG.chinaLon,
|
||||
EARTH_CONFIG.chinaRotLon,
|
||||
),
|
||||
{ timeout: 5000, enableHighAccuracy: false },
|
||||
);
|
||||
} else {
|
||||
animateToView(
|
||||
EARTH_CONFIG.chinaLat,
|
||||
EARTH_CONFIG.chinaLon,
|
||||
EARTH_CONFIG.chinaRotLon,
|
||||
);
|
||||
}
|
||||
|
||||
clearLockedObject();
|
||||
}
|
||||
|
||||
function setupRotateControls(camera) {
|
||||
const rotateBtn = document.getElementById("rotate-toggle");
|
||||
const resetViewBtn = document.getElementById("reset-view");
|
||||
|
||||
bindListener(rotateBtn, "click", () => {
|
||||
const isRotating = toggleAutoRotate();
|
||||
showStatusMessage(isRotating ? "自动旋转已开启" : "自动旋转已暂停", "info");
|
||||
});
|
||||
|
||||
updateRotateUI();
|
||||
|
||||
bindListener(resetViewBtn, "click", () => {
|
||||
resetView(camera);
|
||||
});
|
||||
}
|
||||
|
||||
function setupTerrainControls() {
|
||||
const container = document.getElementById("container");
|
||||
const terrainBtn = document.getElementById("toggle-terrain");
|
||||
const satellitesBtn = document.getElementById("toggle-satellites");
|
||||
const trailsBtn = document.getElementById("toggle-trails");
|
||||
const cablesBtn = document.getElementById("toggle-cables");
|
||||
const layoutBtn = document.getElementById("layout-toggle");
|
||||
const reloadBtn = document.getElementById("reload-data");
|
||||
|
||||
if (trailsBtn) {
|
||||
trailsBtn.classList.add("active");
|
||||
const tooltip = trailsBtn.querySelector(".tooltip");
|
||||
if (tooltip) tooltip.textContent = "隐藏轨迹";
|
||||
}
|
||||
|
||||
bindListener(terrainBtn, "click", function () {
|
||||
showTerrain = !showTerrain;
|
||||
toggleTerrain(showTerrain);
|
||||
this.classList.toggle("active", showTerrain);
|
||||
const tooltip = this.querySelector(".tooltip");
|
||||
if (tooltip) tooltip.textContent = showTerrain ? "隐藏地形" : "显示地形";
|
||||
const terrainStatus = document.getElementById("terrain-status");
|
||||
if (terrainStatus)
|
||||
terrainStatus.textContent = showTerrain ? "开启" : "关闭";
|
||||
showStatusMessage(showTerrain ? "地形已显示" : "地形已隐藏", "info");
|
||||
});
|
||||
|
||||
bindListener(satellitesBtn, "click", function () {
|
||||
const showSats = !getShowSatellites();
|
||||
if (!showSats) {
|
||||
clearLockedObject();
|
||||
}
|
||||
toggleSatellites(showSats);
|
||||
this.classList.toggle("active", showSats);
|
||||
const tooltip = this.querySelector(".tooltip");
|
||||
if (tooltip) tooltip.textContent = showSats ? "隐藏卫星" : "显示卫星";
|
||||
const satelliteCountEl = document.getElementById("satellite-count");
|
||||
if (satelliteCountEl)
|
||||
satelliteCountEl.textContent = getSatelliteCount() + " 颗";
|
||||
showStatusMessage(showSats ? "卫星已显示" : "卫星已隐藏", "info");
|
||||
});
|
||||
|
||||
bindListener(trailsBtn, "click", function () {
|
||||
const isActive = this.classList.contains("active");
|
||||
const nextShowTrails = !isActive;
|
||||
toggleTrails(nextShowTrails);
|
||||
this.classList.toggle("active", nextShowTrails);
|
||||
const tooltip = this.querySelector(".tooltip");
|
||||
if (tooltip) tooltip.textContent = nextShowTrails ? "隐藏轨迹" : "显示轨迹";
|
||||
showStatusMessage(nextShowTrails ? "轨迹已显示" : "轨迹已隐藏", "info");
|
||||
});
|
||||
|
||||
bindListener(cablesBtn, "click", function () {
|
||||
const showNextCables = !getShowCables();
|
||||
if (!showNextCables) {
|
||||
clearLockedObject();
|
||||
}
|
||||
toggleCables(showNextCables);
|
||||
this.classList.toggle("active", showNextCables);
|
||||
const tooltip = this.querySelector(".tooltip");
|
||||
if (tooltip) tooltip.textContent = showNextCables ? "隐藏线缆" : "显示线缆";
|
||||
showStatusMessage(showNextCables ? "线缆已显示" : "线缆已隐藏", "info");
|
||||
});
|
||||
|
||||
bindListener(reloadBtn, "click", async () => {
|
||||
await reloadData();
|
||||
});
|
||||
|
||||
bindListener(layoutBtn, "click", () => {
|
||||
const expanded = toggleLayoutExpanded(container);
|
||||
showStatusMessage(expanded ? "布局已最大化" : "布局已恢复", "info");
|
||||
});
|
||||
|
||||
updateLayoutUI(container);
|
||||
}
|
||||
|
||||
export function teardownControls() {
|
||||
resetCleanup();
|
||||
}
|
||||
|
||||
export function getAutoRotate() {
|
||||
return autoRotate;
|
||||
}
|
||||
|
||||
function updateRotateUI() {
|
||||
const btn = document.getElementById("rotate-toggle");
|
||||
if (btn) {
|
||||
btn.classList.toggle("active", autoRotate);
|
||||
btn.classList.toggle("is-stopped", !autoRotate);
|
||||
const tooltip = btn.querySelector(".tooltip");
|
||||
if (tooltip) tooltip.textContent = autoRotate ? "暂停旋转" : "开始旋转";
|
||||
}
|
||||
}
|
||||
|
||||
export function setAutoRotate(value) {
|
||||
autoRotate = value;
|
||||
updateRotateUI();
|
||||
}
|
||||
|
||||
export function toggleAutoRotate() {
|
||||
autoRotate = !autoRotate;
|
||||
updateRotateUI();
|
||||
clearLockedObject();
|
||||
return autoRotate;
|
||||
}
|
||||
|
||||
export function getZoomLevel() {
|
||||
return zoomLevel;
|
||||
}
|
||||
|
||||
export function getShowTerrain() {
|
||||
return showTerrain;
|
||||
}
|
||||
|
||||
function updateLayoutUI(container) {
|
||||
if (container) {
|
||||
container.classList.toggle("layout-expanded", layoutExpanded);
|
||||
}
|
||||
|
||||
const btn = document.getElementById("layout-toggle");
|
||||
if (btn) {
|
||||
btn.classList.toggle("active", layoutExpanded);
|
||||
const tooltip = btn.querySelector(".tooltip");
|
||||
const nextLabel = layoutExpanded ? "恢复布局" : "最大化布局";
|
||||
btn.title = nextLabel;
|
||||
if (tooltip) tooltip.textContent = nextLabel;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleLayoutExpanded(container) {
|
||||
layoutExpanded = !layoutExpanded;
|
||||
updateLayoutUI(container);
|
||||
return layoutExpanded;
|
||||
}
|
||||
227
frontend/public/earth/_backup/dock-centered-20260326/index.html
Normal file
@@ -0,0 +1,227 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>智能星球计划 - 现实层宇宙全息感知</title>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://esm.sh/three@0.128.0",
|
||||
"simplex-noise": "https://esm.sh/simplex-noise@4.0.1",
|
||||
"satellite.js": "https://esm.sh/satellite.js@5.0.0"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="css/base.css">
|
||||
<link rel="stylesheet" href="css/info-panel.css">
|
||||
<link rel="stylesheet" href="css/coordinates-display.css">
|
||||
<link rel="stylesheet" href="css/legend.css">
|
||||
<link rel="stylesheet" href="css/earth-stats.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info-panel">
|
||||
<h1>智能星球计划</h1>
|
||||
<div class="subtitle">现实层宇宙全息感知系统 | 卫星 · 海底光缆 · 算力基础设施</div>
|
||||
|
||||
<div id="info-card" class="info-card" style="display: none;">
|
||||
<div class="info-card-header">
|
||||
<span class="info-card-icon" id="info-card-icon">🛰️</span>
|
||||
<h3 id="info-card-title">详情</h3>
|
||||
</div>
|
||||
<div id="info-card-content"></div>
|
||||
</div>
|
||||
|
||||
<div id="error-message" class="error-message"></div>
|
||||
</div>
|
||||
|
||||
<div id="right-toolbar-group">
|
||||
<div id="control-toolbar">
|
||||
<div class="toolbar-items">
|
||||
<button id="layout-toggle" class="toolbar-btn" title="最大化布局">
|
||||
<span class="icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M9 9H5V5"></path>
|
||||
<path d="M15 9h4V5"></path>
|
||||
<path d="M9 15H5v4"></path>
|
||||
<path d="M15 15h4v4"></path>
|
||||
<path d="M5 5l5 5"></path>
|
||||
<path d="M19 5l-5 5"></path>
|
||||
<path d="M5 19l5-5"></path>
|
||||
<path d="M19 19l-5-5"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">最大化布局</span>
|
||||
</button>
|
||||
<button id="rotate-toggle" class="toolbar-btn" title="自动旋转">
|
||||
<span class="icon rotate-icon icon-pause" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M9 6v12"></path>
|
||||
<path d="M15 6v12"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="icon rotate-icon icon-play" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M8 6.5v11l9-5.5z" fill="currentColor" stroke="none"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">自动旋转</span>
|
||||
</button>
|
||||
<button id="toggle-cables" class="toolbar-btn active" title="显示/隐藏线缆">
|
||||
<span class="icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<circle cx="12" cy="12" r="6.5"></circle>
|
||||
<path d="M5.8 12h12.4"></path>
|
||||
<path d="M12 5.8a8.5 8.5 0 0 1 0 12.4"></path>
|
||||
<path d="M8 16c2-1.8 6-1.8 8 0"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">隐藏线缆</span>
|
||||
</button>
|
||||
<button id="toggle-terrain" class="toolbar-btn" title="显示/隐藏地形">
|
||||
<span class="icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M3 18h18"></path>
|
||||
<path d="M4.5 18l5-7 3 4 3.5-6 3.5 9"></path>
|
||||
<path d="M11 18l2-3 1.5 2"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">显示/隐藏地形</span>
|
||||
</button>
|
||||
<button id="toggle-satellites" class="toolbar-btn" title="显示/隐藏卫星">
|
||||
<span class="icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<rect x="10" y="10" width="4" height="4" rx="0.8"></rect>
|
||||
<rect x="4" y="9" width="4" height="6" rx="0.8"></rect>
|
||||
<rect x="16" y="9" width="4" height="6" rx="0.8"></rect>
|
||||
<path d="M8 12h2"></path>
|
||||
<path d="M14 12h2"></path>
|
||||
<path d="M12 8V6"></path>
|
||||
<path d="M11 6h2"></path>
|
||||
<path d="M12 14v4"></path>
|
||||
<path d="M10 18h4"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">显示卫星</span>
|
||||
</button>
|
||||
<button id="toggle-trails" class="toolbar-btn active" title="显示/隐藏轨迹">
|
||||
<span class="icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M5 17h7"></path>
|
||||
<path d="M7 13.5h8"></path>
|
||||
<path d="M10 10h6"></path>
|
||||
<circle cx="17.5" cy="8.5" r="2.2" fill="currentColor" stroke="none"></circle>
|
||||
<path d="M15.8 10.2l2.8-2.8"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">隐藏轨迹</span>
|
||||
</button>
|
||||
<button id="reload-data" class="toolbar-btn" title="重新加载数据">
|
||||
<span class="icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M20 5v5h-5"></path>
|
||||
<path d="M20 10a8 8 0 1 0 2 5"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tooltip">重新加载数据</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toolbar-divider" aria-hidden="true"></div>
|
||||
<div id="zoom-toolbar">
|
||||
<button id="zoom-out" class="zoom-btn" title="缩小">−<span class="tooltip">缩小</span></button>
|
||||
<span id="zoom-value" class="zoom-percent" title="重置缩放到100%">100%<span class="tooltip">重置缩放到100%</span></span>
|
||||
<button id="zoom-in" class="zoom-btn" title="放大">+<span class="tooltip">放大</span></button>
|
||||
<button id="reset-view" class="zoom-btn" title="重置视角">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<path d="M12 3v4"></path>
|
||||
<path d="M12 17v4"></path>
|
||||
<path d="M3 12h4"></path>
|
||||
<path d="M17 12h4"></path>
|
||||
<circle cx="12" cy="12" r="1.5" fill="currentColor" stroke="none"></circle>
|
||||
</svg>
|
||||
<span class="tooltip">重置视角</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="coordinates-display">
|
||||
<h3 style="color:#4db8ff; margin-bottom:8px; font-size:1.1rem;">坐标信息</h3>
|
||||
<div class="coord-item">
|
||||
<span class="coord-label">经度:</span>
|
||||
<span id="longitude-value" class="coord-value">0.00°</span>
|
||||
</div>
|
||||
<div class="coord-item">
|
||||
<span class="coord-label">纬度:</span>
|
||||
<span id="latitude-value" class="coord-value">0.00°</span>
|
||||
</div>
|
||||
<div id="zoom-level">缩放: 1.0x</div>
|
||||
<div class="mouse-coords" id="mouse-coords">鼠标位置: 无</div>
|
||||
</div>
|
||||
|
||||
<div id="legend">
|
||||
<h3 style="color:#4db8ff; margin-bottom:10px; font-size:1.1rem;">图例</h3>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #ff4444;"></div>
|
||||
<span>Americas II</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #44ff44;"></div>
|
||||
<span>AU Aleutian A</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #4444ff;"></div>
|
||||
<span>AU Aleutian B</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #ffff44;"></div>
|
||||
<span>其他电缆</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="earth-stats">
|
||||
<h3 style="color:#4db8ff; margin-bottom:10px; font-size:1.1rem;">地球信息</h3>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">电缆系统:</span>
|
||||
<span class="stats-value" id="cable-count">0个</span>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">状态:</span>
|
||||
<span class="stats-value" id="cable-status-summary">-</span>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">登陆点:</span>
|
||||
<span class="stats-value" id="landing-point-count">0个</span>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">地形:</span>
|
||||
<span class="stats-value" id="terrain-status">开启</span>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">卫星:</span>
|
||||
<span class="stats-value" id="satellite-count">0 颗</span>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">视角距离:</span>
|
||||
<span class="stats-value" id="camera-distance">300 km</span>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<span class="stats-label">纹理质量:</span>
|
||||
<span class="stats-value" id="texture-quality">8K 卫星图</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loading">
|
||||
<div id="loading-spinner"></div>
|
||||
<div id="loading-title">正在初始化全球态势数据...</div>
|
||||
<div id="loading-subtitle" style="font-size:0.9rem; margin-top:10px; color:#aaa;">同步卫星、海底光缆与登陆点数据</div>
|
||||
</div>
|
||||
<div id="status-message" class="status-message" style="display: none;"></div>
|
||||
<div id="tooltip" class="tooltip"></div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
6
frontend/public/earth/assets/icons/cables.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="6.75" stroke="#4DB8FF" stroke-width="2.1"/>
|
||||
<path d="M5.75 12H18.25" stroke="#4DB8FF" stroke-width="2.1" stroke-linecap="round"/>
|
||||
<path d="M12 5.8C14.7 7.75 14.7 16.25 12 18.2" stroke="#4DB8FF" stroke-width="2.1" stroke-linecap="round"/>
|
||||
<path d="M8 16C9.95 14.2 14.05 14.2 16 16" stroke="#4DB8FF" stroke-width="2.1" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 480 B |
5
frontend/public/earth/assets/icons/info.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="8" stroke="#4DB8FF" stroke-width="2.2"/>
|
||||
<path d="M12 10V16" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<circle cx="12" cy="7.25" r="1.25" fill="#4DB8FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 310 B |
10
frontend/public/earth/assets/icons/layout-collapse.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 9L5 5" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M5 8V5H8" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15 9L19 5" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M16 5H19V8" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 15L5 19" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M5 16V19H8" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15 15L19 19" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M16 19H19V16" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 871 B |
10
frontend/public/earth/assets/icons/layout.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 9.2L9.2 9.2L9.2 6" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M18 9.2L14.8 9.2L14.8 6" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 14.8L9.2 14.8L9.2 18" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M18 14.8L14.8 14.8L14.8 18" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 6L10 10" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M18 6L14 10" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M6 18L10 14" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M18 18L14 14" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 927 B |
4
frontend/public/earth/assets/icons/pause.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 6.25V17.75" stroke="#4DB8FF" stroke-width="2.4" stroke-linecap="round"/>
|
||||
<path d="M15 6.25V17.75" stroke="#4DB8FF" stroke-width="2.4" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 278 B |
3
frontend/public/earth/assets/icons/play.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.5 6.5L17.5 12L8.5 17.5V6.5Z" fill="#4DB8FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 163 B |
6
frontend/public/earth/assets/icons/reload.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.8 12.6C6.8 8.95 9.75 6 13.4 6C14.9 6 16.24 6.46 17.3 7.28" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M18.85 10.45C19.2 11.15 19.4 11.95 19.4 12.8C19.4 16.45 16.45 19.4 12.8 19.4C10.05 19.4 7.69 17.72 6.7 15.33" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M15.9 5.95H19.2V9.25" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M19.2 5.95L16.7 8.45" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 631 B |
8
frontend/public/earth/assets/icons/reset-view.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="5" stroke="#4DB8FF" stroke-width="2.2"/>
|
||||
<path d="M12 3V6.5" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M12 17.5V21" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M3 12H6.5" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M17.5 12H21" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<circle cx="12" cy="12" r="1.45" fill="#4DB8FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 561 B |
11
frontend/public/earth/assets/icons/satellite.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="10" y="10" width="4" height="4" rx="0.8" stroke="#4DB8FF" stroke-width="2"/>
|
||||
<rect x="4" y="9" width="4" height="6" rx="0.8" stroke="#4DB8FF" stroke-width="2"/>
|
||||
<rect x="16" y="9" width="4" height="6" rx="0.8" stroke="#4DB8FF" stroke-width="2"/>
|
||||
<path d="M8 12H10" stroke="#4DB8FF" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M14 12H16" stroke="#4DB8FF" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M12 8V6" stroke="#4DB8FF" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M10.75 6H13.25" stroke="#4DB8FF" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M12 14V18" stroke="#4DB8FF" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M10.25 18H13.75" stroke="#4DB8FF" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 858 B |
4
frontend/public/earth/assets/icons/search.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10.5" cy="10.5" r="5.75" stroke="#4DB8FF" stroke-width="2.2"/>
|
||||
<path d="M15.2 15.2L19.25 19.25" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 276 B |
5
frontend/public/earth/assets/icons/terrain.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 18H21" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M4.5 18L9.5 11L12.5 15L16 9L19.5 18" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.25 18L13.05 15.35L14.55 17.25" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 449 B |
7
frontend/public/earth/assets/icons/trails.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 17H12" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M7 13.5H15" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M10 10H16" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<circle cx="17.5" cy="8.5" r="2.2" fill="#4DB8FF"/>
|
||||
<path d="M15.8 10.2L18.55 7.45" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 501 B |
6
frontend/public/earth/assets/icons/zoom.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10.5" cy="10.5" r="5.75" stroke="#4DB8FF" stroke-width="2.2"/>
|
||||
<path d="M15.25 15.25L19.25 19.25" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M10.5 8V13" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M8 10.5H13" stroke="#4DB8FF" stroke-width="2.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 446 B |