release: bump version to 0.31.3
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
BGP_CONFIG,
|
||||
CRUISE_CONFIG,
|
||||
ROTATION_MODE,
|
||||
SCENE_LIGHT_CONFIG,
|
||||
} from "./constants.js";
|
||||
import { vector3ToLatLon, screenToEarthCoords } from "./utils.js";
|
||||
import {
|
||||
@@ -36,7 +37,7 @@ import {
|
||||
clearEarthTexture,
|
||||
setEarthSunDirection,
|
||||
} from "./earth.js";
|
||||
import { registerTerrainMesh, clearTerrainData } from "./terrain.js";
|
||||
import { registerTerrainMesh, clearTerrainData, sampleElevationAt } from "./terrain.js";
|
||||
import {
|
||||
initCelestialLayer,
|
||||
updateCelestialLayer,
|
||||
@@ -45,6 +46,7 @@ import {
|
||||
getSunDirection,
|
||||
setCelestialOrientation,
|
||||
setCelestialFollow,
|
||||
setCelestialDayNightEnabled,
|
||||
} from "./celestial.js";
|
||||
import {
|
||||
loadGeoJSONFromPath,
|
||||
@@ -129,12 +131,17 @@ import {
|
||||
getAutoRotate,
|
||||
getRotationMode,
|
||||
getShowTerrain,
|
||||
getStartupLoadLayers,
|
||||
setAutoRotate,
|
||||
applyImmediateView,
|
||||
focusEarthView,
|
||||
getZoomLevel,
|
||||
teardownControls,
|
||||
} from "./controls.js";
|
||||
import {
|
||||
createLayerStartupTaskMap,
|
||||
resolveStartupMessage,
|
||||
} from "./layer-startup-tasks.js";
|
||||
import {
|
||||
setLayerButtonState,
|
||||
} from "./layer-button-state.js";
|
||||
@@ -1224,10 +1231,13 @@ export function init() {
|
||||
registerTerrainMesh(createTerrain(earthObj));
|
||||
initCelestialLayer(scene, {
|
||||
camera,
|
||||
ambientLight: sceneLights?.ambientLight ?? null,
|
||||
sunLight: sceneLights?.sunLight ?? null,
|
||||
backLight: sceneLights?.backLight ?? null,
|
||||
pointLight: sceneLights?.pointLight ?? null,
|
||||
earth: earthObj,
|
||||
});
|
||||
setCelestialDayNightEnabled(true);
|
||||
createGridLines(scene, earthObj);
|
||||
createSatellites(scene, earthObj);
|
||||
|
||||
@@ -1258,21 +1268,43 @@ function registerGlobalApi() {
|
||||
}
|
||||
|
||||
function addLights() {
|
||||
const ambientLight = new THREE.AmbientLight(0x404060);
|
||||
const ambientLight = new THREE.AmbientLight(SCENE_LIGHT_CONFIG.ambient.color);
|
||||
ambientLight.intensity = SCENE_LIGHT_CONFIG.ambient.intensity;
|
||||
scene.add(ambientLight);
|
||||
|
||||
const sunLight = new THREE.DirectionalLight(0xffffff, 1.2);
|
||||
sunLight.position.set(5, 3, 5);
|
||||
const sunLight = new THREE.DirectionalLight(
|
||||
SCENE_LIGHT_CONFIG.sun.color,
|
||||
SCENE_LIGHT_CONFIG.sun.intensity,
|
||||
);
|
||||
sunLight.position.set(
|
||||
SCENE_LIGHT_CONFIG.sun.position.x,
|
||||
SCENE_LIGHT_CONFIG.sun.position.y,
|
||||
SCENE_LIGHT_CONFIG.sun.position.z,
|
||||
);
|
||||
sunLight.target.position.set(0, 0, 0);
|
||||
scene.add(sunLight);
|
||||
scene.add(sunLight.target);
|
||||
|
||||
const backLight = new THREE.DirectionalLight(0x446688, 0.3);
|
||||
backLight.position.set(-5, 0, -5);
|
||||
const backLight = new THREE.DirectionalLight(
|
||||
SCENE_LIGHT_CONFIG.back.color,
|
||||
SCENE_LIGHT_CONFIG.back.intensity,
|
||||
);
|
||||
backLight.position.set(
|
||||
SCENE_LIGHT_CONFIG.back.position.x,
|
||||
SCENE_LIGHT_CONFIG.back.position.y,
|
||||
SCENE_LIGHT_CONFIG.back.position.z,
|
||||
);
|
||||
scene.add(backLight);
|
||||
|
||||
const pointLight = new THREE.PointLight(0xffffff, 0.4);
|
||||
pointLight.position.set(10, 10, 10);
|
||||
const pointLight = new THREE.PointLight(
|
||||
SCENE_LIGHT_CONFIG.point.color,
|
||||
SCENE_LIGHT_CONFIG.point.intensity,
|
||||
);
|
||||
pointLight.position.set(
|
||||
SCENE_LIGHT_CONFIG.point.position.x,
|
||||
SCENE_LIGHT_CONFIG.point.position.y,
|
||||
SCENE_LIGHT_CONFIG.point.position.z,
|
||||
);
|
||||
scene.add(pointLight);
|
||||
|
||||
return {
|
||||
@@ -1364,100 +1396,54 @@ async function loadData() {
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
await yieldFrame(16);
|
||||
|
||||
// Step 2 — Landing points
|
||||
if (cablesEnabled) {
|
||||
setLoadingMessage("正在加载登陆点...");
|
||||
await yieldFrame(12);
|
||||
try {
|
||||
await loadLandingPoints(scene, earth, { silent: true });
|
||||
} catch (err) {
|
||||
errors.push({ label: "登陆点", reason: err });
|
||||
}
|
||||
const startupLoaders = createLayerStartupTaskMap({
|
||||
scene,
|
||||
earth,
|
||||
setLoadingMessage,
|
||||
yieldFrame,
|
||||
refreshLegend,
|
||||
setLegendItems,
|
||||
updateCableToggleUi,
|
||||
updateSatelliteToggleUi,
|
||||
updateBGPHud,
|
||||
getShowBGP,
|
||||
getInitialSatelliteLoadLimit,
|
||||
shouldHydrateFullSatelliteSet,
|
||||
scheduleSatellitePositionWarmup,
|
||||
hydrateAllSatellitesInBackground,
|
||||
syncBGPKnownEventIds: () => ensureBGPCruiseAdapter().syncKnownEventIds(),
|
||||
isCancelled: () => loadToken !== currentLoadToken || destroyed,
|
||||
isCablesEnabled: () => cablesEnabled,
|
||||
isSatellitesEnabled: () => satellitesEnabled,
|
||||
nextSatelliteHydrationToken: () => ++satelliteHydrationToken,
|
||||
getSatelliteHydrationToken: () => satelliteHydrationToken,
|
||||
reportError: (label, reason) => {
|
||||
errors.push({ label, reason });
|
||||
},
|
||||
});
|
||||
|
||||
const startupLayers = getStartupLoadLayers();
|
||||
const startupLoadQueue = startupLayers
|
||||
.map((layer) => ({
|
||||
layer,
|
||||
run: startupLoaders[layer.id],
|
||||
}))
|
||||
.filter((entry) => typeof entry.run === "function");
|
||||
|
||||
for (const entry of startupLoadQueue) {
|
||||
await entry.run(entry.layer);
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
await yieldFrame(16);
|
||||
}
|
||||
|
||||
// Step 3 — Cables
|
||||
if (cablesEnabled) {
|
||||
setLoadingMessage("正在加载海缆...");
|
||||
await yieldFrame(12);
|
||||
try {
|
||||
const cableCount = await loadGeoJSONFromPath(scene, earth, {
|
||||
silent: true,
|
||||
});
|
||||
if (loadToken === currentLoadToken && cablesEnabled) {
|
||||
toggleCables(true);
|
||||
updateCableToggleUi(true);
|
||||
setLegendItems("cables", getCableLegendItems());
|
||||
refreshLegend();
|
||||
}
|
||||
} catch (err) {
|
||||
errors.push({ label: "海缆", reason: err });
|
||||
}
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
await yieldFrame(16);
|
||||
}
|
||||
|
||||
// Step 4 — Satellites
|
||||
if (satellitesEnabled) {
|
||||
setLoadingMessage("正在加载卫星...");
|
||||
await yieldFrame(12);
|
||||
try {
|
||||
clearSatelliteData();
|
||||
const loadResult = await loadSatellites({
|
||||
limit: getInitialSatelliteLoadLimit(),
|
||||
});
|
||||
if (loadToken === currentLoadToken && satellitesEnabled) {
|
||||
updateSatelliteToggleUi(true, loadResult.count);
|
||||
setLegendItems("satellites", getSatelliteLegendItems());
|
||||
refreshLegend();
|
||||
scheduleSatellitePositionWarmup(() => {
|
||||
if (
|
||||
loadToken === currentLoadToken &&
|
||||
satellitesEnabled &&
|
||||
!destroyed
|
||||
) {
|
||||
toggleSatellites(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (shouldHydrateFullSatelliteSet(loadResult)) {
|
||||
const hydrationToken = ++satelliteHydrationToken;
|
||||
hydrateAllSatellitesInBackground(
|
||||
() =>
|
||||
hydrationToken === satelliteHydrationToken &&
|
||||
loadToken === currentLoadToken &&
|
||||
satellitesEnabled &&
|
||||
!destroyed,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
errors.push({ label: "卫星", reason: err });
|
||||
}
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
await yieldFrame(16);
|
||||
}
|
||||
|
||||
// Step 5 — BGP
|
||||
setLoadingMessage("正在加载BGP态势...");
|
||||
await yieldFrame(12);
|
||||
try {
|
||||
const bgpResult = await loadBGPAnomalies(scene, earth);
|
||||
if (loadToken === currentLoadToken) {
|
||||
toggleBGP(true);
|
||||
updateBGPHud(bgpResult);
|
||||
ensureBGPCruiseAdapter().syncKnownEventIds();
|
||||
}
|
||||
} catch (err) {
|
||||
errors.push({ label: "BGP态势", reason: err });
|
||||
}
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
await yieldFrame(16);
|
||||
|
||||
// Step 6 — Terrain (if enabled)
|
||||
if (getShowTerrain()) {
|
||||
setLoadingMessage("正在渲染地形...");
|
||||
const terrainLayer = startupLayers.find((layer) => layer.id === "terrain");
|
||||
const terrainMessage = resolveStartupMessage(
|
||||
terrainLayer,
|
||||
"load",
|
||||
"正在渲染地形...",
|
||||
);
|
||||
setLoadingMessage(terrainMessage);
|
||||
await yieldFrame(24);
|
||||
}
|
||||
|
||||
@@ -1493,7 +1479,14 @@ export async function reloadData() {
|
||||
await loadData();
|
||||
}
|
||||
|
||||
export async function setCablesEnabled(enabled) {
|
||||
export function getSatellitesEnabled() {
|
||||
return satellitesEnabled;
|
||||
}
|
||||
|
||||
export async function setCablesEnabled(
|
||||
enabled,
|
||||
{ suppressStatus = false, suppressLoadingUi = false } = {},
|
||||
) {
|
||||
if (enabled === cablesEnabled) {
|
||||
updateCableToggleUi(enabled);
|
||||
return getCableLines().length;
|
||||
@@ -1502,32 +1495,47 @@ export async function setCablesEnabled(enabled) {
|
||||
if (!enabled) {
|
||||
clearSelectionAndInfo();
|
||||
disableCables();
|
||||
showStatusMessage("线缆已隐藏", "info");
|
||||
if (!suppressStatus) {
|
||||
showStatusMessage("线缆已隐藏", "info");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
setLoadingMessage("正在加载线缆数据...");
|
||||
setLoading(true);
|
||||
hideError();
|
||||
if (!suppressLoadingUi) {
|
||||
setLoadingMessage("正在加载线缆数据...");
|
||||
setLoading(true);
|
||||
hideError();
|
||||
}
|
||||
|
||||
try {
|
||||
const cableCount = await ensureCablesEnabled();
|
||||
showStatusMessage("线缆已显示", "info");
|
||||
if (!suppressStatus) {
|
||||
showStatusMessage("线缆已显示", "info");
|
||||
}
|
||||
return cableCount;
|
||||
} catch (error) {
|
||||
cablesEnabled = false;
|
||||
clearCableData(getEarth());
|
||||
updateCableToggleUi(false);
|
||||
const message = `线缆加载失败: ${error?.message || String(error)}`;
|
||||
showError(message);
|
||||
showStatusMessage(message, "error");
|
||||
if (!suppressLoadingUi) {
|
||||
showError(message);
|
||||
}
|
||||
if (!suppressStatus) {
|
||||
showStatusMessage(message, "error");
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (!suppressLoadingUi) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function setSatellitesEnabled(enabled) {
|
||||
export async function setSatellitesEnabled(
|
||||
enabled,
|
||||
{ suppressStatus = false, suppressLoadingUi = false } = {},
|
||||
) {
|
||||
if (enabled === satellitesEnabled) {
|
||||
updateSatelliteToggleUi(enabled);
|
||||
return getSatelliteCount();
|
||||
@@ -1539,24 +1547,34 @@ export async function setSatellitesEnabled(enabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setLoadingMessage("正在加载卫星数据...");
|
||||
setLoading(true);
|
||||
hideError();
|
||||
if (!suppressLoadingUi) {
|
||||
setLoadingMessage("正在加载卫星数据...");
|
||||
setLoading(true);
|
||||
hideError();
|
||||
}
|
||||
|
||||
try {
|
||||
const satelliteCount = await ensureSatellitesEnabled();
|
||||
showStatusMessage("卫星已显示", "info");
|
||||
if (!suppressStatus) {
|
||||
showStatusMessage("卫星已显示", "info");
|
||||
}
|
||||
return satelliteCount;
|
||||
} catch (error) {
|
||||
satellitesEnabled = false;
|
||||
resetSatelliteState();
|
||||
updateSatelliteToggleUi(false, 0);
|
||||
const message = `卫星加载失败: ${error?.message || String(error)}`;
|
||||
showError(message);
|
||||
showStatusMessage(message, "error");
|
||||
if (!suppressLoadingUi) {
|
||||
showError(message);
|
||||
}
|
||||
if (!suppressStatus) {
|
||||
showStatusMessage(message, "error");
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (!suppressLoadingUi) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1618,7 +1636,10 @@ function getFrontFacingCables(cableLines) {
|
||||
scratchCableDirection
|
||||
.subVectors(scratchCableCenter, earth.position)
|
||||
.normalize();
|
||||
return scratchCameraToEarth.dot(scratchCableDirection) > 0;
|
||||
return (
|
||||
scratchCameraToEarth.dot(scratchCableDirection) >
|
||||
SATELLITE_CONFIG.frontFacingDotThreshold
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1634,7 +1655,10 @@ function getFrontFacingBGPMarkers(markers) {
|
||||
scratchBGPDirection
|
||||
.subVectors(scratchBGPWorldPosition, earth.position)
|
||||
.normalize();
|
||||
return scratchCameraToEarth.dot(scratchBGPDirection) > 0;
|
||||
return (
|
||||
scratchCameraToEarth.dot(scratchBGPDirection) >
|
||||
SATELLITE_CONFIG.frontFacingDotThreshold
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1793,10 +1817,16 @@ function onMouseMove(event) {
|
||||
if (earthPoint) {
|
||||
const coords = vector3ToLatLon(earthPoint);
|
||||
updateCoordinatesDisplay(coords.lat, coords.lon, coords.alt);
|
||||
const elevMeters = sampleElevationAt(coords.lat, coords.lon);
|
||||
const elevText = elevMeters !== null
|
||||
? elevMeters >= 1000
|
||||
? `${(elevMeters / 1000).toFixed(2)} km`
|
||||
: `${Math.round(elevMeters)} m`
|
||||
: "—";
|
||||
showTooltip(
|
||||
event.clientX + TOOLTIP_COORDS_OFFSET,
|
||||
event.clientY + TOOLTIP_COORDS_OFFSET,
|
||||
`纬度: ${coords.lat}°<br>经度: ${coords.lon}°<br>海拔: ${coords.alt.toFixed(1)} km`,
|
||||
`纬度: ${coords.lat}°<br>经度: ${coords.lon}°<br>海拔: ${elevText}`,
|
||||
);
|
||||
} else {
|
||||
hideTooltip();
|
||||
|
||||
Reference in New Issue
Block a user