This commit is contained in:
@@ -543,6 +543,8 @@ const poiAmbientLabelServiceSpacingPx = 72
|
||||
const modelLoadRetryDelaysMs = [300, 900]
|
||||
const adjacentPreloadDelayMs = 900
|
||||
const manualAutoSwitchPauseMs = 1500
|
||||
const autoSwitchExitDistanceRatio = 0.2
|
||||
const autoSwitchExitDistanceMarginRatio = 0.08
|
||||
const poiMarkerVisualLiftFactor = 0.92
|
||||
const poiAmbientLabelLiftFactor = 2.1
|
||||
const poiFocusLabelLiftFactor = 2.72
|
||||
@@ -3275,6 +3277,18 @@ const resetAutoSwitchDistanceTracking = () => {
|
||||
autoSwitchStateMachine.reset(activeView.value)
|
||||
}
|
||||
|
||||
const ensureFloorAutoExitZoomRange = () => {
|
||||
if (!controls) return
|
||||
|
||||
const distance = controls.getDistance()
|
||||
if (!Number.isFinite(distance) || distance <= 0) return
|
||||
|
||||
// 楼层退出以当前距离的 120% 为阈值;参考外观相机正好处于原 600 上限时,
|
||||
// 必须预留额外缩小空间,否则切层后无法满足自动返回外观的条件。
|
||||
const requiredMaxDistance = distance * (1 + autoSwitchExitDistanceRatio + autoSwitchExitDistanceMarginRatio)
|
||||
controls.maxDistance = Math.max(controls.maxDistance, requiredMaxDistance)
|
||||
}
|
||||
|
||||
const handleWheelIntent = (event: WheelEvent) => {
|
||||
if (!controls || activeView.value !== 'overview' || event.deltaY === 0) return
|
||||
|
||||
@@ -3368,6 +3382,7 @@ const autoSwitchStateMachine = new GuideAutoSwitchStateMachine({
|
||||
exitHoldMs: 400,
|
||||
intentTimeoutMs: 2000,
|
||||
reverseToleranceRatio: 0.008,
|
||||
exitRatio: autoSwitchExitDistanceRatio,
|
||||
cooldownMs: props.autoSwitchCooldown,
|
||||
canSwitch: canRunAutoSwitch,
|
||||
onSwitchRequested: requestAutoSwitch
|
||||
@@ -3752,6 +3767,7 @@ const applyIndoorInitialModelTransform = (model: THREE.Object3D) => {
|
||||
const resetCamera = () => {
|
||||
applyReferenceOverviewCameraState()
|
||||
if (activeView.value === 'floor' && controls) {
|
||||
ensureFloorAutoExitZoomRange()
|
||||
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
|
||||
}
|
||||
refreshPoiVisibilityByDistance()
|
||||
@@ -4060,6 +4076,7 @@ const commitPreparedFloorScene = (
|
||||
}
|
||||
recordCameraSnapshotRestoration(cameraSnapshot, `floor:${expectedFloorId}`)
|
||||
if (controls) {
|
||||
ensureFloorAutoExitZoomRange()
|
||||
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
|
||||
}
|
||||
options.onCameraStable?.()
|
||||
|
||||
@@ -168,6 +168,21 @@ const showOverview = async (page: Page, testInfo: TestInfo, name: string) => {
|
||||
assertStableTransition(before, after)
|
||||
}
|
||||
|
||||
const exitOverviewWithZoomControl = async (page: Page, testInfo: TestInfo, name: string) => {
|
||||
const before = await getReport(page)
|
||||
await screenshot(page, testInfo, `${name}-before`)
|
||||
|
||||
await page.getByText('−', { exact: true }).click()
|
||||
await expect.poll(async () => (await getReport(page)).activeView, { timeout: 10_000 }).toBe('overview')
|
||||
|
||||
const after = await getReport(page)
|
||||
await screenshot(page, testInfo, `${name}-after`)
|
||||
expect(after.isCameraTweening).toBe(false)
|
||||
expect(after.modelRoot, 'the overview model must stay committed').not.toBeNull()
|
||||
expect(after.modelRoot!.maxError).toBeLessThan(1e-12)
|
||||
expect(after.camera.distance).toBeGreaterThanOrEqual(before.camera.distance * 1.2)
|
||||
}
|
||||
|
||||
const normalizeFloorKey = (value: string) => value.trim().toLowerCase().replace(/[^a-z0-9.-]/g, '')
|
||||
|
||||
const resolveRequiredFloorId = (floors: FloorReport[], requested: string) => {
|
||||
@@ -213,4 +228,8 @@ test('ordinary exterior and floor switches preserve the GLB_METER camera project
|
||||
|
||||
await switchFloor(page, testInfo, l1Point5, 'exterior-l1point5')
|
||||
await showOverview(page, testInfo, 'l1point5-exterior')
|
||||
|
||||
await switchFloor(page, testInfo, l1, 'exterior-l1-auto-exit')
|
||||
await switchFloor(page, testInfo, l2, 'l1-l2-auto-exit')
|
||||
await exitOverviewWithZoomControl(page, testInfo, 'l2-exterior-auto-exit')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user