From 32bb48cc0b65c61072d5931602fbf6e171e7dd98 Mon Sep 17 00:00:00 2001 From: fukunee Date: Sat, 19 Sep 2026 01:18:15 +0800 Subject: [PATCH] Add loading overlay while scenes initialize - Show a spinner overlay that fades out once Cesium globe data is ready, with a 1s minimum and 8s timeout - Expose a ready promise on CesiumGlobe resolved after country and city data load - Remove temporary inspect script --- index.html | 8 ++++++++ scripts/inspect-temp.mjs | 26 -------------------------- src/main.js | 13 +++++++++++++ src/scene/CesiumGlobe.js | 13 +++++++++++++ src/styles.css | 23 +++++++++++++++++++++++ 5 files changed, 57 insertions(+), 26 deletions(-) delete mode 100644 scripts/inspect-temp.mjs diff --git a/index.html b/index.html index aa8aa19..5cb73d5 100644 --- a/index.html +++ b/index.html @@ -63,6 +63,14 @@
拖动旋转 · 滚轮缩放 · 时间轴视图拖拽左右滑动 · 点击选中 · ← → 翻页
+ + + diff --git a/scripts/inspect-temp.mjs b/scripts/inspect-temp.mjs deleted file mode 100644 index 0398fce..0000000 --- a/scripts/inspect-temp.mjs +++ /dev/null @@ -1,26 +0,0 @@ -import puppeteer from 'puppeteer-core'; -const CHROME = 'C:/Program Files/Google/Chrome/Application/chrome.exe'; -const browser = await puppeteer.launch({ executablePath: CHROME, headless: 'new', - args: ['--no-sandbox', '--disable-gpu', '--use-gl=swiftshader', '--enable-unsafe-swiftshader', '--window-size=1440,900'] }); -const page = await browser.newPage(); -await page.setViewport({ width: 1440, height: 900 }); -const errors = []; -page.on('pageerror', (e) => errors.push(e.message)); -page.on('console', (m) => { if (m.type() === 'error') errors.push('console: ' + m.text()); }); -await page.goto('http://localhost:5250/', { waitUntil: 'domcontentloaded', timeout: 60000 }); -await new Promise(r => setTimeout(r, 8000)); -// 还没切到地理视图,Cesium 应该已经创建 -const pre = await page.evaluate(() => { - const g = window.__app.globe; - return { created: !!(g && g.viewer), markers: g && g.markers ? g.markers.length : 0 }; -}); -console.log('启动即创建:', JSON.stringify(pre)); -await page.click('.view-btn[data-view="globe"]'); -await new Promise(r => setTimeout(r, 2000)); -const after = await page.evaluate(() => { - const el = document.getElementById('cesium-container'); - return { visible: el.classList.contains('visible'), visibility: getComputedStyle(el).visibility }; -}); -console.log('切到地理:', JSON.stringify(after)); -console.log('ERRORS', errors.length ? errors.join(' | ') : '(none)'); -await browser.close(); diff --git a/src/main.js b/src/main.js index 004717f..2362535 100644 --- a/src/main.js +++ b/src/main.js @@ -8,3 +8,16 @@ for (const ev of ['copy', 'cut', 'contextmenu']) { // 启动应用 const app = new App(); window.__app = app; // 便于调试 + +// 加载界面:等三个视图初始化完成(最少展示 1 秒,最多等 8 秒)后淡出 +const t0 = Date.now(); +const MIN_DISPLAY = 1000; +Promise.race([ + app.globe.ready, + new Promise((r) => setTimeout(r, 8000)), +]).then(() => { + const wait = Math.max(0, MIN_DISPLAY - (Date.now() - t0)); + setTimeout(() => { + document.getElementById('loading').classList.add('hidden'); + }, wait); +}); diff --git a/src/scene/CesiumGlobe.js b/src/scene/CesiumGlobe.js index 0f87161..39daea9 100644 --- a/src/scene/CesiumGlobe.js +++ b/src/scene/CesiumGlobe.js @@ -69,6 +69,8 @@ export class CesiumGlobe { this.selected = -1; this._created = false; this._visible = false; + this._pendingData = 2; // 国家边界 + 城市数据 + this.ready = new Promise((resolve) => { this._resolveReady = resolve; }); } ensureCreated() { @@ -316,6 +318,8 @@ export class CesiumGlobe { } } catch (err) { console.warn('[CesiumGlobe] 行政区划加载失败:', err); + } finally { + this._dataReady(); } } @@ -362,6 +366,15 @@ export class CesiumGlobe { }, }); } + this._dataReady(); + } + + _dataReady() { + this._pendingData--; + if (this._pendingData <= 0 && this._resolveReady) { + this._resolveReady(); + this._resolveReady = null; + } } setSelected(index) { diff --git a/src/styles.css b/src/styles.css index 5c6127e..5d1280b 100644 --- a/src/styles.css +++ b/src/styles.css @@ -52,6 +52,29 @@ html, body { background: #0c0906; opacity: 0; transition: opacity 0.18s ease; } +/* 加载界面 */ +#loading { + position: fixed; inset: 0; z-index: 1000; + display: flex; align-items: center; justify-content: center; + background: #14100d; + transition: opacity 0.6s ease; +} +#loading.hidden { opacity: 0; pointer-events: none; } +.loading-box { display: flex; flex-direction: column; align-items: center; gap: 18px; } +.spinner { + width: 54px; height: 54px; + border: 3px solid rgba(201, 162, 39, 0.22); + border-top-color: #c9a227; + border-radius: 50%; + animation: spin 0.9s linear infinite; +} +@keyframes spin { to { transform: rotate(360deg); } } +.loading-text { + font-family: var(--serif); + font-size: 14px; letter-spacing: 0.3em; + color: rgba(230, 216, 182, 0.7); +} + /* 顶部标题 */ .hud { position: absolute; z-index: 5; } .top-left { top: 22px; left: 26px; }