fix(earth): highlight all cable segments by cable_id

- Add cable_id mapping to group MultiLineString segments
- Highlight all segments of same cable on hover
- Highlight all segments of same cable on click lock
- Reset all segments when clearing lock
- Add pulse animation to all locked cable segments
- Fix hover/click behavior with cable_id grouping
This commit is contained in:
rayd1o
2026-03-12 12:51:07 +08:00
parent aaae6a53c3
commit ceb1b728d5
2 changed files with 81 additions and 23 deletions

View File

@@ -9,6 +9,7 @@ import { updateCableDetails, updateEarthStats, showStatusMessage } from './ui.js
export let cableLines = [];
export let landingPoints = [];
export let lockedCable = null;
let cableIdMap = new Map();
function getCableColor(properties) {
if (properties.color) {
@@ -46,8 +47,10 @@ function createCableLine(points, color, properties, earthObj) {
});
const cableLine = new THREE.Line(lineGeometry, lineMaterial);
const cableId = properties.cable_id || properties.id || properties.Name || Math.random().toString(36);
cableLine.userData = {
type: 'cable',
cableId: cableId,
name: properties.Name || properties.cableName || 'Unknown',
owner: properties.owner || properties.owners || '-',
status: properties.status || '-',
@@ -58,6 +61,11 @@ function createCableLine(points, color, properties, earthObj) {
};
cableLine.renderOrder = 1;
if (!cableIdMap.has(cableId)) {
cableIdMap.set(cableId, []);
}
cableIdMap.get(cableId).push(cableLine);
return cableLine;
}
@@ -332,6 +340,10 @@ export function getCableLines() {
return cableLines;
}
export function getCablesById(cableId) {
return cableIdMap.get(cableId) || [];
}
export function getLandingPoints() {
return landingPoints;
}

View File

@@ -14,7 +14,7 @@ import {
hideTooltip
} from './ui.js';
import { createEarth, createClouds, createTerrain, createStars, createGridLines, toggleTerrain, getEarth } from './earth.js';
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines } from './cables.js';
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById } from './cables.js';
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate } from './controls.js';
export let scene, camera, renderer;
@@ -23,6 +23,7 @@ let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
let hoveredCable = null;
let lockedCable = null;
let lockedCableData = null;
window.addEventListener('error', (e) => {
console.error('全局错误:', e.error);
@@ -149,17 +150,27 @@ function onMouseMove(event, camera) {
const intersects = raycaster.intersectObjects(frontCables);
if (hoveredCable && hoveredCable !== lockedCable) {
if (hoveredCable.userData.originalColor !== undefined) {
hoveredCable.material.color.setHex(hoveredCable.userData.originalColor);
const prevCableId = hoveredCable.userData.cableId;
const prevSameCables = getCablesById(prevCableId);
prevSameCables.forEach(c => {
if (c.userData.originalColor !== undefined) {
c.material.color.setHex(c.userData.originalColor);
}
});
hoveredCable = null;
}
if (intersects.length > 0) {
const cable = intersects[0].object;
const cableId = cable.userData.cableId;
const sameCables = getCablesById(cableId);
if (cable !== lockedCable) {
cable.material.color.setHex(0xffffff);
cable.material.opacity = 1;
sameCables.forEach(c => {
c.material.color.setHex(0xffffff);
c.material.opacity = 1;
});
hoveredCable = cable;
hoveredCable = cable;
}
@@ -174,7 +185,15 @@ function onMouseMove(event, camera) {
hideTooltip();
} else {
if (!lockedCable) {
if (lockedCable && lockedCableData) {
document.getElementById('cable-name').textContent =
lockedCableData.name || lockedCableData.shortname || '未命名电缆';
document.getElementById('cable-owner').textContent = lockedCableData.owner || '-';
document.getElementById('cable-status').textContent = lockedCableData.status || '-';
document.getElementById('cable-length').textContent = lockedCableData.length || '-';
document.getElementById('cable-coords').textContent = '-';
document.getElementById('cable-rfs').textContent = lockedCableData.rfs || '-';
} else {
document.getElementById('cable-name').textContent = '点击电缆查看详情';
document.getElementById('cable-owner').textContent = '-';
document.getElementById('cable-status').textContent = '-';
@@ -236,23 +255,41 @@ function onClick(event, camera, renderer) {
const intersects = raycaster.intersectObjects(frontCables);
if (intersects.length > 0) {
if (lockedCable && lockedCable !== intersects[0].object) {
if (lockedCable.userData.originalColor !== undefined) {
lockedCable.material.color.setHex(lockedCable.userData.originalColor);
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 = intersects[0].object;
lockedCable.material.color.setHex(0xffffff);
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;
});
lockedCable = clickedCable;
lockedCableData = { ...clickedCable.userData };
setAutoRotate(false);
handleCableClick(intersects[0].object);
handleCableClick(clickedCable);
} else {
if (lockedCable) {
if (lockedCable.userData.originalColor !== undefined) {
lockedCable.material.color.setHex(lockedCable.userData.originalColor);
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;
}
setAutoRotate(true);
clearCableSelection();
@@ -270,9 +307,13 @@ function animate() {
if (lockedCable) {
const pulse = (Math.sin(Date.now() * 0.003) + 1) * 0.5;
lockedCable.material.opacity = 0.6 + pulse * 0.4;
const glowIntensity = 0.7 + pulse * 0.3;
lockedCable.material.color.setRGB(glowIntensity, glowIntensity, glowIntensity);
const cableId = lockedCable.userData.cableId;
const sameCables = getCablesById(cableId);
sameCables.forEach(c => {
c.material.opacity = 0.6 + pulse * 0.4;
c.material.color.setRGB(glowIntensity, glowIntensity, glowIntensity);
});
}
renderer.render(scene, camera);
@@ -280,11 +321,16 @@ function animate() {
window.clearLockedCable = function() {
if (lockedCable) {
if (lockedCable.userData.originalColor !== undefined) {
lockedCable.material.color.setHex(lockedCable.userData.originalColor);
lockedCable.material.opacity = 1.0;
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();
};