diff --git a/src/scenes/director.js b/src/scenes/director.js index 98a46bf1f..dbe12bcac 100644 --- a/src/scenes/director.js +++ b/src/scenes/director.js @@ -113,7 +113,7 @@ export class SceneDirector { this._interactionTransitions = 0; this._interactions = createSceneInteractions(viewer, { available: () => - !this._destroyed && !this._running && !this.viewer.trackedEntity, + !this._destroyed && !this._running && !this.viewer?.trackedEntity, execute: (action, signal) => this._trackWork(this._executeInteraction(action, signal)), }); @@ -132,12 +132,12 @@ export class SceneDirector { }; this._cameraHandoffUnsubscribe = styleManager.subscribeCameraHandoff?.(yieldCamera); - const canvas = viewer.scene?.canvas; + const canvas = engine?.host.canvas ?? viewer?.scene?.canvas; for (const event of ['pointerdown', 'wheel']) - canvas?.addEventListener(event, yieldCamera, { passive: true }); + canvas?.addEventListener?.(event, yieldCamera, { passive: true }); this._removeCameraInput = () => { for (const event of ['pointerdown', 'wheel']) - canvas?.removeEventListener(event, yieldCamera); + canvas?.removeEventListener?.(event, yieldCamera); }; /** @type {boolean} True while a scene run is in progress */ diff --git a/src/scenes/director.test.mjs b/src/scenes/director.test.mjs index 21799e567..2d2552efd 100644 --- a/src/scenes/director.test.mjs +++ b/src/scenes/director.test.mjs @@ -1597,3 +1597,27 @@ test('camera refusal starts no authored frame or playback clock', async () => { assert.deepEqual(viewer.flights, []); } finally { restore(); } }); + +test('scene placement, flights and stop run on a globe engine without a viewer', async () => { + const restore = installSceneRuntime(); + try { + const engine = createFakeEngine(); + const director = new SceneDirector(null, fakeStyleManager(), fakeDataManager(), { engine }); + const pose = { lat: 27.95, lon: 85.95, alt: 4200, heading: 40, pitch: -25, roll: 0 }; + assert.equal(director._setCameraView(pose), true); + const placed = engine.camera.pose().cartographic; + assert.ok(Math.abs(placed.height - 4200) < 1e-6); + const flying = director._flyCamera({ ...pose, alt: 6000 }, 0.2, { cancelled: false }); + const [flight] = engine.fake.callsOf('camera.flyTo').at(-1).args; + assert.equal(flight.easing, 'cubicInOut'); + engine.fake.frames(20, 16); + await flying; + assert.ok(Math.abs(engine.camera.height() - 6000) < 1e-6); + director.stopScene('test'); + assert.ok(engine.fake.callsOf('camera.cancelFlight').length >= 2); + director.destroy(); + await director._destroyPromise; + } finally { + restore(); + } +});