fix(satellites): fix ring size attenuation and breathing animation
- Add sizeAttenuation: false to sprite materials for fixed ring size - Move breathing animation parameters to SATELLITE_CONFIG constants - Export updateBreathingPhase function to avoid ES module binding issues - Adjust breathing speed and amplitude for better visual effect
This commit is contained in:
@@ -54,10 +54,19 @@ export const CABLE_STATE = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SATELLITE_CONFIG = {
|
export const SATELLITE_CONFIG = {
|
||||||
maxCount: 2000,
|
maxCount: 5000,
|
||||||
dotSize: 1.5,
|
trailLength: 10,
|
||||||
trailLength: 30,
|
dotSize: 4,
|
||||||
apiPath: '/api/v1/visualization/geo/satellites'
|
ringSize: 0.07,
|
||||||
|
apiPath: '/api/v1/visualization/geo/satellites',
|
||||||
|
breathingSpeed: 0.08,
|
||||||
|
breathingScaleAmplitude: 0.15,
|
||||||
|
breathingOpacityMin: 0.5,
|
||||||
|
breathingOpacityMax: 0.8,
|
||||||
|
dotBreathingSpeed: 0.12,
|
||||||
|
dotBreathingScaleAmplitude: 0.2,
|
||||||
|
dotOpacityMin: 0.7,
|
||||||
|
dotOpacityMax: 1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PREDICTED_ORBIT_CONFIG = {
|
export const PREDICTED_ORBIT_CONFIG = {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
} from './ui.js';
|
} from './ui.js';
|
||||||
import { createEarth, createClouds, createTerrain, createStars, createGridLines, toggleTerrain, getEarth } from './earth.js';
|
import { createEarth, createClouds, createTerrain, createStars, createGridLines, toggleTerrain, getEarth } from './earth.js';
|
||||||
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked, getCableState, setCableState, clearAllCableStates, applyLandingPointVisualState, resetLandingPointVisualState, getAllLandingPoints, getShowCables } from './cables.js';
|
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked, getCableState, setCableState, clearAllCableStates, applyLandingPointVisualState, resetLandingPointVisualState, getAllLandingPoints, getShowCables } from './cables.js';
|
||||||
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, getSatelliteCount, selectSatellite, getSatelliteData, getSatellitePoints, setSatelliteRingState, updateLockedRingPosition, updateHoverRingPosition, getSatellitePositions, showPredictedOrbit, hidePredictedOrbit } from './satellites.js';
|
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, getSatelliteCount, selectSatellite, getSatelliteData, getSatellitePoints, setSatelliteRingState, updateLockedRingPosition, updateHoverRingPosition, getSatellitePositions, showPredictedOrbit, hidePredictedOrbit, updateBreathingPhase } from './satellites.js';
|
||||||
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate, resetView } from './controls.js';
|
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate, resetView } from './controls.js';
|
||||||
import { initInfoCard, showInfoCard, hideInfoCard, getCurrentType, setInfoCardNoBorder } from './info-card.js';
|
import { initInfoCard, showInfoCard, hideInfoCard, getCurrentType, setInfoCardNoBorder } from './info-card.js';
|
||||||
|
|
||||||
@@ -32,6 +32,9 @@ let lockedObject = null;
|
|||||||
let lockedObjectType = null;
|
let lockedObjectType = null;
|
||||||
let dragStartTime = 0;
|
let dragStartTime = 0;
|
||||||
let isLongDrag = false;
|
let isLongDrag = false;
|
||||||
|
let lastSatClickTime = 0;
|
||||||
|
let lastSatClickIndex = 0;
|
||||||
|
let lastSatClickPos = { x: 0, y: 0 };
|
||||||
|
|
||||||
export function clearLockedObject() {
|
export function clearLockedObject() {
|
||||||
hidePredictedOrbit();
|
hidePredictedOrbit();
|
||||||
@@ -44,6 +47,7 @@ export function clearLockedObject() {
|
|||||||
lockedObjectType = null;
|
lockedObjectType = null;
|
||||||
lockedSatellite = null;
|
lockedSatellite = null;
|
||||||
lockedSatelliteIndex = null;
|
lockedSatelliteIndex = null;
|
||||||
|
window.lockedSatelliteIndex = null;
|
||||||
cableLockedData = null;
|
cableLockedData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +139,7 @@ export function init() {
|
|||||||
|
|
||||||
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||||
camera.position.z = CONFIG.defaultCameraZ;
|
camera.position.z = CONFIG.defaultCameraZ;
|
||||||
|
window.camera = camera;
|
||||||
|
|
||||||
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false, powerPreference: 'high-performance' });
|
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false, powerPreference: 'high-performance' });
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
@@ -430,8 +435,26 @@ function onClick(event, camera, renderer) {
|
|||||||
setAutoRotate(false);
|
setAutoRotate(false);
|
||||||
handleCableClick(clickedCable);
|
handleCableClick(clickedCable);
|
||||||
} else if (satIntersects.length > 0) {
|
} else if (satIntersects.length > 0) {
|
||||||
const index = satIntersects[0].index;
|
const now = Date.now();
|
||||||
const sat = selectSatellite(index);
|
const clickX = event.clientX;
|
||||||
|
const clickY = event.clientY;
|
||||||
|
|
||||||
|
let selectedIndex;
|
||||||
|
if (satIntersects.length > 1 &&
|
||||||
|
now - lastSatClickTime < 500 &&
|
||||||
|
Math.abs(clickX - lastSatClickPos.x) < 30 &&
|
||||||
|
Math.abs(clickY - lastSatClickPos.y) < 30) {
|
||||||
|
const currentIdx = satIntersects.findIndex(s => s.index === lastSatClickIndex);
|
||||||
|
selectedIndex = satIntersects[(currentIdx + 1) % satIntersects.length].index;
|
||||||
|
} else {
|
||||||
|
selectedIndex = satIntersects[0].index;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSatClickTime = now;
|
||||||
|
lastSatClickIndex = selectedIndex;
|
||||||
|
lastSatClickPos = { x: clickX, y: clickY };
|
||||||
|
|
||||||
|
const sat = selectSatellite(selectedIndex);
|
||||||
|
|
||||||
if (sat && sat.properties) {
|
if (sat && sat.properties) {
|
||||||
clearLockedObject();
|
clearLockedObject();
|
||||||
@@ -439,13 +462,14 @@ function onClick(event, camera, renderer) {
|
|||||||
lockedObject = sat;
|
lockedObject = sat;
|
||||||
lockedObjectType = 'satellite';
|
lockedObjectType = 'satellite';
|
||||||
lockedSatellite = sat;
|
lockedSatellite = sat;
|
||||||
lockedSatelliteIndex = index;
|
lockedSatelliteIndex = selectedIndex;
|
||||||
|
window.lockedSatelliteIndex = selectedIndex;
|
||||||
showPredictedOrbit(sat);
|
showPredictedOrbit(sat);
|
||||||
setAutoRotate(false);
|
setAutoRotate(false);
|
||||||
|
|
||||||
const satPositions = getSatellitePositions();
|
const satPositions = getSatellitePositions();
|
||||||
if (satPositions && satPositions[index]) {
|
if (satPositions && satPositions[selectedIndex]) {
|
||||||
setSatelliteRingState(index, 'locked', satPositions[index].current);
|
setSatelliteRingState(selectedIndex, 'locked', satPositions[selectedIndex].current);
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = sat.properties;
|
const props = sat.properties;
|
||||||
@@ -501,6 +525,9 @@ function animate() {
|
|||||||
|
|
||||||
const satPositions = getSatellitePositions();
|
const satPositions = getSatellitePositions();
|
||||||
|
|
||||||
|
// 更新呼吸动画相位
|
||||||
|
updateBreathingPhase();
|
||||||
|
|
||||||
if (lockedObjectType === 'satellite' && lockedSatelliteIndex !== null) {
|
if (lockedObjectType === 'satellite' && lockedSatelliteIndex !== null) {
|
||||||
if (satPositions && satPositions[lockedSatelliteIndex]) {
|
if (satPositions && satPositions[lockedSatelliteIndex]) {
|
||||||
updateLockedRingPosition(satPositions[lockedSatelliteIndex].current);
|
updateLockedRingPosition(satPositions[lockedSatelliteIndex].current);
|
||||||
|
|||||||
@@ -14,13 +14,19 @@ let selectedSatellite = null;
|
|||||||
let satellitePositions = [];
|
let satellitePositions = [];
|
||||||
let hoverRingSprite = null;
|
let hoverRingSprite = null;
|
||||||
let lockedRingSprite = null;
|
let lockedRingSprite = null;
|
||||||
|
let lockedDotSprite = null;
|
||||||
|
export let breathingPhase = 0;
|
||||||
|
|
||||||
|
export function updateBreathingPhase() {
|
||||||
|
breathingPhase += SATELLITE_CONFIG.breathingSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
const SATELLITE_API = SATELLITE_CONFIG.apiPath + '?limit=' + SATELLITE_CONFIG.maxCount;
|
const SATELLITE_API = SATELLITE_CONFIG.apiPath + '?limit=' + SATELLITE_CONFIG.maxCount;
|
||||||
const MAX_SATELLITES = SATELLITE_CONFIG.maxCount;
|
const MAX_SATELLITES = SATELLITE_CONFIG.maxCount;
|
||||||
const TRAIL_LENGTH = SATELLITE_CONFIG.trailLength;
|
const TRAIL_LENGTH = SATELLITE_CONFIG.trailLength;
|
||||||
const DOT_TEXTURE_SIZE = 32;
|
const DOT_TEXTURE_SIZE = 32;
|
||||||
|
|
||||||
function createCircularDotTexture() {
|
function createDotTexture() {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = DOT_TEXTURE_SIZE;
|
canvas.width = DOT_TEXTURE_SIZE;
|
||||||
canvas.height = DOT_TEXTURE_SIZE;
|
canvas.height = DOT_TEXTURE_SIZE;
|
||||||
@@ -68,7 +74,7 @@ export function createSatellites(scene, earthObj) {
|
|||||||
const positions = new Float32Array(MAX_SATELLITES * 3);
|
const positions = new Float32Array(MAX_SATELLITES * 3);
|
||||||
const colors = new Float32Array(MAX_SATELLITES * 3);
|
const colors = new Float32Array(MAX_SATELLITES * 3);
|
||||||
|
|
||||||
const dotTexture = createCircularDotTexture();
|
const dotTexture = createDotTexture();
|
||||||
|
|
||||||
const pointsGeometry = new THREE.BufferGeometry();
|
const pointsGeometry = new THREE.BufferGeometry();
|
||||||
pointsGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
pointsGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
||||||
@@ -80,13 +86,27 @@ export function createSatellites(scene, earthObj) {
|
|||||||
vertexColors: true,
|
vertexColors: true,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
sizeAttenuation: true,
|
sizeAttenuation: false,
|
||||||
alphaTest: 0.1
|
alphaTest: 0.1
|
||||||
});
|
});
|
||||||
|
|
||||||
satellitePoints = new THREE.Points(pointsGeometry, pointsMaterial);
|
satellitePoints = new THREE.Points(pointsGeometry, pointsMaterial);
|
||||||
satellitePoints.visible = false;
|
satellitePoints.visible = false;
|
||||||
satellitePoints.userData = { type: 'satellitePoints' };
|
satellitePoints.userData = { type: 'satellitePoints' };
|
||||||
|
|
||||||
|
const originalScale = { x: 1, y: 1, z: 1 };
|
||||||
|
satellitePoints.onBeforeRender = (renderer, scene, camera, geometry, material) => {
|
||||||
|
if (earthObj && earthObj.scale.x !== 1) {
|
||||||
|
satellitePoints.scale.set(
|
||||||
|
originalScale.x / earthObj.scale.x,
|
||||||
|
originalScale.y / earthObj.scale.y,
|
||||||
|
originalScale.z / earthObj.scale.z
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
satellitePoints.scale.set(originalScale.x, originalScale.y, originalScale.z);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
earthObj.add(satellitePoints);
|
earthObj.add(satellitePoints);
|
||||||
|
|
||||||
const trailPositions = new Float32Array(MAX_SATELLITES * TRAIL_LENGTH * 3);
|
const trailPositions = new Float32Array(MAX_SATELLITES * TRAIL_LENGTH * 3);
|
||||||
@@ -112,7 +132,9 @@ export function createSatellites(scene, earthObj) {
|
|||||||
for (let i = 0; i < MAX_SATELLITES; i++) {
|
for (let i = 0; i < MAX_SATELLITES; i++) {
|
||||||
satellitePositions.push({
|
satellitePositions.push({
|
||||||
current: new THREE.Vector3(),
|
current: new THREE.Vector3(),
|
||||||
trail: []
|
trail: [],
|
||||||
|
trailIndex: 0,
|
||||||
|
trailCount: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,12 +171,8 @@ function computeSatellitePosition(satellite, time) {
|
|||||||
const tleLine1 = `1 ${noradId.toString().padStart(5)}U 00001A ${epochStr} .00000000 00000-0 00000-0 0 9999`;
|
const tleLine1 = `1 ${noradId.toString().padStart(5)}U 00001A ${epochStr} .00000000 00000-0 00000-0 0 9999`;
|
||||||
const tleLine2 = `2 ${noradId.toString().padStart(5)} ${raan.toFixed(4).padStart(8)} ${inclination.toFixed(4).padStart(8)} ${eccStr.substring(1)} ${argOfPerigee.toFixed(4).padStart(8)} ${meanAnomaly.toFixed(4).padStart(8)} ${meanMotion.toFixed(8).padStart(11)} 0 9999`;
|
const tleLine2 = `2 ${noradId.toString().padStart(5)} ${raan.toFixed(4).padStart(8)} ${inclination.toFixed(4).padStart(8)} ${eccStr.substring(1)} ${argOfPerigee.toFixed(4).padStart(8)} ${meanAnomaly.toFixed(4).padStart(8)} ${meanMotion.toFixed(8).padStart(11)} 0 9999`;
|
||||||
|
|
||||||
console.log('[DEBUG computeSat] TLE1:', tleLine1);
|
|
||||||
console.log('[DEBUG computeSat] TLE2:', tleLine2);
|
|
||||||
const satrec = twoline2satrec(tleLine1, tleLine2);
|
const satrec = twoline2satrec(tleLine1, tleLine2);
|
||||||
console.log('[DEBUG computeSat] satrec.error:', satrec?.error, 'satrec.no:', satrec?.no);
|
|
||||||
if (!satrec || satrec.error) {
|
if (!satrec || satrec.error) {
|
||||||
console.log('[DEBUG computeSat] returning null due to satrec error');
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,9 +273,11 @@ export function updateSatellitePositions(deltaTime = 0) {
|
|||||||
|
|
||||||
satellitePositions[i].current.copy(pos);
|
satellitePositions[i].current.copy(pos);
|
||||||
|
|
||||||
satellitePositions[i].trail.push(pos.clone());
|
const satPos = satellitePositions[i];
|
||||||
if (satellitePositions[i].trail.length > TRAIL_LENGTH) {
|
if (i !== window.lockedSatelliteIndex) {
|
||||||
satellitePositions[i].trail.shift();
|
satPos.trail[satPos.trailIndex] = pos.clone();
|
||||||
|
satPos.trailIndex = (satPos.trailIndex + 1) % TRAIL_LENGTH;
|
||||||
|
if (satPos.trailCount < TRAIL_LENGTH) satPos.trailCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
positions[i * 3] = pos.x;
|
positions[i * 3] = pos.x;
|
||||||
@@ -287,20 +307,33 @@ export function updateSatellitePositions(deltaTime = 0) {
|
|||||||
colors[i * 3 + 1] = g;
|
colors[i * 3 + 1] = g;
|
||||||
colors[i * 3 + 2] = b;
|
colors[i * 3 + 2] = b;
|
||||||
|
|
||||||
const trail = satellitePositions[i].trail;
|
const sp = satellitePositions[i];
|
||||||
|
const trail = sp.trail;
|
||||||
|
const tc = sp.trailCount;
|
||||||
|
const ti = sp.trailIndex;
|
||||||
|
|
||||||
for (let j = 0; j < TRAIL_LENGTH; j++) {
|
for (let j = 0; j < TRAIL_LENGTH; j++) {
|
||||||
const trailIdx = (i * TRAIL_LENGTH + j) * 3;
|
const trailIdx = (i * TRAIL_LENGTH + j) * 3;
|
||||||
|
|
||||||
if (j < trail.length) {
|
if (j < tc) {
|
||||||
const t = trail[j];
|
const idx = (ti - tc + j + TRAIL_LENGTH) % TRAIL_LENGTH;
|
||||||
trailPositions[trailIdx] = t.x;
|
const t = trail[idx];
|
||||||
trailPositions[trailIdx + 1] = t.y;
|
if (t) {
|
||||||
trailPositions[trailIdx + 2] = t.z;
|
trailPositions[trailIdx] = t.x;
|
||||||
|
trailPositions[trailIdx + 1] = t.y;
|
||||||
const alpha = j / trail.length;
|
trailPositions[trailIdx + 2] = t.z;
|
||||||
trailColors[trailIdx] = r * alpha;
|
const alpha = (j + 1) / tc;
|
||||||
trailColors[trailIdx + 1] = g * alpha;
|
trailColors[trailIdx] = r * alpha;
|
||||||
trailColors[trailIdx + 2] = b * alpha;
|
trailColors[trailIdx + 1] = g * alpha;
|
||||||
|
trailColors[trailIdx + 2] = b * alpha;
|
||||||
|
} else {
|
||||||
|
trailPositions[trailIdx] = pos.x;
|
||||||
|
trailPositions[trailIdx + 1] = pos.y;
|
||||||
|
trailPositions[trailIdx + 2] = pos.z;
|
||||||
|
trailColors[trailIdx] = 0;
|
||||||
|
trailColors[trailIdx + 1] = 0;
|
||||||
|
trailColors[trailIdx + 2] = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trailPositions[trailIdx] = pos.x;
|
trailPositions[trailIdx] = pos.x;
|
||||||
trailPositions[trailIdx + 1] = pos.y;
|
trailPositions[trailIdx + 1] = pos.y;
|
||||||
@@ -312,7 +345,7 @@ export function updateSatellitePositions(deltaTime = 0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = count; i < 2000; i++) {
|
for (let i = count; i < MAX_SATELLITES; i++) {
|
||||||
positions[i * 3] = 0;
|
positions[i * 3] = 0;
|
||||||
positions[i * 3 + 1] = 0;
|
positions[i * 3 + 1] = 0;
|
||||||
positions[i * 3 + 2] = 0;
|
positions[i * 3 + 2] = 0;
|
||||||
@@ -393,12 +426,19 @@ export function showHoverRing(position, isLocked = false) {
|
|||||||
map: ringTexture,
|
map: ringTexture,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
depthTest: false
|
depthTest: false,
|
||||||
|
sizeAttenuation: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ringSize = SATELLITE_CONFIG.ringSize;
|
||||||
const sprite = new THREE.Sprite(spriteMaterial);
|
const sprite = new THREE.Sprite(spriteMaterial);
|
||||||
sprite.position.copy(position);
|
sprite.position.copy(position);
|
||||||
sprite.scale.set(3, 3, 1);
|
|
||||||
|
const camera = window.camera;
|
||||||
|
const cameraDistance = camera ? camera.position.distanceTo(position) : 400;
|
||||||
|
const scale = ringSize;
|
||||||
|
sprite.scale.set(scale, scale, 1);
|
||||||
|
console.log(`[Ring create] ringSize: ${ringSize}, camDist: ${cameraDistance}, scale: ${scale}`);
|
||||||
|
|
||||||
earthObjRef.add(sprite);
|
earthObjRef.add(sprite);
|
||||||
|
|
||||||
@@ -407,6 +447,24 @@ export function showHoverRing(position, isLocked = false) {
|
|||||||
earthObjRef.remove(lockedRingSprite);
|
earthObjRef.remove(lockedRingSprite);
|
||||||
}
|
}
|
||||||
lockedRingSprite = sprite;
|
lockedRingSprite = sprite;
|
||||||
|
|
||||||
|
if (lockedDotSprite) {
|
||||||
|
earthObjRef.remove(lockedDotSprite);
|
||||||
|
}
|
||||||
|
const dotCanvas = createBrighterDotCanvas();
|
||||||
|
const dotTexture = new THREE.CanvasTexture(dotCanvas);
|
||||||
|
dotTexture.needsUpdate = true;
|
||||||
|
const dotMaterial = new THREE.SpriteMaterial({
|
||||||
|
map: dotTexture,
|
||||||
|
transparent: true,
|
||||||
|
opacity: 1.0,
|
||||||
|
depthTest: false
|
||||||
|
});
|
||||||
|
lockedDotSprite = new THREE.Sprite(dotMaterial);
|
||||||
|
lockedDotSprite.position.copy(position);
|
||||||
|
lockedDotSprite.scale.set(4 * cameraDistance / 200, 4 * cameraDistance / 200, 1);
|
||||||
|
|
||||||
|
earthObjRef.add(lockedDotSprite);
|
||||||
} else {
|
} else {
|
||||||
if (hoverRingSprite) {
|
if (hoverRingSprite) {
|
||||||
earthObjRef.remove(hoverRingSprite);
|
earthObjRef.remove(hoverRingSprite);
|
||||||
@@ -417,6 +475,23 @@ export function showHoverRing(position, isLocked = false) {
|
|||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBrighterDotCanvas() {
|
||||||
|
const size = DOT_TEXTURE_SIZE * 2;
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = size;
|
||||||
|
canvas.height = size;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
const center = size / 2;
|
||||||
|
const gradient = ctx.createRadialGradient(center, center, 0, center, center, center);
|
||||||
|
gradient.addColorStop(0, 'rgba(255, 255, 200, 1)');
|
||||||
|
gradient.addColorStop(0.3, 'rgba(255, 220, 100, 0.9)');
|
||||||
|
gradient.addColorStop(0.7, 'rgba(255, 180, 50, 0.5)');
|
||||||
|
gradient.addColorStop(1, 'rgba(255, 150, 0, 0)');
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
export function hideHoverRings() {
|
export function hideHoverRings() {
|
||||||
if (!earthObjRef) return;
|
if (!earthObjRef) return;
|
||||||
|
|
||||||
@@ -427,20 +502,45 @@ export function hideHoverRings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hideLockedRing() {
|
export function hideLockedRing() {
|
||||||
if (!earthObjRef || !lockedRingSprite) return;
|
if (!earthObjRef) return;
|
||||||
earthObjRef.remove(lockedRingSprite);
|
if (lockedRingSprite) {
|
||||||
lockedRingSprite = null;
|
earthObjRef.remove(lockedRingSprite);
|
||||||
|
lockedRingSprite = null;
|
||||||
|
}
|
||||||
|
if (lockedDotSprite) {
|
||||||
|
earthObjRef.remove(lockedDotSprite);
|
||||||
|
lockedDotSprite = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateLockedRingPosition(position) {
|
export function updateLockedRingPosition(position) {
|
||||||
|
const ringSize = SATELLITE_CONFIG.ringSize;
|
||||||
|
const camera = window.camera;
|
||||||
|
const cameraDistance = camera ? camera.position.distanceTo(position) : 400;
|
||||||
if (lockedRingSprite && position) {
|
if (lockedRingSprite && position) {
|
||||||
lockedRingSprite.position.copy(position);
|
lockedRingSprite.position.copy(position);
|
||||||
|
const breathScale = 1 + Math.sin(breathingPhase) * SATELLITE_CONFIG.breathingScaleAmplitude;
|
||||||
|
lockedRingSprite.scale.set(ringSize * breathScale, ringSize * breathScale, 1);
|
||||||
|
const breathOpacity = SATELLITE_CONFIG.breathingOpacityMin + Math.sin(breathingPhase) * (SATELLITE_CONFIG.breathingOpacityMax - SATELLITE_CONFIG.breathingOpacityMin);
|
||||||
|
lockedRingSprite.material.opacity = breathOpacity;
|
||||||
|
}
|
||||||
|
if (lockedDotSprite && position) {
|
||||||
|
lockedDotSprite.position.copy(position);
|
||||||
|
const dotBreathScale = 1 + Math.sin(breathingPhase) * SATELLITE_CONFIG.dotBreathingScaleAmplitude;
|
||||||
|
lockedDotSprite.scale.set(4 * cameraDistance / 200 * dotBreathScale, 4 * cameraDistance / 200 * dotBreathScale, 1);
|
||||||
|
lockedDotSprite.material.opacity = SATELLITE_CONFIG.dotOpacityMin + Math.sin(breathingPhase) * (SATELLITE_CONFIG.dotOpacityMax - SATELLITE_CONFIG.dotOpacityMin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateHoverRingPosition(position) {
|
export function updateHoverRingPosition(position) {
|
||||||
|
const ringSize = SATELLITE_CONFIG.ringSize;
|
||||||
|
const camera = window.camera;
|
||||||
|
const cameraDistance = camera ? camera.position.distanceTo(position) : 400;
|
||||||
|
const scale = ringSize;
|
||||||
if (hoverRingSprite && position) {
|
if (hoverRingSprite && position) {
|
||||||
hoverRingSprite.position.copy(position);
|
hoverRingSprite.position.copy(position);
|
||||||
|
hoverRingSprite.scale.set(scale, scale, 1);
|
||||||
|
console.log(`[Hover update] ringSize: ${ringSize}, camDist: ${cameraDistance}, scale: ${scale}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,16 +612,8 @@ export function showPredictedOrbit(satellite) {
|
|||||||
const props = satellite.properties;
|
const props = satellite.properties;
|
||||||
const meanMotion = props?.mean_motion || 15;
|
const meanMotion = props?.mean_motion || 15;
|
||||||
const periodSeconds = calculateOrbitalPeriod(meanMotion);
|
const periodSeconds = calculateOrbitalPeriod(meanMotion);
|
||||||
console.log('[DEBUG] meanMotion:', meanMotion, 'periodSeconds:', periodSeconds);
|
|
||||||
|
|
||||||
// Test current time
|
|
||||||
const now = new Date();
|
|
||||||
const testPos = computeSatellitePosition(satellite, now);
|
|
||||||
console.log('[DEBUG] testPos (now):', testPos);
|
|
||||||
|
|
||||||
const points = calculatePredictedOrbit(satellite, periodSeconds);
|
const points = calculatePredictedOrbit(satellite, periodSeconds);
|
||||||
console.log('[DEBUG] points.length:', points.length);
|
|
||||||
|
|
||||||
if (points.length < 2) return;
|
if (points.length < 2) return;
|
||||||
|
|
||||||
const positions = new Float32Array(points.length * 3);
|
const positions = new Float32Array(points.length * 3);
|
||||||
|
|||||||
Reference in New Issue
Block a user