mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
feat(app): construct the globe engine with the viewer
The scene builds the page's Cesium engine right after the viewer (src/app/globeEngine.js), names the startup Google tileset to it once loaded, returns it beside the viewer and destroys it before the viewer. The debug handle exposes it as window.__godsEyeView.engine. Nothing consumes it yet; render holds taken before the governor is installed apply at install. qa-globe-contract now runs on the app's engine (self-built only when the app has none); a throwaway engine checks creation and destroy leave the scene untouched.
This commit is contained in:
1 parent
ab2368f3f3
commit
a5c98c6b07
7 files changed
+141
-2
No files matched your search
@@ -736,6 +736,8 @@
|
||||
"src/globe/cesium/createCesiumEngine.test.mjs",
|
||||
"src/globe/cesium/testing/fakeViewer.mjs",
|
||||
"scripts/qa-globe-contract.mjs",
|
||||
"src/app/globeEngine.js",
|
||||
"src/app/globeEngine.test.mjs",
|
||||
"src/sources/reference.js",
|
||||
"src/sources/reference.test.mjs",
|
||||
"src/search/nominatim.js",
|
||||
|
||||
@@ -1737,6 +1737,20 @@
|
||||
"src/app/layers/traffic.js",
|
||||
"src/app/operations.js",
|
||||
"src/app/scene.js",
|
||||
"src/app/globeEngine.js",
|
||||
"src/globe/contract.js",
|
||||
"src/globe/cesium/createCesiumEngine.js",
|
||||
"src/globe/cesium/camera.js",
|
||||
"src/globe/cesium/convert.js",
|
||||
"src/globe/cesium/credits.js",
|
||||
"src/globe/cesium/events.js",
|
||||
"src/globe/cesium/frames.js",
|
||||
"src/globe/cesium/input.js",
|
||||
"src/globe/cesium/maps.js",
|
||||
"src/globe/cesium/picker.js",
|
||||
"src/globe/cesium/projector.js",
|
||||
"src/globe/cesium/render.js",
|
||||
"src/globe/cesium/surface.js",
|
||||
"src/sources/sourceSlot.js",
|
||||
"src/app/sources.js",
|
||||
"src/app/startupChrome.js",
|
||||
|
||||
@@ -83,6 +83,32 @@ test('startup shares one promise and teardown keeps data alive for controls', as
|
||||
await assert.rejects(app.start(), /destroyed/);
|
||||
});
|
||||
|
||||
test('later components receive the scene engine beside its viewer', async () => {
|
||||
const viewer = { name: 'viewer' };
|
||||
const engine = { kind: 'cesium' };
|
||||
const seen = [];
|
||||
const receive =
|
||||
(phase) =>
|
||||
({ scene }) => {
|
||||
seen.push([phase, scene.viewer, scene.engine]);
|
||||
return { name: phase };
|
||||
};
|
||||
const { app } = fixture({
|
||||
createScene: () => ({ viewer, engine }),
|
||||
createControls: receive('Controls'),
|
||||
createData: receive('Data'),
|
||||
createTools: receive('Tools'),
|
||||
});
|
||||
const components = await app.start();
|
||||
assert.equal(components.scene.engine, engine);
|
||||
assert.deepEqual(seen, [
|
||||
['Controls', viewer, engine],
|
||||
['Data', viewer, engine],
|
||||
['Tools', viewer, engine],
|
||||
]);
|
||||
await app.destroy();
|
||||
});
|
||||
|
||||
for (const phase of phases) {
|
||||
test(`failure during ${phase} releases partially acquired resources`, async () => {
|
||||
const { app, events } = fixture({
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createCesiumEngine } from '../globe/cesium/createCesiumEngine.js';
|
||||
|
||||
/**
|
||||
* Build the page's one globe engine on the application viewer and tie its
|
||||
* teardown to the scene lifetime. Call after the viewer's own cleanup is
|
||||
* deferred, so the engine is destroyed first. Render holds taken before the
|
||||
* render governor is installed apply when it is (src/renderGovernor.js).
|
||||
* @param {Cesium.Viewer} viewer
|
||||
* @param {{
|
||||
* tilesetRef: { current: object | null } | (() => object | null) | null,
|
||||
* defer: (dispose: () => void) => void,
|
||||
* createEngine?: typeof createCesiumEngine,
|
||||
* }} options
|
||||
* @returns {import('../globe/contract.js').GlobeEngine}
|
||||
*/
|
||||
export function createSceneEngine(
|
||||
viewer,
|
||||
{ tilesetRef, defer, createEngine = createCesiumEngine },
|
||||
) {
|
||||
const engine = createEngine(viewer, { tilesetRef });
|
||||
defer(() => engine.destroy());
|
||||
return engine;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createSceneEngine } from './globeEngine.js';
|
||||
import { createCesiumEngine } from '../globe/cesium/createCesiumEngine.js';
|
||||
|
||||
const ROOT = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'..',
|
||||
'..',
|
||||
);
|
||||
const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
||||
|
||||
test('the scene engine is built on the viewer and destroyed by the scene lifetime', () => {
|
||||
const viewer = { name: 'viewer' };
|
||||
const tilesetRef = { current: null };
|
||||
const cleanups = [];
|
||||
const calls = [];
|
||||
const engine = createSceneEngine(viewer, {
|
||||
tilesetRef,
|
||||
defer: (dispose) => cleanups.push(dispose),
|
||||
createEngine(target, options) {
|
||||
calls.push([target, options]);
|
||||
return { kind: 'cesium', destroy: () => calls.push('destroy') };
|
||||
},
|
||||
});
|
||||
assert.equal(engine.kind, 'cesium');
|
||||
assert.equal(calls.length, 1);
|
||||
assert.equal(calls[0][0], viewer);
|
||||
assert.equal(calls[0][1].tilesetRef, tilesetRef);
|
||||
assert.equal(cleanups.length, 1, 'engine teardown is deferred at once');
|
||||
cleanups[0]();
|
||||
assert.equal(calls.at(-1), 'destroy');
|
||||
});
|
||||
|
||||
test('the scene engine defaults to the Cesium engine factory', () => {
|
||||
assert.throws(
|
||||
() => createSceneEngine({}, { tilesetRef: null, defer: () => {} }),
|
||||
/createCesiumEngine needs a viewer/,
|
||||
);
|
||||
assert.equal(typeof createCesiumEngine, 'function');
|
||||
});
|
||||
|
||||
test('the scene constructs the engine with the viewer and returns it beside the viewer', () => {
|
||||
const scene = read('src/app/scene.js');
|
||||
const viewerTeardown = scene.indexOf('uninstallRenderGovernor(viewer);');
|
||||
const engineAt = scene.indexOf('createSceneEngine(viewer, {');
|
||||
assert.ok(viewerTeardown >= 0 && engineAt >= 0);
|
||||
// Cleanups run last-in first-out: the engine goes before the viewer.
|
||||
assert.ok(engineAt > viewerTeardown, 'engine teardown must precede viewer');
|
||||
assert.match(scene, /tilesetRef\.current = tileset;/);
|
||||
assert.match(
|
||||
scene,
|
||||
/return \{ viewer, engine, tileset, mapStackController, operations \};/,
|
||||
);
|
||||
});
|
||||
|
||||
test('the debug handle exposes the engine beside the viewer', () => {
|
||||
const tools = read('src/app/tools.js');
|
||||
assert.match(
|
||||
tools,
|
||||
/const \{ viewer, engine, tileset, mapStackController, operations \} = scene;/,
|
||||
);
|
||||
assert.match(tools, /window\.__godsEyeView = \{\n\s+viewer,\n\s+engine,/);
|
||||
});
|
||||
+7
-1
@@ -14,6 +14,7 @@ import {
|
||||
governorRequestRender,
|
||||
} from '../renderGovernor.js';
|
||||
import { describeError } from './errors.js';
|
||||
import { createSceneEngine } from './globeEngine.js';
|
||||
|
||||
/** Construct the application globe using the caller's local configuration. */
|
||||
export async function createApplicationScene({
|
||||
@@ -56,6 +57,10 @@ export async function createApplicationScene({
|
||||
uninstallRenderGovernor(viewer);
|
||||
if (!viewer.isDestroyed()) viewer.destroy();
|
||||
});
|
||||
// The globe engine over this viewer; Google's startup tileset is named
|
||||
// once it loads.
|
||||
const tilesetRef = { current: null };
|
||||
const engine = createSceneEngine(viewer, { tilesetRef, defer });
|
||||
defer(installTrackpadPinchZoom(viewer));
|
||||
registerDataCredits(viewer, credits);
|
||||
configureCreditKeyboardAccess(document);
|
||||
@@ -69,6 +74,7 @@ export async function createApplicationScene({
|
||||
cesiumToken,
|
||||
});
|
||||
const tileset = photoreal.tileset;
|
||||
tilesetRef.current = tileset;
|
||||
// A provider can finish after cancellation; retain ownership of its result.
|
||||
defer(() => {
|
||||
if (tileset && !tileset.isDestroyed()) {
|
||||
@@ -121,5 +127,5 @@ export async function createApplicationScene({
|
||||
});
|
||||
|
||||
signal.throwIfAborted();
|
||||
return { viewer, tileset, mapStackController, operations };
|
||||
return { viewer, engine, tileset, mapStackController, operations };
|
||||
}
|
||||
+2
-1
@@ -28,7 +28,7 @@ export function createApplicationTools({
|
||||
signal,
|
||||
defer,
|
||||
}) {
|
||||
const { viewer, tileset, mapStackController, operations } = scene;
|
||||
const { viewer, engine, tileset, mapStackController, operations } = scene;
|
||||
const { styleManager, weatherEffects, cockpitCloudEffects } = controls;
|
||||
const { dataManager } = data;
|
||||
const sceneDirector = new SceneDirector(viewer, styleManager, dataManager, {
|
||||
@@ -144,6 +144,7 @@ export function createApplicationTools({
|
||||
|
||||
window.__godsEyeView = {
|
||||
viewer,
|
||||
engine,
|
||||
styleManager,
|
||||
tileset,
|
||||
dataManager,
|
||||
|
||||
Reference in new issue
Block a user