release: bump version to 0.41.1
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,56 @@ export let lockedCable = null;
|
||||
let cableIdMap = new Map();
|
||||
let cableStates = new Map();
|
||||
let cablesVisible = true;
|
||||
let landingPointGeometry = null;
|
||||
let landingPointTexture = null;
|
||||
const _lpWorldPos = new THREE.Vector3();
|
||||
|
||||
function createLandingPointTexture() {
|
||||
const size = CABLE_CONFIG.landingPoint.textureSize;
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
const ctx = canvas.getContext("2d");
|
||||
const iconPath = new Path2D(
|
||||
[
|
||||
"M400 704",
|
||||
"C386 704 375 697 367 684",
|
||||
"L173 378",
|
||||
"C117 290 144 173 229 111",
|
||||
"C278 75 337 57 400 57",
|
||||
"C463 57 522 75 571 111",
|
||||
"C656 173 683 290 627 378",
|
||||
"L433 684",
|
||||
"C425 697 414 704 400 704",
|
||||
"Z",
|
||||
].join(" "),
|
||||
);
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
ctx.save();
|
||||
ctx.translate(size * 0.12, size * 0.02);
|
||||
ctx.scale(size / 1000, size / 1000);
|
||||
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.fill(iconPath);
|
||||
|
||||
ctx.globalCompositeOperation = "destination-out";
|
||||
ctx.beginPath();
|
||||
ctx.arc(400, 320, 86, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
|
||||
const texture = new THREE.CanvasTexture(canvas);
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.needsUpdate = true;
|
||||
return texture;
|
||||
}
|
||||
|
||||
function getLandingPointTexture() {
|
||||
if (!landingPointTexture) {
|
||||
landingPointTexture = createLandingPointTexture();
|
||||
}
|
||||
return landingPointTexture;
|
||||
}
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
@@ -49,7 +98,7 @@ function disposeMaterial(material) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (material.map) {
|
||||
if (material.map && !material.userData?.sharedMap) {
|
||||
material.map.dispose();
|
||||
}
|
||||
material.dispose();
|
||||
@@ -69,6 +118,22 @@ function disposeObject(object, parent) {
|
||||
}
|
||||
}
|
||||
|
||||
function setLandingPointMaterialState(point, { color, opacity, emissive, emissiveIntensity }) {
|
||||
point.material.color.set(color);
|
||||
point.material.opacity = opacity;
|
||||
if (point.material.emissive && emissive !== undefined) {
|
||||
point.material.emissive.setHex(emissive);
|
||||
}
|
||||
if ("emissiveIntensity" in point.material && emissiveIntensity !== undefined) {
|
||||
point.material.emissiveIntensity = emissiveIntensity;
|
||||
}
|
||||
}
|
||||
|
||||
function setLandingPointScale(point, heightScale) {
|
||||
const aspect = CABLE_CONFIG.landingPoint.iconAspectRatio;
|
||||
point.scale.set(heightScale * aspect, heightScale, 1);
|
||||
}
|
||||
|
||||
function getCableColor(properties) {
|
||||
if (properties.color) {
|
||||
if (
|
||||
@@ -357,13 +422,6 @@ export async function loadLandingPoints(scene, earthObj, options = {}) {
|
||||
|
||||
clearLandingPoints(earthObj);
|
||||
|
||||
if (!landingPointGeometry) {
|
||||
landingPointGeometry = new THREE.SphereGeometry(
|
||||
CABLE_CONFIG.landingPoint.radius,
|
||||
CABLE_CONFIG.landingPoint.widthSegments,
|
||||
CABLE_CONFIG.landingPoint.heightSegments,
|
||||
);
|
||||
}
|
||||
let validCount = 0;
|
||||
|
||||
for (const feature of data.features) {
|
||||
@@ -396,29 +454,35 @@ export async function loadLandingPoints(scene, earthObj, options = {}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sphere = new THREE.Mesh(
|
||||
landingPointGeometry,
|
||||
new THREE.MeshStandardMaterial({
|
||||
const marker = new THREE.Sprite(
|
||||
new THREE.SpriteMaterial({
|
||||
map: getLandingPointTexture(),
|
||||
color: CABLE_CONFIG.landingPoint.color,
|
||||
emissive: CABLE_CONFIG.landingPoint.emissive,
|
||||
emissiveIntensity: CABLE_CONFIG.landingPoint.emissiveIntensity,
|
||||
transparent: true,
|
||||
opacity: CABLE_CONFIG.landingPoint.opacity,
|
||||
depthTest: true,
|
||||
depthWrite: false,
|
||||
}),
|
||||
);
|
||||
sphere.position.copy(position);
|
||||
sphere.userData = {
|
||||
marker.material.userData.sharedMap = true;
|
||||
marker.renderOrder = CABLE_CONFIG.landingPoint.renderOrder;
|
||||
marker.center.set(
|
||||
CABLE_CONFIG.landingPoint.anchorX,
|
||||
CABLE_CONFIG.landingPoint.anchorY,
|
||||
);
|
||||
marker.position.copy(position);
|
||||
marker.userData = {
|
||||
type: "landingPoint",
|
||||
name: properties.name || "未知登陆站",
|
||||
cableNames: properties.cable_names || [],
|
||||
country: properties.country || "未知国家",
|
||||
status: properties.status || "Unknown",
|
||||
baseScale: CABLE_CONFIG.landingPoint.baseScale,
|
||||
sharedGeometry: true,
|
||||
};
|
||||
setLandingPointScale(marker, CABLE_CONFIG.landingPoint.baseScale);
|
||||
|
||||
earthObj.add(sphere);
|
||||
landingPoints.push(sphere);
|
||||
earthObj.add(marker);
|
||||
landingPoints.push(marker);
|
||||
validCount++;
|
||||
}
|
||||
|
||||
@@ -533,6 +597,18 @@ export function getAllLandingPoints() {
|
||||
return landingPoints;
|
||||
}
|
||||
|
||||
// Hide pins within ~3° of the limb (normalised dot < 0.05) to prevent the
|
||||
// "half-clipped-into-globe" look caused by depthTest clipping the billboard
|
||||
// against closer earth-surface geometry near the horizon.
|
||||
const _FACING_DOT_MIN_SQ = 0.05 * 0.05;
|
||||
|
||||
function isFacingCamera(lp, camera) {
|
||||
lp.getWorldPosition(_lpWorldPos);
|
||||
const d = _lpWorldPos.dot(camera.position);
|
||||
if (d <= 0) return false;
|
||||
return d * d > _FACING_DOT_MIN_SQ * _lpWorldPos.lengthSq() * camera.position.lengthSq();
|
||||
}
|
||||
|
||||
export function applyLandingPointVisualState(lockedCableName, dimAll = false, camera = null) {
|
||||
const pulse =
|
||||
(Math.sin(Date.now() * CABLE_CONFIG.landingPointVisual.pulseSpeed) + 1) * 0.5;
|
||||
@@ -544,58 +620,65 @@ export function applyLandingPointVisualState(lockedCableName, dimAll = false, ca
|
||||
: [];
|
||||
|
||||
landingPoints.forEach((lp) => {
|
||||
lp.visible = cablesVisible && (camera ? isFacingCamera(lp, camera) : true);
|
||||
const isRelated =
|
||||
!dimAll &&
|
||||
Array.isArray(lp.userData.cableNames) &&
|
||||
lp.userData.cableNames.some((name) => relatedNames.includes(name));
|
||||
|
||||
if (isRelated) {
|
||||
lp.material.color.setHex(0xffd27a);
|
||||
lp.material.emissive.setHex(0x7a4a00);
|
||||
lp.material.emissiveIntensity =
|
||||
CABLE_CONFIG.landingPointVisual.related.emissiveIntensityBase +
|
||||
0.2 +
|
||||
pulse * (CABLE_CONFIG.landingPointVisual.related.emissiveIntensityPulse + 0.2);
|
||||
lp.material.opacity =
|
||||
Math.max(
|
||||
setLandingPointMaterialState(lp, {
|
||||
color: 0xffd27a,
|
||||
emissive: 0x7a4a00,
|
||||
emissiveIntensity:
|
||||
CABLE_CONFIG.landingPointVisual.related.emissiveIntensityBase +
|
||||
0.2 +
|
||||
pulse * (CABLE_CONFIG.landingPointVisual.related.emissiveIntensityPulse + 0.2),
|
||||
opacity: Math.max(
|
||||
0.92,
|
||||
CABLE_CONFIG.landingPointVisual.related.opacityBase +
|
||||
pulse * CABLE_CONFIG.landingPointVisual.related.opacityPulse,
|
||||
);
|
||||
),
|
||||
});
|
||||
const distanceScale = getLandingPointDistanceScale(lp, camera);
|
||||
const baseScale = lp.userData?.baseScale || CABLE_CONFIG.landingPoint.baseScale;
|
||||
lp.scale.setScalar(
|
||||
setLandingPointScale(
|
||||
lp,
|
||||
(CABLE_CONFIG.landingPointVisual.related.scaleBase +
|
||||
pulse * CABLE_CONFIG.landingPointVisual.related.scalePulse) *
|
||||
baseScale *
|
||||
distanceScale,
|
||||
distanceScale,
|
||||
);
|
||||
} else {
|
||||
const dimColor = CABLE_CONFIG.landingPointVisual.dimmed.colorRGB;
|
||||
const r = dimColor.r * brightness;
|
||||
const g = dimColor.g * brightness;
|
||||
const b = dimColor.b * brightness;
|
||||
lp.material.color.setRGB(r / 255, g / 255, b / 255);
|
||||
lp.material.emissive.setHex(CABLE_CONFIG.landingPointVisual.dimmed.emissive);
|
||||
lp.material.emissiveIntensity =
|
||||
CABLE_CONFIG.landingPointVisual.dimmed.emissiveIntensity;
|
||||
lp.material.opacity = CABLE_CONFIG.landingPointVisual.dimmed.opacity;
|
||||
setLandingPointMaterialState(lp, {
|
||||
color: new THREE.Color(r / 255, g / 255, b / 255),
|
||||
emissive: CABLE_CONFIG.landingPointVisual.dimmed.emissive,
|
||||
emissiveIntensity: CABLE_CONFIG.landingPointVisual.dimmed.emissiveIntensity,
|
||||
opacity: CABLE_CONFIG.landingPointVisual.dimmed.opacity,
|
||||
});
|
||||
const distanceScale = getLandingPointDistanceScale(lp, camera);
|
||||
const baseScale = lp.userData?.baseScale || CABLE_CONFIG.landingPoint.baseScale;
|
||||
lp.scale.setScalar(baseScale * distanceScale);
|
||||
setLandingPointScale(lp, baseScale * distanceScale);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function resetLandingPointVisualState(camera = null) {
|
||||
landingPoints.forEach((lp) => {
|
||||
lp.material.color.setHex(CABLE_CONFIG.landingPoint.color);
|
||||
lp.material.emissive.setHex(CABLE_CONFIG.landingPoint.emissive);
|
||||
lp.material.emissiveIntensity = CABLE_CONFIG.landingPoint.emissiveIntensity;
|
||||
lp.material.opacity = CABLE_CONFIG.landingPoint.opacity;
|
||||
lp.visible = cablesVisible && (camera ? isFacingCamera(lp, camera) : true);
|
||||
setLandingPointMaterialState(lp, {
|
||||
color: CABLE_CONFIG.landingPoint.color,
|
||||
emissive: CABLE_CONFIG.landingPoint.emissive,
|
||||
emissiveIntensity: CABLE_CONFIG.landingPoint.emissiveIntensity,
|
||||
opacity: CABLE_CONFIG.landingPoint.opacity,
|
||||
});
|
||||
const distanceScale = getLandingPointDistanceScale(lp, camera);
|
||||
const baseScale = lp.userData?.baseScale || CABLE_CONFIG.landingPoint.baseScale;
|
||||
lp.scale.setScalar(baseScale * distanceScale);
|
||||
setLandingPointScale(lp, baseScale * distanceScale);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -201,6 +201,7 @@ export const PATHS = {
|
||||
bgpApi: '/api/v1/visualization/geo/bgp-anomalies',
|
||||
bgpIncidentsApi: '/api/v1/visualization/geo/bgp-incidents',
|
||||
bgpCollectorsApi: '/api/v1/visualization/geo/bgp-collectors',
|
||||
earthSummaryApi: '/api/v1/visualization/geo/summary',
|
||||
earthClientLogsApi: '/api/v1/system/logs/earth-client',
|
||||
};
|
||||
|
||||
@@ -259,15 +260,17 @@ export const CABLE_CONFIG = {
|
||||
renderOrder: 1,
|
||||
},
|
||||
landingPoint: {
|
||||
altitudeOffset: 0.1,
|
||||
radius: 0.4,
|
||||
widthSegments: 16,
|
||||
heightSegments: 16,
|
||||
baseScale: 2.5,
|
||||
altitudeOffset: 0.48,
|
||||
textureSize: 256,
|
||||
iconAspectRatio: 0.82,
|
||||
anchorX: 0.52,
|
||||
anchorY: 0.276,
|
||||
baseScale: 12,
|
||||
color: 0xffaa00,
|
||||
emissive: 0x442200,
|
||||
emissiveIntensity: 0.5,
|
||||
opacity: 1.0,
|
||||
renderOrder: 4.5,
|
||||
},
|
||||
landingPointSizeStabilization: {
|
||||
enabled: true,
|
||||
@@ -277,7 +280,7 @@ export const CABLE_CONFIG = {
|
||||
},
|
||||
landingPointVisual: {
|
||||
pulseSpeed: 0.003,
|
||||
dimBrightness: 0.3,
|
||||
dimBrightness: 0.62,
|
||||
related: {
|
||||
emissiveIntensityBase: 0.5,
|
||||
emissiveIntensityPulse: 0.5,
|
||||
@@ -287,10 +290,10 @@ export const CABLE_CONFIG = {
|
||||
scalePulse: 0.3,
|
||||
},
|
||||
dimmed: {
|
||||
colorRGB: { r: 255, g: 170, b: 0 },
|
||||
emissive: 0x000000,
|
||||
emissiveIntensity: 0,
|
||||
opacity: 0.3,
|
||||
colorRGB: { r: 180, g: 116, b: 28 },
|
||||
emissive: 0x3a2200,
|
||||
emissiveIntensity: 0.18,
|
||||
opacity: 0.78,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
5
frontend/public/earth/js/controls.js
vendored
5
frontend/public/earth/js/controls.js
vendored
@@ -915,7 +915,10 @@ function syncEarthSettingsStateFromRuntime() {
|
||||
const scope = getSettingsViewportScope();
|
||||
|
||||
nextSettings.shared = getCurrentSharedSettingsSnapshot();
|
||||
nextSettings.views[scope].panelVisibility = getCurrentPanelVisibilitySnapshot();
|
||||
// panelVisibility is maintained in earthSettingsState via setHudPanelVisibility.
|
||||
// Do not re-snapshot from DOM here: transient hides (e.g. closeTransientMobileOverlays)
|
||||
// change the DOM without going through setHudPanelVisibility and would corrupt the
|
||||
// user's persisted preference.
|
||||
earthSettingsState = nextSettings;
|
||||
return nextSettings;
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ let calloutConnector = null;
|
||||
let cruiseBGPAdapter = null;
|
||||
let cruiseNewsAdapter = null;
|
||||
let cruiseSequencer = null;
|
||||
let earthStatsSummary = null;
|
||||
let activeDragPointerId = null;
|
||||
let activeTouchPoints = new Map();
|
||||
let pinchGesture = null;
|
||||
@@ -1246,6 +1247,61 @@ function getBGPStatusText(bgpResult) {
|
||||
return "当前无活跃事件";
|
||||
}
|
||||
|
||||
function toCount(value) {
|
||||
const count = Number(value);
|
||||
return Number.isFinite(count) ? count : 0;
|
||||
}
|
||||
|
||||
function formatBGPStatusFromSummary(summary) {
|
||||
if (!summary) return "-";
|
||||
if (summary.bgpIncidentCount > 0) {
|
||||
return `${summary.bgpIncidentCount} 起活跃事件`;
|
||||
}
|
||||
if (summary.bgpAnomalyCount > 0) {
|
||||
return `${summary.bgpAnomalyCount} 条活跃异常`;
|
||||
}
|
||||
return "当前无活跃事件";
|
||||
}
|
||||
|
||||
function applyEarthStatsSummary(summary) {
|
||||
if (!summary) return;
|
||||
updateEarthStats({
|
||||
cableCount: `${summary.cableCount}个`,
|
||||
landingPointCount: `${summary.landingPointCount}个`,
|
||||
satelliteCount: `${summary.satelliteCount} 颗`,
|
||||
computeCenterCount: `${summary.computeCenterCount} 个`,
|
||||
bgpAnomalyCount: `${summary.bgpEventCount} 起`,
|
||||
bgpCollectorCount: `${summary.bgpCollectorCount} 个`,
|
||||
bgpStatusSummary: formatBGPStatusFromSummary(summary),
|
||||
terrainOn: getShowTerrain(),
|
||||
textureQuality: "8K 卫星图",
|
||||
});
|
||||
}
|
||||
|
||||
async function loadEarthStatsSummary() {
|
||||
try {
|
||||
const response = await fetch(PATHS.earthSummaryApi);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Earth summary HTTP ${response.status}`);
|
||||
}
|
||||
const payload = await response.json();
|
||||
const stats = payload?.stats || {};
|
||||
earthStatsSummary = {
|
||||
cableCount: toCount(stats.cable_count),
|
||||
landingPointCount: toCount(stats.landing_point_count),
|
||||
satelliteCount: toCount(stats.satellite_count),
|
||||
computeCenterCount: toCount(stats.compute_center_count),
|
||||
bgpEventCount: toCount(stats.bgp_event_count),
|
||||
bgpIncidentCount: toCount(stats.bgp_incident_count),
|
||||
bgpAnomalyCount: toCount(stats.bgp_anomaly_count),
|
||||
bgpCollectorCount: toCount(stats.bgp_collector_count),
|
||||
};
|
||||
applyEarthStatsSummary(earthStatsSummary);
|
||||
} catch (error) {
|
||||
console.warn("全球态势聚合统计加载失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateComputeCenterHud(computeCenterResult) {
|
||||
const computeBtn = document.getElementById("toggle-compute-centers");
|
||||
if (computeBtn) {
|
||||
@@ -1885,7 +1941,8 @@ function updateSatelliteToggleUi(enabled, satelliteCount = getSatelliteCount())
|
||||
});
|
||||
}
|
||||
|
||||
setEarthStatValue("satellite-count", `${satelliteCount} 颗`);
|
||||
const resolvedCount = satelliteCount || earthStatsSummary?.satelliteCount || 0;
|
||||
setEarthStatValue("satellite-count", `${resolvedCount} 颗`);
|
||||
}
|
||||
|
||||
function updateCableToggleUi(enabled) {
|
||||
@@ -1898,8 +1955,11 @@ function updateCableToggleUi(enabled) {
|
||||
});
|
||||
}
|
||||
|
||||
setEarthStatValue("cable-count", `${getCableLines().length}个`);
|
||||
setEarthStatValue("landing-point-count", `${getLandingPoints().length}个`);
|
||||
const cableCount = getCableLines().length || earthStatsSummary?.cableCount || 0;
|
||||
const landingPointCount =
|
||||
getLandingPoints().length || earthStatsSummary?.landingPointCount || 0;
|
||||
setEarthStatValue("cable-count", `${cableCount}个`);
|
||||
setEarthStatValue("landing-point-count", `${landingPointCount}个`);
|
||||
}
|
||||
|
||||
async function ensureCablesEnabled() {
|
||||
@@ -2015,13 +2075,25 @@ function disableSatellites() {
|
||||
}
|
||||
|
||||
function updateStatsSummary() {
|
||||
const cableCount = getCableLines().length || earthStatsSummary?.cableCount || 0;
|
||||
const landingPointCount =
|
||||
getLandingPoints().length || earthStatsSummary?.landingPointCount || 0;
|
||||
const satelliteCount = getSatelliteCount() || earthStatsSummary?.satelliteCount || 0;
|
||||
const computeCenterCount =
|
||||
getComputeCenterCount() || earthStatsSummary?.computeCenterCount || 0;
|
||||
const bgpEventCount = getBGPCount() || earthStatsSummary?.bgpEventCount || 0;
|
||||
const bgpCollectorCount =
|
||||
getBGPCollectorCount() || earthStatsSummary?.bgpCollectorCount || 0;
|
||||
updateEarthStats({
|
||||
cableCount: getCableLines().length,
|
||||
landingPointCount: getLandingPoints().length,
|
||||
computeCenterCount: `${getComputeCenterCount()} 个`,
|
||||
bgpAnomalyCount: `${getBGPCount()} 条`,
|
||||
bgpCollectorCount: `${getBGPCollectorCount()} 个`,
|
||||
bgpStatusSummary: getBGPStatusSummary(),
|
||||
cableCount: `${cableCount}个`,
|
||||
landingPointCount: `${landingPointCount}个`,
|
||||
satelliteCount: `${satelliteCount} 颗`,
|
||||
computeCenterCount: `${computeCenterCount} 个`,
|
||||
bgpAnomalyCount: `${bgpEventCount} 起`,
|
||||
bgpCollectorCount: `${bgpCollectorCount} 个`,
|
||||
bgpStatusSummary: getBGPCount()
|
||||
? getBGPStatusSummary()
|
||||
: formatBGPStatusFromSummary(earthStatsSummary),
|
||||
terrainOn: getShowTerrain(),
|
||||
textureQuality: "8K 卫星图",
|
||||
});
|
||||
@@ -2269,6 +2341,11 @@ async function loadData() {
|
||||
await yieldFrame(18);
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
|
||||
setLoadingMessage("正在读取全球态势统计...");
|
||||
await loadEarthStatsSummary();
|
||||
if (loadToken !== currentLoadToken) { isDataLoading = false; return; }
|
||||
await yieldFrame(12);
|
||||
|
||||
const errors = [];
|
||||
|
||||
// Step 1 — Earth texture
|
||||
|
||||
@@ -185,14 +185,22 @@ export function updateZoomDisplay(zoomLevel, distance) {
|
||||
|
||||
// Update earth stats
|
||||
export function updateEarthStats(stats) {
|
||||
setEarthStatValue("cable-count", String(stats.cableCount || 0));
|
||||
setEarthStatValue("landing-point-count", String(stats.landingPointCount || 0));
|
||||
setEarthStatValue("compute-center-count", String(stats.computeCenterCount || 0));
|
||||
setEarthStatValue("bgp-anomaly-count", String(stats.bgpAnomalyCount || 0));
|
||||
setEarthStatValue("bgp-collector-count", String(stats.bgpCollectorCount || 0));
|
||||
setEarthStatValue("bgp-status-summary", stats.bgpStatusSummary || "-");
|
||||
setEarthStatValue("terrain-status", stats.terrainOn ? "开启" : "关闭");
|
||||
setEarthStatValue("texture-quality", stats.textureQuality || "8K 卫星图");
|
||||
const has = (key) => Object.prototype.hasOwnProperty.call(stats, key);
|
||||
if (has("cableCount")) setEarthStatValue("cable-count", String(stats.cableCount || 0));
|
||||
if (has("landingPointCount")) {
|
||||
setEarthStatValue("landing-point-count", String(stats.landingPointCount || 0));
|
||||
}
|
||||
if (has("satelliteCount")) setEarthStatValue("satellite-count", String(stats.satelliteCount || 0));
|
||||
if (has("computeCenterCount")) {
|
||||
setEarthStatValue("compute-center-count", String(stats.computeCenterCount || 0));
|
||||
}
|
||||
if (has("bgpAnomalyCount")) setEarthStatValue("bgp-anomaly-count", String(stats.bgpAnomalyCount || 0));
|
||||
if (has("bgpCollectorCount")) {
|
||||
setEarthStatValue("bgp-collector-count", String(stats.bgpCollectorCount || 0));
|
||||
}
|
||||
if (has("bgpStatusSummary")) setEarthStatValue("bgp-status-summary", stats.bgpStatusSummary || "-");
|
||||
if (has("terrainOn")) setEarthStatValue("terrain-status", stats.terrainOn ? "开启" : "关闭");
|
||||
if (has("textureQuality")) setEarthStatValue("texture-quality", stats.textureQuality || "8K 卫星图");
|
||||
}
|
||||
|
||||
// Show/hide loading via status message
|
||||
|
||||
Reference in New Issue
Block a user