feat: 统一卫星和线缆锁定逻辑,使用lockedObject系统
- 添加lockedObject和lockedObjectType统一管理锁定状态 - 点击任一对象自动清除之前的锁定 - 修复悬停/锁定优先级逻辑 - 修复坐标映射worldToLocal问题 - 添加bun.lock用于bun包管理
This commit is contained in:
@@ -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 } from './cables.js';
|
||||
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked } from './cables.js';
|
||||
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, selectSatellite, getSatelliteData, getSatellitePoints } from './satellites.js';
|
||||
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate } from './controls.js';
|
||||
import { initInfoCard, showInfoCard, hideInfoCard, getCurrentType, setInfoCardNoBorder } from './info-card.js';
|
||||
@@ -23,8 +23,29 @@ let simplex;
|
||||
let isDragging = false;
|
||||
let previousMousePosition = { x: 0, y: 0 };
|
||||
let hoveredCable = null;
|
||||
let lockedCable = null;
|
||||
let lockedCableData = null;
|
||||
let hoveredSatellite = null;
|
||||
let cableLockedData = null;
|
||||
let lockedSatellite = null;
|
||||
let lockedObject = null;
|
||||
let lockedObjectType = null;
|
||||
let dragStartTime = 0;
|
||||
let isLongDrag = false;
|
||||
|
||||
function clearLockedObject() {
|
||||
if (lockedObjectType === 'cable' && lockedObject) {
|
||||
const prevCableId = lockedObject.userData.cableId;
|
||||
const prevSameCables = getCablesById(prevCableId);
|
||||
prevSameCables.forEach(c => {
|
||||
if (c.userData.originalColor !== undefined) {
|
||||
c.material.color.setHex(c.userData.originalColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
lockedObject = null;
|
||||
lockedObjectType = null;
|
||||
lockedSatellite = null;
|
||||
cableLockedData = null;
|
||||
}
|
||||
|
||||
window.addEventListener('error', (e) => {
|
||||
console.error('全局错误:', e.error);
|
||||
@@ -182,7 +203,7 @@ function onMouseMove(event, camera) {
|
||||
const frontCables = getFrontFacingCables(allCableLines, camera);
|
||||
const intersects = raycaster.intersectObjects(frontCables);
|
||||
|
||||
if (hoveredCable && hoveredCable !== lockedCable) {
|
||||
if (hoveredCable && (lockedObjectType !== 'cable' || hoveredCable !== lockedObject)) {
|
||||
const prevCableId = hoveredCable.userData.cableId;
|
||||
const prevSameCables = getCablesById(prevCableId);
|
||||
prevSameCables.forEach(c => {
|
||||
@@ -192,53 +213,101 @@ function onMouseMove(event, camera) {
|
||||
});
|
||||
hoveredCable = null;
|
||||
}
|
||||
|
||||
if (intersects.length > 0) {
|
||||
|
||||
const hasHoveredCable = intersects.length > 0;
|
||||
let hoveredSat = null;
|
||||
if (getShowSatellites()) {
|
||||
const satPoints = getSatellitePoints();
|
||||
if (satPoints) {
|
||||
const satIntersects = raycaster.intersectObject(satPoints);
|
||||
if (satIntersects.length > 0) {
|
||||
const index = satIntersects[0].index;
|
||||
hoveredSat = selectSatellite(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
const hasHoveredSatellite = hoveredSat && hoveredSat.properties;
|
||||
|
||||
if (hasHoveredCable) {
|
||||
const cable = intersects[0].object;
|
||||
const cableId = cable.userData.cableId;
|
||||
const sameCables = getCablesById(cableId);
|
||||
|
||||
if (cable !== lockedCable) {
|
||||
if (lockedObjectType !== 'cable' || cable !== lockedObject) {
|
||||
sameCables.forEach(c => {
|
||||
c.material.color.setHex(0xffffff);
|
||||
c.material.opacity = 1;
|
||||
});
|
||||
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
|
||||
});
|
||||
setInfoCardNoBorder(true);
|
||||
}
|
||||
|
||||
const userData = cable.userData;
|
||||
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
|
||||
});
|
||||
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
|
||||
});
|
||||
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 (lockedCable) {
|
||||
handleCableClick(lockedCable);
|
||||
} else {
|
||||
hideInfoCard();
|
||||
}
|
||||
hideInfoCard();
|
||||
}
|
||||
|
||||
const earthPoint = screenToEarthCoords(event.clientX, event.clientY, camera, earth);
|
||||
if (earthPoint) {
|
||||
const coords = vector3ToLatLon(earthPoint);
|
||||
updateCoordinatesDisplay(coords.lat, coords.lon, coords.alt);
|
||||
|
||||
const earthPoint = screenToEarthCoords(event.clientX, event.clientY, camera, earth);
|
||||
|
||||
if (earthPoint) {
|
||||
const coords = vector3ToLatLon(earthPoint);
|
||||
updateCoordinatesDisplay(coords.lat, coords.lon, coords.alt);
|
||||
|
||||
if (!isDragging) {
|
||||
showTooltip(event.clientX + 10, event.clientY + 10,
|
||||
`纬度: ${coords.lat}°<br>经度: ${coords.lon}°<br>海拔: ${coords.alt.toFixed(1)} km`);
|
||||
}
|
||||
if (!isDragging) {
|
||||
showTooltip(event.clientX + 10, event.clientY + 10,
|
||||
`纬度: ${coords.lat}°<br>经度: ${coords.lon}°<br>海拔: ${coords.alt.toFixed(1)} km`);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDragging) {
|
||||
if (Date.now() - dragStartTime > 500) {
|
||||
isLongDrag = true;
|
||||
}
|
||||
|
||||
const deltaX = event.clientX - previousMousePosition.x;
|
||||
const deltaY = event.clientY - previousMousePosition.y;
|
||||
|
||||
@@ -251,6 +320,8 @@ function onMouseMove(event, camera) {
|
||||
|
||||
function onMouseDown(event) {
|
||||
isDragging = true;
|
||||
dragStartTime = Date.now();
|
||||
isLongDrag = false;
|
||||
previousMousePosition = { x: event.clientX, y: event.clientY };
|
||||
document.getElementById('container').classList.add('dragging');
|
||||
hideTooltip();
|
||||
@@ -276,17 +347,10 @@ function onClick(event, camera, renderer) {
|
||||
const allCableLines = getCableLines();
|
||||
const frontCables = getFrontFacingCables(allCableLines, camera);
|
||||
const intersects = raycaster.intersectObjects(frontCables);
|
||||
const satIntersects = getShowSatellites() ? raycaster.intersectObject(getSatellitePoints()) : [];
|
||||
|
||||
if (intersects.length > 0) {
|
||||
if (lockedCable) {
|
||||
const prevCableId = lockedCable.userData.cableId;
|
||||
const prevSameCables = getCablesById(prevCableId);
|
||||
prevSameCables.forEach(c => {
|
||||
if (c.userData.originalColor !== undefined) {
|
||||
c.material.color.setHex(c.userData.originalColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
clearLockedObject();
|
||||
|
||||
const clickedCable = intersects[0].object;
|
||||
const cableId = clickedCable.userData.cableId;
|
||||
@@ -297,64 +361,51 @@ function onClick(event, camera, renderer) {
|
||||
c.material.opacity = 1;
|
||||
});
|
||||
|
||||
lockedCable = clickedCable;
|
||||
lockedCableData = { ...clickedCable.userData };
|
||||
lockedObject = clickedCable;
|
||||
lockedObjectType = 'cable';
|
||||
cableLockedData = { ...clickedCable.userData };
|
||||
|
||||
setAutoRotate(false);
|
||||
handleCableClick(clickedCable);
|
||||
} else if (satIntersects.length > 0) {
|
||||
const index = satIntersects[0].index;
|
||||
const sat = selectSatellite(index);
|
||||
|
||||
showInfoCard('cable', {
|
||||
name: clickedCable.userData.name,
|
||||
owner: clickedCable.userData.owner,
|
||||
status: clickedCable.userData.status,
|
||||
length: clickedCable.userData.length,
|
||||
coords: clickedCable.userData.coords,
|
||||
rfs: clickedCable.userData.rfs
|
||||
});
|
||||
} else if (getShowSatellites()) {
|
||||
const satIntersects = raycaster.intersectObject(getSatellitePoints());
|
||||
|
||||
if (satIntersects.length > 0) {
|
||||
const index = satIntersects[0].index;
|
||||
const sat = selectSatellite(index);
|
||||
if (sat && sat.properties) {
|
||||
clearLockedObject();
|
||||
|
||||
if (sat && sat.properties) {
|
||||
const props = sat.properties;
|
||||
|
||||
const meanMotion = props.mean_motion || 0;
|
||||
const period = meanMotion > 0 ? (1440 / meanMotion).toFixed(1) : '-';
|
||||
|
||||
const ecc = props.eccentricity || 0;
|
||||
const earthRadius = 6371;
|
||||
const perigee = (earthRadius * (1 - ecc)).toFixed(0);
|
||||
const apogee = (earthRadius * (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
|
||||
});
|
||||
|
||||
showStatusMessage('已选择: ' + props.name, 'info');
|
||||
}
|
||||
lockedObject = sat;
|
||||
lockedObjectType = 'satellite';
|
||||
lockedSatellite = sat;
|
||||
setAutoRotate(false);
|
||||
|
||||
const props = sat.properties;
|
||||
|
||||
const meanMotion = props.mean_motion || 0;
|
||||
const period = meanMotion > 0 ? (1440 / meanMotion).toFixed(1) : '-';
|
||||
|
||||
const ecc = props.eccentricity || 0;
|
||||
const earthRadius = 6371;
|
||||
const perigee = (earthRadius * (1 - ecc)).toFixed(0);
|
||||
const apogee = (earthRadius * (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
|
||||
});
|
||||
|
||||
showStatusMessage('已选择: ' + props.name, 'info');
|
||||
}
|
||||
} else {
|
||||
if (lockedCable) {
|
||||
const prevCableId = lockedCable.userData.cableId;
|
||||
const prevSameCables = getCablesById(prevCableId);
|
||||
prevSameCables.forEach(c => {
|
||||
if (c.userData.originalColor !== undefined) {
|
||||
c.material.color.setHex(c.userData.originalColor);
|
||||
}
|
||||
});
|
||||
lockedCable = null;
|
||||
lockedCableData = null;
|
||||
if (!isLongDrag) {
|
||||
clearLockedObject();
|
||||
setAutoRotate(true);
|
||||
clearCableSelection();
|
||||
}
|
||||
setAutoRotate(true);
|
||||
clearCableSelection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,10 +418,10 @@ function animate() {
|
||||
earth.rotation.y += CONFIG.rotationSpeed;
|
||||
}
|
||||
|
||||
if (lockedCable) {
|
||||
if (lockedObjectType === 'cable') {
|
||||
const pulse = (Math.sin(Date.now() * 0.003) + 1) * 0.5;
|
||||
const glowIntensity = 0.7 + pulse * 0.3;
|
||||
const cableId = lockedCable.userData.cableId;
|
||||
const cableId = lockedObject.userData.cableId;
|
||||
const sameCables = getCablesById(cableId);
|
||||
sameCables.forEach(c => {
|
||||
c.material.opacity = 0.6 + pulse * 0.4;
|
||||
@@ -384,19 +435,7 @@ function animate() {
|
||||
}
|
||||
|
||||
window.clearLockedCable = function() {
|
||||
if (lockedCable) {
|
||||
const cableId = lockedCable.userData.cableId;
|
||||
const sameCables = getCablesById(cableId);
|
||||
sameCables.forEach(c => {
|
||||
if (c.userData.originalColor !== undefined) {
|
||||
c.material.color.setHex(c.userData.originalColor);
|
||||
c.material.opacity = 1.0;
|
||||
}
|
||||
});
|
||||
lockedCable = null;
|
||||
lockedCableData = null;
|
||||
}
|
||||
clearCableSelection();
|
||||
clearLockedObject();
|
||||
};
|
||||
|
||||
window.clearSelection = function() {
|
||||
|
||||
Reference in New Issue
Block a user