refactor(scenes): the director needs no viewer for its camera

Camera-gesture listeners attach to the engine's canvas and the
interaction availability check tolerates a missing viewer, so a director
built on an engine alone places, flies and stops scene cameras.
This commit is contained in:
German Khokhlov committed 2026-10-15 19:49:24 +04:00
1 parent 0b9deddd70
commit c6e1b65c67
2 files changed
+28 -4

No files matched your search

+4 -4
View File
@@ -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 */
+24
View File
@@ -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();
}
});