This commit is contained in:
@@ -543,6 +543,8 @@ const poiAmbientLabelServiceSpacingPx = 72
|
|||||||
const modelLoadRetryDelaysMs = [300, 900]
|
const modelLoadRetryDelaysMs = [300, 900]
|
||||||
const adjacentPreloadDelayMs = 900
|
const adjacentPreloadDelayMs = 900
|
||||||
const manualAutoSwitchPauseMs = 1500
|
const manualAutoSwitchPauseMs = 1500
|
||||||
|
const autoSwitchExitDistanceRatio = 0.2
|
||||||
|
const autoSwitchExitDistanceMarginRatio = 0.08
|
||||||
const poiMarkerVisualLiftFactor = 0.92
|
const poiMarkerVisualLiftFactor = 0.92
|
||||||
const poiAmbientLabelLiftFactor = 2.1
|
const poiAmbientLabelLiftFactor = 2.1
|
||||||
const poiFocusLabelLiftFactor = 2.72
|
const poiFocusLabelLiftFactor = 2.72
|
||||||
@@ -3275,6 +3277,18 @@ const resetAutoSwitchDistanceTracking = () => {
|
|||||||
autoSwitchStateMachine.reset(activeView.value)
|
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) => {
|
const handleWheelIntent = (event: WheelEvent) => {
|
||||||
if (!controls || activeView.value !== 'overview' || event.deltaY === 0) return
|
if (!controls || activeView.value !== 'overview' || event.deltaY === 0) return
|
||||||
|
|
||||||
@@ -3368,6 +3382,7 @@ const autoSwitchStateMachine = new GuideAutoSwitchStateMachine({
|
|||||||
exitHoldMs: 400,
|
exitHoldMs: 400,
|
||||||
intentTimeoutMs: 2000,
|
intentTimeoutMs: 2000,
|
||||||
reverseToleranceRatio: 0.008,
|
reverseToleranceRatio: 0.008,
|
||||||
|
exitRatio: autoSwitchExitDistanceRatio,
|
||||||
cooldownMs: props.autoSwitchCooldown,
|
cooldownMs: props.autoSwitchCooldown,
|
||||||
canSwitch: canRunAutoSwitch,
|
canSwitch: canRunAutoSwitch,
|
||||||
onSwitchRequested: requestAutoSwitch
|
onSwitchRequested: requestAutoSwitch
|
||||||
@@ -3752,6 +3767,7 @@ const applyIndoorInitialModelTransform = (model: THREE.Object3D) => {
|
|||||||
const resetCamera = () => {
|
const resetCamera = () => {
|
||||||
applyReferenceOverviewCameraState()
|
applyReferenceOverviewCameraState()
|
||||||
if (activeView.value === 'floor' && controls) {
|
if (activeView.value === 'floor' && controls) {
|
||||||
|
ensureFloorAutoExitZoomRange()
|
||||||
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
|
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
|
||||||
}
|
}
|
||||||
refreshPoiVisibilityByDistance()
|
refreshPoiVisibilityByDistance()
|
||||||
@@ -4060,6 +4076,7 @@ const commitPreparedFloorScene = (
|
|||||||
}
|
}
|
||||||
recordCameraSnapshotRestoration(cameraSnapshot, `floor:${expectedFloorId}`)
|
recordCameraSnapshotRestoration(cameraSnapshot, `floor:${expectedFloorId}`)
|
||||||
if (controls) {
|
if (controls) {
|
||||||
|
ensureFloorAutoExitZoomRange()
|
||||||
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
|
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
|
||||||
}
|
}
|
||||||
options.onCameraStable?.()
|
options.onCameraStable?.()
|
||||||
|
|||||||
@@ -168,6 +168,21 @@ const showOverview = async (page: Page, testInfo: TestInfo, name: string) => {
|
|||||||
assertStableTransition(before, after)
|
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 normalizeFloorKey = (value: string) => value.trim().toLowerCase().replace(/[^a-z0-9.-]/g, '')
|
||||||
|
|
||||||
const resolveRequiredFloorId = (floors: FloorReport[], requested: string) => {
|
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 switchFloor(page, testInfo, l1Point5, 'exterior-l1point5')
|
||||||
await showOverview(page, testInfo, 'l1point5-exterior')
|
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