feat(earth): cable state management, hover/lock visual separation, fix isSameCable undefined bug
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as THREE from 'three';
|
||||
|
||||
import { CONFIG, CABLE_COLORS, PATHS } from './constants.js';
|
||||
import { CONFIG, CABLE_COLORS, PATHS, CABLE_STATE } from './constants.js';
|
||||
import { latLonToVector3 } from './utils.js';
|
||||
import { updateEarthStats, showStatusMessage } from './ui.js';
|
||||
import { showInfoCard } from './info-card.js';
|
||||
@@ -340,3 +340,25 @@ export function getCablesById(cableId) {
|
||||
export function getLandingPoints() {
|
||||
return landingPoints;
|
||||
}
|
||||
|
||||
const cableStates = new Map();
|
||||
|
||||
export function getCableState(cableId) {
|
||||
return cableStates.get(cableId) || CABLE_STATE.NORMAL;
|
||||
}
|
||||
|
||||
export function setCableState(cableId, state) {
|
||||
cableStates.set(cableId, state);
|
||||
}
|
||||
|
||||
export function clearAllCableStates() {
|
||||
cableStates.clear();
|
||||
}
|
||||
|
||||
export function getCableStateInfo() {
|
||||
const states = {};
|
||||
cableStates.forEach((state, cableId) => {
|
||||
states[cableId] = state;
|
||||
});
|
||||
return states;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ export const CABLE_CONFIG = {
|
||||
pulseCoefficient: 0.4
|
||||
};
|
||||
|
||||
export const CABLE_STATE = {
|
||||
NORMAL: 'normal',
|
||||
HOVERED: 'hovered',
|
||||
LOCKED: 'locked'
|
||||
};
|
||||
|
||||
export const GRID_CONFIG = {
|
||||
latitudeStep: 10,
|
||||
longitudeStep: 30,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as THREE from 'three';
|
||||
import { createNoise3D } from 'simplex-noise';
|
||||
|
||||
import { CONFIG, CABLE_CONFIG } from './constants.js';
|
||||
import { CONFIG, CABLE_CONFIG, CABLE_STATE } from './constants.js';
|
||||
import { latLonToVector3, vector3ToLatLon, screenToEarthCoords } from './utils.js';
|
||||
import {
|
||||
showStatusMessage,
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
hideTooltip
|
||||
} from './ui.js';
|
||||
import { createEarth, createClouds, createTerrain, createStars, createGridLines, toggleTerrain, getEarth } from './earth.js';
|
||||
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked } from './cables.js';
|
||||
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked, getCableState, setCableState, clearAllCableStates } from './cables.js';
|
||||
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, selectSatellite, getSatelliteData, getSatellitePoints } from './satellites.js';
|
||||
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate, resetView } from './controls.js';
|
||||
import { initInfoCard, showInfoCard, hideInfoCard, getCurrentType, setInfoCardNoBorder } from './info-card.js';
|
||||
@@ -33,6 +33,7 @@ let isLongDrag = false;
|
||||
|
||||
function clearLockedObject() {
|
||||
hoveredCable = null;
|
||||
clearAllCableStates();
|
||||
lockedObject = null;
|
||||
lockedObjectType = null;
|
||||
lockedSatellite = null;
|
||||
@@ -40,25 +41,61 @@ function clearLockedObject() {
|
||||
}
|
||||
|
||||
function isSameCable(cable1, cable2) {
|
||||
return cable1 && cable2 && cable1.userData.cableId === cable2.userData.cableId;
|
||||
if (!cable1 || !cable2) return false;
|
||||
const id1 = cable1.userData?.cableId;
|
||||
const id2 = cable2.userData?.cableId;
|
||||
if (id1 === undefined || id2 === undefined) return false;
|
||||
return id1 === id2;
|
||||
}
|
||||
|
||||
function showCableInfo(cable) {
|
||||
showInfoCard('cable', {
|
||||
name: cable.userData.name,
|
||||
owner: cable.userData.owner,
|
||||
status: cable.userData.status,
|
||||
length: cable.userData.length,
|
||||
coords: cable.userData.coords,
|
||||
rfs: cable.userData.rfs
|
||||
});
|
||||
}
|
||||
|
||||
function showSatelliteInfo(props) {
|
||||
const meanMotion = props?.mean_motion || 0;
|
||||
const period = meanMotion > 0 ? (1440 / meanMotion).toFixed(1) : '-';
|
||||
const ecc = props?.eccentricity || 0;
|
||||
const perigee = (6371 * (1 - ecc)).toFixed(0);
|
||||
const apogee = (6371 * (1 + ecc)).toFixed(0);
|
||||
|
||||
showInfoCard('satellite', {
|
||||
name: props?.name || '-',
|
||||
norad_id: props?.norad_cat_id,
|
||||
inclination: props?.inclination ? props.inclination.toFixed(2) : '-',
|
||||
period: period,
|
||||
perigee: perigee,
|
||||
apogee: apogee
|
||||
});
|
||||
}
|
||||
|
||||
function applyCableVisualState() {
|
||||
const allCables = getCableLines();
|
||||
const pulse = (Math.sin(Date.now() * CABLE_CONFIG.pulseSpeed) + 1) * 0.5;
|
||||
const isLocked = lockedObjectType === 'cable' && lockedObject;
|
||||
|
||||
allCables.forEach(c => {
|
||||
const cableIsLocked = isSameCable(c, lockedObject);
|
||||
const cableIsHovered = isSameCable(c, hoveredCable);
|
||||
const cableId = c.userData.cableId;
|
||||
const state = getCableState(cableId);
|
||||
|
||||
if (cableIsLocked) {
|
||||
switch (state) {
|
||||
case CABLE_STATE.LOCKED:
|
||||
c.material.opacity = CABLE_CONFIG.lockedOpacityMin + pulse * CABLE_CONFIG.pulseCoefficient;
|
||||
c.material.color.setRGB(1, 1, 1);
|
||||
} else if (cableIsHovered) {
|
||||
break;
|
||||
case CABLE_STATE.HOVERED:
|
||||
c.material.opacity = 1;
|
||||
c.material.color.setRGB(1, 1, 1);
|
||||
} else if (isLocked) {
|
||||
break;
|
||||
case CABLE_STATE.NORMAL:
|
||||
default:
|
||||
if (lockedObjectType === 'cable' && lockedObject) {
|
||||
c.material.opacity = CABLE_CONFIG.otherOpacity;
|
||||
const origColor = c.userData.originalColor;
|
||||
const brightness = CABLE_CONFIG.otherBrightness;
|
||||
@@ -71,6 +108,7 @@ function applyCableVisualState() {
|
||||
c.material.opacity = 1;
|
||||
c.material.color.setHex(c.userData.originalColor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,10 +269,6 @@ function onMouseMove(event, camera) {
|
||||
const frontCables = getFrontFacingCables(allCableLines, camera);
|
||||
const intersects = raycaster.intersectObjects(frontCables);
|
||||
|
||||
if (hoveredCable && (lockedObjectType !== 'cable' || !isSameCable(hoveredCable, lockedObject))) {
|
||||
hoveredCable = null;
|
||||
}
|
||||
|
||||
const hasHoveredCable = intersects.length > 0;
|
||||
let hoveredSat = null;
|
||||
if (getShowSatellites()) {
|
||||
@@ -249,57 +283,35 @@ function onMouseMove(event, camera) {
|
||||
}
|
||||
const hasHoveredSatellite = hoveredSat && hoveredSat.properties;
|
||||
|
||||
if (hoveredCable) {
|
||||
if (!hasHoveredCable || !isSameCable(intersects[0]?.object, hoveredCable)) {
|
||||
if (!isSameCable(hoveredCable, lockedObject)) {
|
||||
setCableState(hoveredCable.userData.cableId, CABLE_STATE.NORMAL);
|
||||
}
|
||||
hoveredCable = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasHoveredCable) {
|
||||
const cable = intersects[0].object;
|
||||
if (!isSameCable(cable, lockedObject)) {
|
||||
hoveredCable = cable;
|
||||
setCableState(cable.userData.cableId, CABLE_STATE.HOVERED);
|
||||
} else {
|
||||
hoveredCable = cable;
|
||||
}
|
||||
|
||||
showInfoCard('cable', {
|
||||
name: cable.userData.name,
|
||||
owner: cable.userData.owner,
|
||||
status: cable.userData.status,
|
||||
length: cable.userData.length,
|
||||
coords: cable.userData.coords,
|
||||
rfs: cable.userData.rfs
|
||||
});
|
||||
showCableInfo(cable);
|
||||
setInfoCardNoBorder(true);
|
||||
hideTooltip();
|
||||
} else if (hasHoveredSatellite) {
|
||||
hoveredSatellite = hoveredSat;
|
||||
const props = hoveredSat.properties;
|
||||
|
||||
const meanMotion = props.mean_motion || 0;
|
||||
const period = meanMotion > 0 ? (1440 / meanMotion).toFixed(1) : '-';
|
||||
const ecc = props.eccentricity || 0;
|
||||
const perigee = (6371 * (1 - ecc)).toFixed(0);
|
||||
const apogee = (6371 * (1 + ecc)).toFixed(0);
|
||||
|
||||
showInfoCard('satellite', {
|
||||
name: props.name,
|
||||
norad_id: props.norad_cat_id,
|
||||
inclination: props.inclination ? props.inclination.toFixed(2) : '-',
|
||||
period: period,
|
||||
perigee: perigee,
|
||||
apogee: apogee
|
||||
});
|
||||
showSatelliteInfo(hoveredSat.properties);
|
||||
setInfoCardNoBorder(true);
|
||||
} else if (lockedObjectType === 'cable') {
|
||||
handleCableClick(lockedObject);
|
||||
} else if (lockedObjectType === 'satellite') {
|
||||
const props = lockedSatellite.properties;
|
||||
const meanMotion = props?.mean_motion || 0;
|
||||
const period = meanMotion > 0 ? (1440 / meanMotion).toFixed(1) : '-';
|
||||
const ecc = props?.eccentricity || 0;
|
||||
const perigee = (6371 * (1 - ecc)).toFixed(0);
|
||||
const apogee = (6371 * (1 + ecc)).toFixed(0);
|
||||
|
||||
showInfoCard('satellite', {
|
||||
name: props?.name || '-',
|
||||
norad_id: props?.norad_cat_id,
|
||||
inclination: props?.inclination ? props.inclination.toFixed(2) : '-',
|
||||
period: period,
|
||||
perigee: perigee,
|
||||
apogee: apogee
|
||||
});
|
||||
} else if (lockedObjectType === 'cable' && lockedObject) {
|
||||
showCableInfo(lockedObject);
|
||||
} else if (lockedObjectType === 'satellite' && lockedSatellite) {
|
||||
showSatelliteInfo(lockedSatellite.properties);
|
||||
} else {
|
||||
hideInfoCard();
|
||||
}
|
||||
@@ -368,12 +380,8 @@ function onClick(event, camera, renderer) {
|
||||
|
||||
const clickedCable = intersects[0].object;
|
||||
const cableId = clickedCable.userData.cableId;
|
||||
const sameCables = getCablesById(cableId);
|
||||
|
||||
sameCables.forEach(c => {
|
||||
c.material.color.setHex(0xffffff);
|
||||
c.material.opacity = 1;
|
||||
});
|
||||
setCableState(cableId, CABLE_STATE.LOCKED);
|
||||
|
||||
lockedObject = clickedCable;
|
||||
lockedObjectType = 'cable';
|
||||
|
||||
Reference in New Issue
Block a user