/** * 极点探针:实测把相机拖到南北极点附近时,相机到底发生了什么。 * * 只读诊断,不改产品代码:用 dev 把手读状态,用真实鼠标事件驱动, * 采样相机的位置/朝向/中心,判断异常是「中心翻到另一侧」「朝向乱转」还是「引擎报错」。 * * 运行(需先起 `yarn dev`):node .scratch/cockpit-shell-panel-layout/verify/t03-pole-probe.mjs */ import { join } from 'node:path' import { tmpdir } from 'node:os' const BASE = process.env.COCKPIT_BASE || 'http://localhost:8000' const CHROME = process.env.CHROME_PATH || 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' const PUPPETEER = 'file:///C:/Users/ASUS/.dsh/profiles/desktop/node_modules/puppeteer-core/lib/puppeteer/puppeteer-core.js' const puppeteer = (await import(PUPPETEER)).default const browser = await puppeteer.launch({ executablePath: CHROME, headless: true, userDataDir: join(tmpdir(), 'cockpit-t03-pole-profile'), defaultViewport: { width: 1680, height: 950 }, args: ['--no-sandbox', '--disable-dev-shm-usage', '--no-first-run'], }) const sleep = (ms) => new Promise((r) => setTimeout(r, ms)) try { const page = await browser.newPage() const errors = [] page.on('pageerror', (e) => errors.push(String((e && e.message) || e))) await page.goto(`${BASE}/#/cockpit`, { waitUntil: 'networkidle2', timeout: 60000 }) await page.waitForSelector('.cockpit-shell', { timeout: 20000 }) await page.waitForFunction(() => !!window.__cockpitMap, { timeout: 30000 }).catch(() => {}) await page .waitForFunction( () => document.querySelector('.cockpit-shell__map .map-canvas')?.dataset.mapEngine === 'ready', { timeout: 60000 }, ) .catch(() => {}) await sleep(1000) // 把中心放到极点上(正上方俯视),这是最容易触发奇点的位形。 const readState = () => page.evaluate(() => { const s = window.__cockpitMap.getCameraState() const host = document.querySelector('.cockpit-shell__map .map-canvas') return { pivot: s.pivot, shownPivot: s.shownPivot, hpr: s.hpr, shownHpr: s.shownHpr, settled: s.settled, data: host ? host.dataset.camera : '', } }) const canvasCenter = await page.evaluate(() => { const c = document.querySelector('.cockpit-shell__map .map-canvas') const b = c.getBoundingClientRect() return { x: b.x + b.width / 2, y: b.y + b.height / 2 } }) console.log('== 初始 ==') console.log(JSON.stringify(await readState())) // 直接飞到北极上空附近(避免拖上千像素),再贴近观察。 for (const [name, point] of [ ['北极附近', { lon: 0, lat: 89.5, height: 0 }], ['南极附近', { lon: 0, lat: -89.5, height: 0 }], ]) { console.log(`\n== 飞到 ${name} ==`) await page.evaluate((p) => window.__cockpitMap.setCameraFocus(p), point) await sleep(1500) const at = await readState() console.log(JSON.stringify({ pivot: at.pivot, hpr: at.hpr, settled: at.settled })) // 在极点附近继续往极点方向拖(正是维护者遇到的操作)。 await page.mouse.move(canvasCenter.x, canvasCenter.y) await page.mouse.down({ button: 'left' }) for (let i = 1; i <= 12; i += 1) { await page.mouse.move(canvasCenter.x, canvasCenter.y - i * 40, { steps: 2 }) await sleep(25) const s = await readState() console.log( ` 拖 ${i}: pivot=${s.pivot ? `${s.pivot.lon.toFixed(3)},${s.pivot.lat.toFixed(3)}` : 'null'}` + ` h=${s.hpr.heading.toFixed(1)} p=${s.hpr.pitch.toFixed(1)} r=${Math.round(s.hpr.range)}` + ` | shown=${s.shownPivot ? `${s.shownPivot.lon.toFixed(3)},${s.shownPivot.lat.toFixed(3)}` : 'null'}` + ` settled=${s.settled}`, ) } await page.mouse.up({ button: 'left' }) await sleep(1200) const after = await readState() console.log(` 松手后: pivot=${after.pivot.lon.toFixed(4)},${after.pivot.lat.toFixed(4)} r=${Math.round(after.hpr.range)}`) } console.log(`\n== 页面报错 ==\n${errors.length ? errors.slice(0, 5).join('\n') : '(无)'}`) } finally { await browser.close() }