release: bump version to 0.32.0
This commit is contained in:
@@ -8,6 +8,25 @@ This project follows the repository versioning rule:
|
||||
- `improvement` -> `+0.0.1`(bugfix + 小功能混合)
|
||||
- `bugfix` -> `+0.0.1`
|
||||
|
||||
## [0.32.0] — 2026-04-22
|
||||
|
||||
### ✨ Highlights
|
||||
- Earth 设置新增“地球默认大小”持久化项,重置视角、缩放百分比重置和 BGP 巡航视图现在统一复用这一份默认 zoom
|
||||
- 卫星焦点层次继续收口:巡航进入 presentation 前不再过早 dim,非焦点卫星改成“降亮度/尾迹/背板”而不是去饱和度
|
||||
|
||||
### 🔧 Improvements
|
||||
- Earth 设置面板区块和左右留白进一步收紧,整体更贴近 HUD 面板的密度
|
||||
- toolbar 展开边界缓存改为按需刷新,减少 document 级 mousemove 期间的重复布局读取
|
||||
- Scrollbar 和 ScrollbarOverlay 收窄 observer 范围,减少大表格和动态菜单下的额外刷新成本
|
||||
- 更新 [earth-frontend-context.md](/home/ray/dev/linkong/planet/docs/technical/earth-frontend-context.md),补充默认视图大小已进入 Earth 设置持久化真源
|
||||
|
||||
### 🐛 Fixes
|
||||
- 修复开启巡航后,尚未进入连线/presentation 时卫星已经整体变暗的问题
|
||||
- 修复默认大小重置链路分散在多个入口、实际 reset/cruise/缩放提示不一致的问题
|
||||
- 修复开启地形后卫星反馈层与地球背面可见性之间的一组表现问题,保留正面反馈同时恢复背面轨道遮挡
|
||||
|
||||
---
|
||||
|
||||
## [0.31.3] — 2026-04-22
|
||||
|
||||
### ✨ Highlights
|
||||
|
||||
@@ -258,6 +258,7 @@ Earth 设置面板当前由 [controls.js](/home/ray/dev/linkong/planet/frontend/
|
||||
当前持久化的范围是:
|
||||
|
||||
- 旋转模式
|
||||
- 地球默认大小(作为重置视角、缩放重置和巡航视图的默认 zoom 真源)
|
||||
- HUD 面板显示/隐藏
|
||||
- 图层控制开关:`地形 / 卫星 / 轨迹 / 海缆 / BGP`
|
||||
- 地形透明度
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
## Current Version
|
||||
|
||||
- `main` 当前主线历史推导到:`0.16.5`
|
||||
- `dev` 当前开发分支历史推导到:`0.31.3`
|
||||
- `dev` 当前开发分支历史推导到:`0.32.0`
|
||||
|
||||
## Timeline
|
||||
|
||||
| Version | Type | Branch | Commit | Summary |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `0.32.0` | feature | `dev` | `pending` | Earth 设置新增默认地球大小真源,并继续收口卫星焦点层次、toolbar/scrollbar 性能与 HUD 设置面板细节 |
|
||||
| `0.31.3` | bugfix | `dev` | `pending` | 收口 Earth 图层注册表与启动任务框架,修复旋转/巡航切换、卫星地形遮挡与日夜关闭照明回归 |
|
||||
| `0.31.2` | bugfix | `dev` | `pending` | 将 Earth 巡航模式拆成通用 sequencer、通用连线和 BGP 巡航适配层,并修复空白点击推进与连线动画回归 |
|
||||
| `0.31.1` | bugfix | `dev` | `pending` | Earth 图层开关统一 loading 状态机,卫星首次加载可见化,并将文档按 technical / plans / deprecated 重构归档 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planet-frontend",
|
||||
"version": "0.31.3",
|
||||
"version": "0.32.0",
|
||||
"private": true,
|
||||
"packageManager": "bun@1",
|
||||
"dependencies": {
|
||||
|
||||
@@ -566,7 +566,8 @@
|
||||
|
||||
.earth-settings-content {
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
padding-inline: 8px;
|
||||
padding-right: 10px;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(160, 186, 216, 0.34) transparent;
|
||||
}
|
||||
@@ -585,11 +586,11 @@
|
||||
}
|
||||
|
||||
.earth-settings-section {
|
||||
padding: 12px 0 20px;
|
||||
padding: 6px 0 10px;
|
||||
}
|
||||
|
||||
.earth-settings-section-title {
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 10px;
|
||||
color: var(--hud-text-soft);
|
||||
font-size: calc(0.62rem * var(--hud-scale));
|
||||
letter-spacing: 0.16em;
|
||||
@@ -599,7 +600,7 @@
|
||||
.earth-settings-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.earth-settings-item {
|
||||
@@ -607,7 +608,7 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 11px 14px;
|
||||
padding: 10px 13px;
|
||||
border-radius: 14px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent),
|
||||
@@ -629,7 +630,7 @@
|
||||
.earth-settings-item--stacked {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
gap: 10px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@@ -644,7 +645,7 @@
|
||||
.earth-settings-slider-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.earth-settings-segmented {
|
||||
@@ -783,7 +784,7 @@
|
||||
.earth-settings-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.earth-settings-item-title {
|
||||
|
||||
@@ -512,6 +512,30 @@
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
<section class="earth-settings-section">
|
||||
<div class="earth-settings-section-title">视图</div>
|
||||
<div class="earth-settings-list">
|
||||
<div class="earth-settings-item earth-settings-item--stacked">
|
||||
<div class="earth-settings-copy">
|
||||
<span class="earth-settings-item-title">地球默认大小</span>
|
||||
<span class="earth-settings-item-subtitle">用于重置视角、缩放重置和巡航视图的默认缩放比例</span>
|
||||
</div>
|
||||
<div class="earth-settings-slider-row">
|
||||
<input
|
||||
id="default-earth-size-slider"
|
||||
class="earth-settings-slider"
|
||||
type="range"
|
||||
min="0.5"
|
||||
max="5"
|
||||
step="0.01"
|
||||
value="1"
|
||||
aria-label="调整地球默认大小"
|
||||
>
|
||||
<span id="default-earth-size-value" class="earth-settings-slider-value">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="earth-settings-section">
|
||||
<div class="earth-settings-section-title">地形</div>
|
||||
<div class="earth-settings-list">
|
||||
|
||||
@@ -169,13 +169,11 @@ export function createBGPCruiseAdapter({
|
||||
cardPlacement = getCardScreenCoords(marker);
|
||||
setMarkerLocked(marker);
|
||||
showMarkerOverlay(marker);
|
||||
applySatelliteHighlights(marker);
|
||||
|
||||
await focusView({
|
||||
lat: marker.userData?.latitude ?? 0,
|
||||
lon: marker.userData?.longitude ?? 0,
|
||||
rotLon: (marker.userData?.longitude ?? 0) - 270,
|
||||
zoom: 1.0,
|
||||
duration: interrupt
|
||||
? Math.round(CRUISE_CONFIG.focusDurationMs * 0.78)
|
||||
: CRUISE_CONFIG.focusDurationMs,
|
||||
@@ -203,6 +201,8 @@ export function createBGPCruiseAdapter({
|
||||
return false;
|
||||
}
|
||||
|
||||
applySatelliteHighlights(marker);
|
||||
|
||||
const connectorDelayCompleted = await context.wait(CRUISE_CONNECTOR_DRAW_MS);
|
||||
if (!connectorDelayCompleted || !context.isCurrent()) {
|
||||
cardPlacement = null;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Scene configuration
|
||||
export const CONFIG = {
|
||||
defaultCameraZ: 300,
|
||||
defaultViewZoom: 1.0,
|
||||
minZoom: 0.5,
|
||||
maxZoom: 5.0,
|
||||
earthRadius: 100,
|
||||
|
||||
158
frontend/public/earth/js/controls.js
vendored
158
frontend/public/earth/js/controls.js
vendored
@@ -44,6 +44,8 @@ export let showTerrain = false;
|
||||
export let layoutExpanded = false;
|
||||
export let rotationMode = ROTATION_MODE.ROTATE;
|
||||
let dayNightEnabled = true;
|
||||
let defaultEarthZoom = CONFIG.defaultViewZoom;
|
||||
let activeCamera = null;
|
||||
|
||||
let earthObj = null;
|
||||
let listeners = [];
|
||||
@@ -73,6 +75,7 @@ const SETTINGS_SHEET_MIN_SCALE = 0.06;
|
||||
const SETTINGS_SHEET_MAX_SCALE_X = 0.22;
|
||||
const SETTINGS_SHEET_MAX_SCALE_Y = 0.18;
|
||||
const EARTH_SETTINGS_STORAGE_KEY = "planet.earth.settings.v1";
|
||||
const DEFAULT_EARTH_ZOOM_STEP = 0.01;
|
||||
let settingsModalTimer = null;
|
||||
let settingsSheetAnimation = null;
|
||||
let terrainToggleToken = 0;
|
||||
@@ -120,6 +123,26 @@ function shouldIncludeLayerInStartupLoad(definition) {
|
||||
return Boolean(definition?.getVisible?.());
|
||||
}
|
||||
|
||||
function clampEarthZoomLevel(nextZoom) {
|
||||
const parsedZoom = Number.parseFloat(nextZoom);
|
||||
if (!Number.isFinite(parsedZoom)) {
|
||||
return CONFIG.defaultViewZoom;
|
||||
}
|
||||
return Math.min(CONFIG.maxZoom, Math.max(CONFIG.minZoom, parsedZoom));
|
||||
}
|
||||
|
||||
function formatZoomPercent(zoom) {
|
||||
return `${Math.round(zoom * 100)}%`;
|
||||
}
|
||||
|
||||
function getZoomResetTooltipText(zoom) {
|
||||
return `重置缩放到${formatZoomPercent(zoom)}`;
|
||||
}
|
||||
|
||||
function getZoomResetStatusMessage(zoom) {
|
||||
return `缩放已重置到${formatZoomPercent(zoom)}`;
|
||||
}
|
||||
|
||||
function canUseLocalStorage() {
|
||||
try {
|
||||
return typeof window !== "undefined" && !!window.localStorage;
|
||||
@@ -145,6 +168,7 @@ function getCurrentSettingsSnapshot() {
|
||||
),
|
||||
terrainOpacity: getTerrainOpacity(),
|
||||
dayNightEnabled,
|
||||
defaultEarthZoom,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -160,6 +184,7 @@ function cloneEarthSettings(settings) {
|
||||
rotationMode: settings.rotationMode,
|
||||
terrainOpacity: settings.terrainOpacity,
|
||||
dayNightEnabled: settings.dayNightEnabled,
|
||||
defaultEarthZoom: settings.defaultEarthZoom,
|
||||
panelVisibility: { ...(settings.panelVisibility || {}) },
|
||||
layerVisibility: { ...(settings.layerVisibility || {}) },
|
||||
};
|
||||
@@ -197,6 +222,9 @@ function normalizeEarthSettings(rawSettings, defaults) {
|
||||
const nextDayNightEnabled = typeof rawSettings?.dayNightEnabled === "boolean"
|
||||
? rawSettings.dayNightEnabled
|
||||
: defaults.dayNightEnabled;
|
||||
const nextDefaultEarthZoom = clampEarthZoomLevel(
|
||||
rawSettings?.defaultEarthZoom ?? defaults.defaultEarthZoom,
|
||||
);
|
||||
|
||||
return {
|
||||
rotationMode: nextRotationMode,
|
||||
@@ -206,6 +234,7 @@ function normalizeEarthSettings(rawSettings, defaults) {
|
||||
? nextTerrainOpacity
|
||||
: defaults.terrainOpacity,
|
||||
dayNightEnabled: nextDayNightEnabled,
|
||||
defaultEarthZoom: nextDefaultEarthZoom,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -251,6 +280,46 @@ function persistEarthSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
function syncDefaultEarthZoomUi(nextZoom) {
|
||||
const slider = document.getElementById("default-earth-size-slider");
|
||||
const value = document.getElementById("default-earth-size-value");
|
||||
const zoomValue = document.getElementById("zoom-value");
|
||||
const tooltipText = getZoomResetTooltipText(nextZoom);
|
||||
|
||||
if (slider instanceof HTMLInputElement) {
|
||||
slider.min = CONFIG.minZoom.toString();
|
||||
slider.max = CONFIG.maxZoom.toString();
|
||||
slider.step = DEFAULT_EARTH_ZOOM_STEP.toString();
|
||||
slider.value = nextZoom.toFixed(2);
|
||||
}
|
||||
if (value) {
|
||||
value.textContent = formatZoomPercent(nextZoom);
|
||||
}
|
||||
if (zoomValue instanceof HTMLElement) {
|
||||
zoomValue.title = tooltipText;
|
||||
const tooltip = zoomValue.querySelector(".tooltip");
|
||||
if (tooltip) {
|
||||
tooltip.textContent = tooltipText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setDefaultEarthZoom(nextZoom, { persist = true, applyToCurrentView = true } = {}) {
|
||||
defaultEarthZoom = clampEarthZoomLevel(nextZoom);
|
||||
syncDefaultEarthZoomUi(defaultEarthZoom);
|
||||
|
||||
if (applyToCurrentView && activeCamera) {
|
||||
zoomLevel = defaultEarthZoom;
|
||||
applyZoom(activeCamera);
|
||||
}
|
||||
|
||||
if (persist) {
|
||||
persistEarthSettings();
|
||||
}
|
||||
|
||||
return defaultEarthZoom;
|
||||
}
|
||||
|
||||
async function applyEarthSettings(settings) {
|
||||
if (!settings) return;
|
||||
|
||||
@@ -277,6 +346,11 @@ async function applyEarthSettings(settings) {
|
||||
applyDayNightEnabled(settings.dayNightEnabled, { persist: false });
|
||||
}
|
||||
|
||||
setDefaultEarthZoom(settings.defaultEarthZoom, {
|
||||
persist: false,
|
||||
applyToCurrentView: true,
|
||||
});
|
||||
|
||||
await applyLayerVisibilitySettings(settings.layerVisibility, {
|
||||
persist: false,
|
||||
silent: true,
|
||||
@@ -660,7 +734,7 @@ export function applyImmediateView(targetEarthObj, camera, options = {}) {
|
||||
const {
|
||||
lat = EARTH_CONFIG.chinaLat,
|
||||
rotLon = EARTH_CONFIG.chinaRotLon,
|
||||
zoom = 1.0,
|
||||
zoom = getDefaultEarthZoomLevel(),
|
||||
} = options;
|
||||
const nextRotation = getViewRotation(lat, rotLon);
|
||||
|
||||
@@ -956,6 +1030,7 @@ function setupSettingsControls() {
|
||||
|
||||
const terrainOpacitySlider = document.getElementById("terrain-opacity-slider");
|
||||
const terrainOpacityValue = document.getElementById("terrain-opacity-value");
|
||||
const defaultEarthSizeSlider = document.getElementById("default-earth-size-slider");
|
||||
const rotationModeButtons = document.querySelectorAll("[data-rotation-mode]");
|
||||
const syncTerrainOpacityUi = (nextOpacity) => {
|
||||
const safeOpacity = Math.round(nextOpacity * 100);
|
||||
@@ -968,6 +1043,7 @@ function setupSettingsControls() {
|
||||
};
|
||||
|
||||
syncTerrainOpacityUi(getTerrainOpacity());
|
||||
syncDefaultEarthZoomUi(defaultEarthZoom);
|
||||
|
||||
if (terrainOpacitySlider instanceof HTMLInputElement) {
|
||||
bindListener(terrainOpacitySlider, "input", (event) => {
|
||||
@@ -982,6 +1058,18 @@ function setupSettingsControls() {
|
||||
});
|
||||
}
|
||||
|
||||
if (defaultEarthSizeSlider instanceof HTMLInputElement) {
|
||||
bindListener(defaultEarthSizeSlider, "input", (event) => {
|
||||
const target = event.currentTarget;
|
||||
if (!(target instanceof HTMLInputElement)) return;
|
||||
const nextZoom = Number.parseFloat(target.value);
|
||||
setDefaultEarthZoom(
|
||||
Number.isFinite(nextZoom) ? nextZoom : defaultEarthZoom,
|
||||
{ persist: true, applyToCurrentView: true },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
rotationModeButtons.forEach((button) => {
|
||||
bindListener(button, "click", (event) => {
|
||||
const target = event.currentTarget;
|
||||
@@ -1303,6 +1391,7 @@ function resetCleanup() {
|
||||
|
||||
export function setupControls(camera, renderer, scene, earth) {
|
||||
resetCleanup();
|
||||
activeCamera = camera;
|
||||
earthObj = earth;
|
||||
setupZoomControls(camera);
|
||||
setupWheelZoom(camera, renderer);
|
||||
@@ -1407,7 +1496,7 @@ function setupZoomControls(camera) {
|
||||
|
||||
bindListener(zoomValue, "click", () => {
|
||||
const startZoomVal = zoomLevel;
|
||||
const targetZoom = 1.0;
|
||||
const targetZoom = getDefaultEarthZoomLevel();
|
||||
const startDistance = CONFIG.defaultCameraZ / startZoomVal;
|
||||
const targetDistance = CONFIG.defaultCameraZ / targetZoom;
|
||||
|
||||
@@ -1424,8 +1513,8 @@ function setupZoomControls(camera) {
|
||||
updateZoomDisplay(zoomLevel, distance.toFixed(0));
|
||||
},
|
||||
() => {
|
||||
zoomLevel = 1.0;
|
||||
showStatusMessage("缩放已重置到100%", "info");
|
||||
zoomLevel = targetZoom;
|
||||
showStatusMessage(getZoomResetStatusMessage(targetZoom), "info");
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1482,6 +1571,7 @@ function animateValue(start, end, duration, onUpdate, onComplete) {
|
||||
|
||||
export function resetView(camera) {
|
||||
if (!earthObj) return;
|
||||
const defaultZoom = getDefaultEarthZoomLevel();
|
||||
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
@@ -1490,7 +1580,7 @@ export function resetView(camera) {
|
||||
lat: pos.coords.latitude,
|
||||
lon: pos.coords.longitude,
|
||||
rotLon: pos.coords.longitude - 270,
|
||||
zoom: 1.0,
|
||||
zoom: defaultZoom,
|
||||
duration: 800,
|
||||
suppressStatus: false,
|
||||
}),
|
||||
@@ -1499,7 +1589,7 @@ export function resetView(camera) {
|
||||
lat: EARTH_CONFIG.chinaLat,
|
||||
lon: EARTH_CONFIG.chinaLon,
|
||||
rotLon: EARTH_CONFIG.chinaRotLon,
|
||||
zoom: 1.0,
|
||||
zoom: defaultZoom,
|
||||
duration: 800,
|
||||
suppressStatus: false,
|
||||
}),
|
||||
@@ -1510,7 +1600,7 @@ export function resetView(camera) {
|
||||
lat: EARTH_CONFIG.chinaLat,
|
||||
lon: EARTH_CONFIG.chinaLon,
|
||||
rotLon: EARTH_CONFIG.chinaRotLon,
|
||||
zoom: 1.0,
|
||||
zoom: defaultZoom,
|
||||
duration: 800,
|
||||
suppressStatus: false,
|
||||
});
|
||||
@@ -1877,6 +1967,8 @@ function setupToolbarHubCluster() {
|
||||
}
|
||||
|
||||
let collapseTimer = null;
|
||||
let expandedToolbarBounds = null;
|
||||
let refreshBoundsFrameId = 0;
|
||||
|
||||
const layoutToolbarOrbs = () => {
|
||||
const orbs = Array.from(cluster.querySelectorAll(".earth-toolbar-orb"));
|
||||
@@ -1942,11 +2034,24 @@ function setupToolbarHubCluster() {
|
||||
orb.style.setProperty("--orb-x", `${x.toFixed(2)}px`);
|
||||
orb.style.setProperty("--orb-y", `${y.toFixed(2)}px`);
|
||||
});
|
||||
|
||||
if (cluster.classList.contains("is-expanded")) {
|
||||
scheduleExpandedToolbarBoundsRefresh();
|
||||
}
|
||||
};
|
||||
|
||||
const setExpanded = (expanded) => {
|
||||
cluster.classList.toggle("is-expanded", expanded);
|
||||
cluster.classList.toggle("is-collapsed", !expanded);
|
||||
if (!expanded) {
|
||||
expandedToolbarBounds = null;
|
||||
if (refreshBoundsFrameId) {
|
||||
cancelAnimationFrame(refreshBoundsFrameId);
|
||||
refreshBoundsFrameId = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
scheduleExpandedToolbarBoundsRefresh();
|
||||
};
|
||||
|
||||
const scheduleCollapse = () => {
|
||||
@@ -1966,6 +2071,10 @@ function setupToolbarHubCluster() {
|
||||
|
||||
cleanupFns.push(() => {
|
||||
if (collapseTimer) clearTimeout(collapseTimer);
|
||||
if (refreshBoundsFrameId) {
|
||||
cancelAnimationFrame(refreshBoundsFrameId);
|
||||
refreshBoundsFrameId = 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Start collapsed — hub acts as the hover target to reveal the arc
|
||||
@@ -2034,9 +2143,23 @@ function setupToolbarHubCluster() {
|
||||
};
|
||||
};
|
||||
|
||||
const scheduleExpandedToolbarBoundsRefresh = () => {
|
||||
if (refreshBoundsFrameId) return;
|
||||
refreshBoundsFrameId = window.requestAnimationFrame(() => {
|
||||
expandedToolbarBounds = collectExpandedToolbarBounds();
|
||||
refreshBoundsFrameId = 0;
|
||||
});
|
||||
};
|
||||
|
||||
bindListener(document, "mousemove", (event) => {
|
||||
if (!cluster.classList.contains("is-expanded")) return;
|
||||
const activeBounds = collectExpandedToolbarBounds();
|
||||
if (
|
||||
event.target instanceof Element &&
|
||||
event.target.closest("#toolbar-cluster, .earth-stack-toolbar")
|
||||
) {
|
||||
scheduleExpandedToolbarBoundsRefresh();
|
||||
}
|
||||
const activeBounds = expandedToolbarBounds;
|
||||
if (!activeBounds) {
|
||||
scheduleCollapse();
|
||||
return;
|
||||
@@ -2052,10 +2175,23 @@ function setupToolbarHubCluster() {
|
||||
scheduleCollapse();
|
||||
}
|
||||
});
|
||||
|
||||
bindListener(cluster, "mouseenter", () => {
|
||||
if (cluster.classList.contains("is-expanded")) {
|
||||
scheduleExpandedToolbarBoundsRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
bindListener(cluster, "focusin", () => {
|
||||
if (cluster.classList.contains("is-expanded")) {
|
||||
scheduleExpandedToolbarBoundsRefresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function teardownControls() {
|
||||
resetCleanup();
|
||||
activeCamera = null;
|
||||
}
|
||||
|
||||
export function getAutoRotate() {
|
||||
@@ -2143,7 +2279,7 @@ export function focusEarthView(camera, options = {}) {
|
||||
lat = EARTH_CONFIG.chinaLat,
|
||||
lon = EARTH_CONFIG.chinaLon,
|
||||
rotLon = lon - 270,
|
||||
zoom = 1.0,
|
||||
zoom = getDefaultEarthZoomLevel(),
|
||||
duration = 800,
|
||||
suppressStatus = true,
|
||||
} = options;
|
||||
@@ -2181,6 +2317,10 @@ export function getZoomLevel() {
|
||||
return zoomLevel;
|
||||
}
|
||||
|
||||
export function getDefaultEarthZoomLevel() {
|
||||
return defaultEarthZoom;
|
||||
}
|
||||
|
||||
export function getShowTerrain() {
|
||||
return showTerrain;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ let satelliteSatrecCache = new Map();
|
||||
const TRAIL_LENGTH = SATELLITE_CONFIG.trailLength;
|
||||
const DOT_TEXTURE_SIZE = 32;
|
||||
const POSITION_UPDATE_INTERVAL_MS = 250;
|
||||
const DIMMED_SATELLITE_BRIGHTNESS = 0.42;
|
||||
const DIMMED_SATELLITE_TRAIL_BRIGHTNESS = 0.24;
|
||||
const DIMMED_SATELLITE_POINT_OPACITY = 0.62;
|
||||
const DIMMED_SATELLITE_BACKDROP_OPACITY = 0.1;
|
||||
|
||||
const scratchWorldSatellitePosition = new THREE.Vector3();
|
||||
const scratchToCamera = new THREE.Vector3();
|
||||
@@ -746,16 +750,16 @@ export function updateSatellitePositions(deltaTime = 0, force = false) {
|
||||
const rule = getSatelliteLegendRule(props);
|
||||
const { r, g, b } = getSatelliteRuleColor(rule);
|
||||
|
||||
if (highlightedSatelliteIndices !== null && !highlightedSatelliteIndices.has(i)) {
|
||||
const lum = r * 0.299 + g * 0.587 + b * 0.114;
|
||||
colors[i * 3] = lum * 0.75 + r * 0.25;
|
||||
colors[i * 3 + 1] = lum * 0.75 + g * 0.25;
|
||||
colors[i * 3 + 2] = lum * 0.75 + b * 0.25;
|
||||
} else {
|
||||
colors[i * 3] = r;
|
||||
colors[i * 3 + 1] = g;
|
||||
colors[i * 3 + 2] = b;
|
||||
}
|
||||
const isNonFocusDimmed =
|
||||
highlightedSatelliteIndices !== null && !highlightedSatelliteIndices.has(i);
|
||||
const pointBrightness = isNonFocusDimmed ? DIMMED_SATELLITE_BRIGHTNESS : 1;
|
||||
const trailBrightness = isNonFocusDimmed
|
||||
? DIMMED_SATELLITE_TRAIL_BRIGHTNESS
|
||||
: 1;
|
||||
|
||||
colors[i * 3] = r * pointBrightness;
|
||||
colors[i * 3 + 1] = g * pointBrightness;
|
||||
colors[i * 3 + 2] = b * pointBrightness;
|
||||
|
||||
const satPosition = satellitePositions[i];
|
||||
for (let j = 0; j < TRAIL_LENGTH; j++) {
|
||||
@@ -771,9 +775,9 @@ export function updateSatellitePositions(deltaTime = 0, force = false) {
|
||||
trailPositions[trailIdx + 1] = trailPoint.y;
|
||||
trailPositions[trailIdx + 2] = trailPoint.z;
|
||||
const alpha = (j + 1) / satPosition.trailCount;
|
||||
trailColors[trailIdx] = r * alpha;
|
||||
trailColors[trailIdx + 1] = g * alpha;
|
||||
trailColors[trailIdx + 2] = b * alpha;
|
||||
trailColors[trailIdx] = r * alpha * trailBrightness;
|
||||
trailColors[trailIdx + 1] = g * alpha * trailBrightness;
|
||||
trailColors[trailIdx + 2] = b * alpha * trailBrightness;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1097,10 +1101,10 @@ export function setSatelliteRingState(index, state, position) {
|
||||
|
||||
function applyDimMaterialState(isDimmed) {
|
||||
if (satellitePoints) {
|
||||
satellitePoints.material.opacity = isDimmed ? 0.32 : 0.9;
|
||||
satellitePoints.material.opacity = isDimmed ? DIMMED_SATELLITE_POINT_OPACITY : 0.9;
|
||||
}
|
||||
if (satelliteBackdropPoints) {
|
||||
satelliteBackdropPoints.material.opacity = isDimmed ? 0.12 : 0.42;
|
||||
satelliteBackdropPoints.material.opacity = isDimmed ? DIMMED_SATELLITE_BACKDROP_OPACITY : 0.42;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,15 @@ export function updateZoomDisplay(zoomLevel, distance) {
|
||||
const slider = getElement("zoom-slider");
|
||||
const cameraDistanceEl = getElement("camera-distance");
|
||||
|
||||
if (zoomValueEl) zoomValueEl.textContent = percent + "%";
|
||||
if (zoomValueEl) {
|
||||
const tooltip = zoomValueEl.querySelector(".tooltip");
|
||||
const label = `${percent}%`;
|
||||
if (zoomValueEl.firstChild?.nodeType === Node.TEXT_NODE) {
|
||||
zoomValueEl.firstChild.nodeValue = label;
|
||||
} else {
|
||||
zoomValueEl.insertBefore(document.createTextNode(label), tooltip || null);
|
||||
}
|
||||
}
|
||||
if (zoomLevelEl) zoomLevelEl.textContent = "缩放: " + percent + "%";
|
||||
if (slider) slider.value = zoomLevel;
|
||||
if (cameraDistanceEl) cameraDistanceEl.textContent = distance + " km";
|
||||
|
||||
@@ -132,13 +132,10 @@ function Scrollbar({
|
||||
resizeObserver.observe(viewport)
|
||||
resizeObserver.observe(trackX)
|
||||
resizeObserver.observe(trackY)
|
||||
Array.from(viewport.children).forEach((child) => resizeObserver.observe(child))
|
||||
|
||||
mutationObserver.observe(viewport, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
characterData: true,
|
||||
})
|
||||
|
||||
viewport.addEventListener('scroll', scheduleUpdate, { passive: true })
|
||||
|
||||
@@ -156,7 +156,6 @@ function ScrollbarOverlay({
|
||||
scheduleUpdate()
|
||||
})
|
||||
resizeObserver.observe(target)
|
||||
Array.from(target.children).forEach((child) => resizeObserver?.observe(child))
|
||||
scheduleUpdate()
|
||||
}
|
||||
|
||||
@@ -169,7 +168,6 @@ function ScrollbarOverlay({
|
||||
mutationObserver.observe(container, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
})
|
||||
|
||||
window.addEventListener('resize', scheduleUpdate)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "planet"
|
||||
version = "0.31.3"
|
||||
version = "0.32.0"
|
||||
description = "智能星球计划 - 态势感知系统"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
|
||||
Reference in New Issue
Block a user