mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-09 21:02:19 +00:00
Load the layer displays lazily and rebase the main-chunk budget
Every layer display was imported statically from the manifest, so all of them sat in the Cesium-mode main chunk. They are re-exported from one module, src/app/layers/displays.js, which the manifest loads with one import() before the catalog is built, on every engine; rendererFor stays synchronous after that. One chunk beats per-family chunks here: every start loads every display, and split chunks compress worse. CCTV's world click gesture moves out of its display, which the app imported only for it. Tests that build layers without the application await the loads. Keyless, gzip-9: the main chunk falls from 2,113,641 to 2,066,560 bytes, below the 2,090,274 of the merge with main this branch carries. A cold Cesium start loads about 7 KB more JS in total over four requests, with the same time to a ready page. The budget's baseline moves to the new size; it had never absorbed main's own growth.
This commit is contained in:
1 parent
47d63128ff
commit
b53b6a48a7
22 files changed
+239
-114
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"gzipBytes": 2021566,
|
||||
"allowanceBytes": 20216,
|
||||
"measuredAt": "merge of origin/main ac28a11e, keyless build (GOOGLE_MAPS_API_KEY and CESIUM_ION_TOKEN empty), entry index-ChmLBAMR.js, 6 220 779 bytes, gzip level 9; main itself grew 93 873 bytes gzip-9 from the merge base (1 853 283 to 1 947 156)",
|
||||
"gzipBytes": 2066560,
|
||||
"allowanceBytes": 20666,
|
||||
"measuredAt": "HEAD 47d63128 with the layer displays loaded through import() (src/app/layers/displays.js), keyless build (GOOGLE_MAPS_API_KEY and CESIUM_ION_TOKEN empty), entry index-DEjtUM5w.js, 6 322 899 bytes, gzip level 9; HEAD 47d63128 itself measured 2 113 641 and the merge of main 92c8f8d9 2 090 274",
|
||||
"allowance": "1% of the baseline; growth past it fails npm run check:main-chunk until the baseline is raised on purpose"
|
||||
}
|
||||
@@ -3447,6 +3447,7 @@
|
||||
"src/globe/navara/followGestures.js",
|
||||
"src/app/layers/directory.js",
|
||||
"src/app/layers/renderers.js",
|
||||
"src/app/layers/displays.js",
|
||||
"src/layers/aircraft/render/display.js",
|
||||
"src/layers/flights/render/display.js",
|
||||
"src/layers/military/render/display.js",
|
||||
@@ -3551,6 +3552,7 @@
|
||||
"src/layers/cctv/render/cesiumMeshes.js",
|
||||
"src/layers/cctv/render/meshes.js",
|
||||
"src/layers/cctv/render/display.js",
|
||||
"src/layers/cctv/worldClick.js",
|
||||
"src/layers/transit/render/display.js",
|
||||
"src/layers/earthquakes/render/display.js",
|
||||
"src/layers/airQuality/render/display.js",
|
||||
@@ -4229,6 +4231,7 @@
|
||||
"src/globe/cesium/follow.js",
|
||||
"src/app/layers/directory.js",
|
||||
"src/app/layers/renderers.js",
|
||||
"src/app/layers/displays.js",
|
||||
"src/layers/aircraft/render/display.js",
|
||||
"src/data/selectionDispatcher.js",
|
||||
"src/layers/shared/color.js",
|
||||
@@ -4293,6 +4296,7 @@
|
||||
"src/layers/cctv/render/cesiumMeshes.js",
|
||||
"src/layers/cctv/render/meshes.js",
|
||||
"src/layers/cctv/render/display.js",
|
||||
"src/layers/cctv/worldClick.js",
|
||||
"src/layers/transit/render/display.js",
|
||||
"src/layers/earthquakes/render/display.js",
|
||||
"src/layers/airQuality/render/display.js",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { bindCctvWorldClickGesture } from '../../layers/cctv/render/display.js';
|
||||
import { bindCctvWorldClickGesture } from '../../layers/cctv/worldClick.js';
|
||||
import { createCctvLayer } from '../../layers/cctv/index.js';
|
||||
import { rendererFor } from './renderers.js';
|
||||
import * as credits from '../../data/dataCredits.js';
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Every layer's display (render/display.js): one chunk, which the layer
|
||||
// manifest (./renderers.js) loads through import() on every engine kind,
|
||||
// before an engine's catalog is built. Every start loads them all, so they
|
||||
// share one request and one compression context.
|
||||
|
||||
export { createFlightsDisplay } from '../../layers/flights/render/display.js';
|
||||
export { createMilitaryDisplay } from '../../layers/military/render/display.js';
|
||||
export { createLocalAdsbDisplay } from '../../layers/localAdsb/render/display.js';
|
||||
export { createVesselsDisplay } from '../../layers/vessels/render/display.js';
|
||||
export { createSatellitesDisplay } from '../../layers/satellites/render/display.js';
|
||||
export { createLaunchesDisplay } from '../../layers/launches/render/display.js';
|
||||
export { createAlprDisplay } from '../../layers/alpr/render/display.js';
|
||||
export { createBikeshareDisplay } from '../../layers/bikeshare/render/display.js';
|
||||
export { createOsmPlacesDisplay } from '../../layers/osmPlaces/render/display.js';
|
||||
export { createRadioDisplay } from '../../layers/radio/render/display.js';
|
||||
export { createTransitDisplay } from '../../layers/transit/render/display.js';
|
||||
export { createCctvDisplay } from '../../layers/cctv/render/display.js';
|
||||
export { createEarthquakesDisplay } from '../../layers/earthquakes/render/display.js';
|
||||
export { createAirQualityDisplay } from '../../layers/airQuality/render/display.js';
|
||||
export { createPerimetersDisplay } from '../../layers/perimeters/render/display.js';
|
||||
export { createGnssDisplay } from '../../layers/gnss/render/display.js';
|
||||
export { createGhostMapsDisplay } from '../../layers/ghostMaps/render/display.js';
|
||||
export { createDroneAirspaceDisplay } from '../../layers/droneAirspace/render/display.js';
|
||||
export { createCyclonesDisplay } from '../../layers/cyclones/render/display.js';
|
||||
export { createCablesDisplay } from '../../layers/submarineCables/render/display.js';
|
||||
export { createInstallationsDisplay } from '../../layers/installations/render/display.js';
|
||||
export { createAwarenessDisplay } from '../../layers/awareness/render/display.js';
|
||||
export { createInfrastructureDisplay } from '../../layers/infrastructure/render/display.js';
|
||||
export { createStreetLevelDisplay } from '../../layers/streetLevel/render/display.js';
|
||||
export { createTrafficDisplay } from '../../layers/traffic/render/display.js';
|
||||
export { createDirectionsDisplay } from '../../layers/directions/render/display.js';
|
||||
export { createFirmsDisplay } from '../../layers/firms/render/display.js';
|
||||
export { createRecentImageryDisplay } from '../../layers/recentImagery/render/display.js';
|
||||
+89
-82
@@ -6,14 +6,16 @@
|
||||
// One entry per layer of the directory (src/app/layers/directory.js), in
|
||||
// its order, of one of three kinds:
|
||||
//
|
||||
// - `display(factory, needs, backends)`: the layer's render/display.js, the
|
||||
// - `display(name, needs, backends)`: the layer's render/display.js, the
|
||||
// same factory `(engine, options) => renderer` on every engine, drawn
|
||||
// through the contract primitives in `needs` (docs/GLOBE-PRIMITIVES.md).
|
||||
// `backends` is the display's engine-specific option, keyed by engine
|
||||
// kind: an import() loader of `{ option: value }` merged into the
|
||||
// display's options on that engine (CCTV's meshes, Global Context's
|
||||
// pulses on Navara). The displays are static (the main chunk, as before):
|
||||
// the layers build their renderers synchronously.
|
||||
// The factory is the export `name` of ./displays.js, one chunk loaded
|
||||
// through import() on every engine kind, outside the Cesium-mode main
|
||||
// chunk (but for the displays a layer package also imports as its
|
||||
// default); the entry's `display` is its loader. `backends` is the
|
||||
// display's engine-specific option, keyed by engine kind: an import()
|
||||
// loader of `{ option: value }` merged into the display's options on that
|
||||
// engine (CCTV's meshes, Global Context's pulses on Navara).
|
||||
// - `drawsItself(needs)`: no renderer; the layer draws itself through the
|
||||
// contract primitives in `needs` (Wildlife Sightings).
|
||||
// - `perEngine({ [kind]: loader | DRAWS_ITSELF })`: a layer with no display
|
||||
@@ -24,7 +26,8 @@
|
||||
//
|
||||
// Every import() here is resolved by `loadLayerRenderers(kind)`, which the
|
||||
// page awaits before it builds an engine's catalog (src/standalone/
|
||||
// application.js), so a Cesium page fetches none of the Navara ones.
|
||||
// application.js), so a Cesium page fetches its displays and none of the
|
||||
// Navara renderers.
|
||||
// `rendererFor(id, engine, options)` then answers synchronously: the
|
||||
// layer's renderer on that engine, or null when it draws itself or the
|
||||
// engine cannot show it.
|
||||
@@ -47,34 +50,6 @@
|
||||
|
||||
import { ENGINE_KINDS } from '../../globe/contract.js';
|
||||
import { APPLICATION_LAYER_DIRECTORY } from './directory.js';
|
||||
import { createFlightsDisplay } from '../../layers/flights/render/display.js';
|
||||
import { createMilitaryDisplay } from '../../layers/military/render/display.js';
|
||||
import { createLocalAdsbDisplay } from '../../layers/localAdsb/render/display.js';
|
||||
import { createSatellitesDisplay } from '../../layers/satellites/render/display.js';
|
||||
import { createVesselsDisplay } from '../../layers/vessels/render/display.js';
|
||||
import { createLaunchesDisplay } from '../../layers/launches/render/display.js';
|
||||
import { createOsmPlacesDisplay } from '../../layers/osmPlaces/render/display.js';
|
||||
import { createAlprDisplay } from '../../layers/alpr/render/display.js';
|
||||
import { createBikeshareDisplay } from '../../layers/bikeshare/render/display.js';
|
||||
import { createRadioDisplay } from '../../layers/radio/render/display.js';
|
||||
import { createTransitDisplay } from '../../layers/transit/render/display.js';
|
||||
import { createCctvDisplay } from '../../layers/cctv/render/display.js';
|
||||
import { createEarthquakesDisplay } from '../../layers/earthquakes/render/display.js';
|
||||
import { createAirQualityDisplay } from '../../layers/airQuality/render/display.js';
|
||||
import { createGnssDisplay } from '../../layers/gnss/render/display.js';
|
||||
import { createPerimetersDisplay } from '../../layers/perimeters/render/display.js';
|
||||
import { createDroneAirspaceDisplay } from '../../layers/droneAirspace/render/display.js';
|
||||
import { createFirmsDisplay } from '../../layers/firms/render/display.js';
|
||||
import { createGhostMapsDisplay } from '../../layers/ghostMaps/render/display.js';
|
||||
import { createCyclonesDisplay } from '../../layers/cyclones/render/display.js';
|
||||
import { createCablesDisplay } from '../../layers/submarineCables/render/display.js';
|
||||
import { createInfrastructureDisplay } from '../../layers/infrastructure/render/display.js';
|
||||
import { createInstallationsDisplay } from '../../layers/installations/render/display.js';
|
||||
import { createAwarenessDisplay } from '../../layers/awareness/render/display.js';
|
||||
import { createStreetLevelDisplay } from '../../layers/streetLevel/render/display.js';
|
||||
import { createTrafficDisplay } from '../../layers/traffic/render/display.js';
|
||||
import { createDirectionsDisplay } from '../../layers/directions/render/display.js';
|
||||
import { createRecentImageryDisplay } from '../../layers/recentImagery/render/display.js';
|
||||
|
||||
/**
|
||||
* The contract's drawing primitives (docs/GLOBE-PRIMITIVES.md). They are
|
||||
@@ -119,11 +94,16 @@ const checkLoaders = (loaders, allowDrawsItself) => {
|
||||
};
|
||||
|
||||
/** A layer drawn by its display on every engine (see the module comment). */
|
||||
function display(factory, needs, backends = {}) {
|
||||
if (typeof factory !== 'function')
|
||||
throw new TypeError('A layer display is a factory');
|
||||
function display(name, needs, backends = {}) {
|
||||
if (typeof name !== 'string')
|
||||
throw new TypeError('A layer display is named by its export');
|
||||
return Object.freeze({
|
||||
display: factory,
|
||||
display: async () => {
|
||||
const factory = (await displays())[name];
|
||||
if (typeof factory !== 'function')
|
||||
throw new TypeError(`No layer display ${name} in ./displays.js`);
|
||||
return factory;
|
||||
},
|
||||
needs: checkNeeds(needs),
|
||||
backends: checkLoaders(backends, false),
|
||||
});
|
||||
@@ -150,6 +130,9 @@ const navaraWeather = async () => {
|
||||
const navaraOnly = (navara, others = DRAWS_ITSELF) =>
|
||||
perEngine({ cesium: others, navara });
|
||||
|
||||
// The layers' displays (./displays.js), one chunk.
|
||||
const displays = () => import('./displays.js');
|
||||
|
||||
/** How every application layer draws, by id, in directory order. */
|
||||
export const LAYER_MANIFEST = Object.freeze({
|
||||
// The Bhote Koshi event and locator draw themselves on Cesium
|
||||
@@ -166,44 +149,47 @@ export const LAYER_MANIFEST = Object.freeze({
|
||||
drawStorySource(engine, navaraNative(engine), data);
|
||||
}),
|
||||
// The aircraft family.
|
||||
flights: display(createFlightsDisplay, ['movers', 'lines']),
|
||||
military: display(createMilitaryDisplay, ['movers', 'lines']),
|
||||
'local-adsb': display(createLocalAdsbDisplay, ['movers', 'lines']),
|
||||
earthquakes: display(createEarthquakesDisplay, ['ground']),
|
||||
'air-quality': display(createAirQualityDisplay, ['ground']),
|
||||
'fire-perimeters': display(createPerimetersDisplay, ['ground']),
|
||||
'gnss-integrity': display(createGnssDisplay, ['ground']),
|
||||
's2-ghostmaps': display(createGhostMapsDisplay, ['movers', 'ground']),
|
||||
'drone-airspace': display(createDroneAirspaceDisplay, ['ground']),
|
||||
flights: display('createFlightsDisplay', ['movers', 'lines']),
|
||||
military: display('createMilitaryDisplay', ['movers', 'lines']),
|
||||
'local-adsb': display('createLocalAdsbDisplay', ['movers', 'lines']),
|
||||
earthquakes: display('createEarthquakesDisplay', ['ground']),
|
||||
'air-quality': display('createAirQualityDisplay', ['ground']),
|
||||
'fire-perimeters': display('createPerimetersDisplay', ['ground']),
|
||||
'gnss-integrity': display('createGnssDisplay', ['ground']),
|
||||
's2-ghostmaps': display('createGhostMapsDisplay', ['movers', 'ground']),
|
||||
'drone-airspace': display('createDroneAirspaceDisplay', ['ground']),
|
||||
// Draws itself through the globe contract (engine.movers, engine.lines).
|
||||
'wildlife-sightings': drawsItself(['movers', 'lines']),
|
||||
'alpr-cameras': display(createAlprDisplay, ['movers']),
|
||||
'street-level': display(createStreetLevelDisplay, ['movers', 'ground']),
|
||||
satellites: display(createSatellitesDisplay, ['movers', 'lines']),
|
||||
'rocket-launches': display(createLaunchesDisplay, ['movers', 'lines']),
|
||||
traffic: display(createTrafficDisplay, ['movers', 'ground']),
|
||||
'alpr-cameras': display('createAlprDisplay', ['movers']),
|
||||
'street-level': display('createStreetLevelDisplay', ['movers', 'ground']),
|
||||
satellites: display('createSatellitesDisplay', ['movers', 'lines']),
|
||||
'rocket-launches': display('createLaunchesDisplay', ['movers', 'lines']),
|
||||
traffic: display('createTrafficDisplay', ['movers', 'ground']),
|
||||
// CCTV's display, with the Navara backend of its plane and volume
|
||||
// (render/meshes.js).
|
||||
cctv: display(createCctvDisplay, ['movers', 'lines'], {
|
||||
cctv: display('createCctvDisplay', ['movers', 'lines'], {
|
||||
navara: async () => ({
|
||||
navaraMeshes: (await import('../../layers/cctv/render/navaraMeshes.js'))
|
||||
.createCctvNavaraMeshes,
|
||||
}),
|
||||
}),
|
||||
radio: display(createRadioDisplay, ['movers']),
|
||||
transit: display(createTransitDisplay, ['movers', 'lines']),
|
||||
bikeshare: display(createBikeshareDisplay, ['movers']),
|
||||
directions: display(createDirectionsDisplay, ['movers', 'ground']),
|
||||
'recent-imagery': display(createRecentImageryDisplay, ['ground', 'imagery']),
|
||||
'osm-places': display(createOsmPlacesDisplay, ['movers']),
|
||||
'ais-live-vessels': display(createVesselsDisplay, ['movers', 'lines']),
|
||||
'military-installations': display(createInstallationsDisplay, [
|
||||
radio: display('createRadioDisplay', ['movers']),
|
||||
transit: display('createTransitDisplay', ['movers', 'lines']),
|
||||
bikeshare: display('createBikeshareDisplay', ['movers']),
|
||||
directions: display('createDirectionsDisplay', ['movers', 'ground']),
|
||||
'recent-imagery': display('createRecentImageryDisplay', [
|
||||
'ground',
|
||||
'imagery',
|
||||
]),
|
||||
'osm-places': display('createOsmPlacesDisplay', ['movers']),
|
||||
'ais-live-vessels': display('createVesselsDisplay', ['movers', 'lines']),
|
||||
'military-installations': display('createInstallationsDisplay', [
|
||||
'movers',
|
||||
'ground',
|
||||
]),
|
||||
// Global Context's display, with the Navara backend of its range pulses
|
||||
// (render/pulseDisc.js).
|
||||
'military-awareness': display(createAwarenessDisplay, ['lines'], {
|
||||
'military-awareness': display('createAwarenessDisplay', ['lines'], {
|
||||
navara: async () => ({
|
||||
navaraPulses: (
|
||||
await import('../../layers/awareness/render/navaraPulses.js')
|
||||
@@ -220,27 +206,27 @@ export const LAYER_MANIFEST = Object.freeze({
|
||||
'weather-radar': navaraOnly(navaraWeather),
|
||||
'weather-satellite': navaraOnly(navaraWeather),
|
||||
'weather-lightning': navaraOnly(navaraWeather),
|
||||
'weather-cyclones': display(createCyclonesDisplay, ['movers', 'ground']),
|
||||
'weather-cyclones': display('createCyclonesDisplay', ['movers', 'ground']),
|
||||
// The open map overlays drape themselves: Cesium imagery on the viewer,
|
||||
// engine.maps.addOverlay on Navara (src/data/osmOverlays.js).
|
||||
'sea-marks': perEngine({ cesium: DRAWS_ITSELF, navara: DRAWS_ITSELF }),
|
||||
'ski-pistes': perEngine({ cesium: DRAWS_ITSELF, navara: DRAWS_ITSELF }),
|
||||
'local-datacenters': display(createInfrastructureDisplay, [
|
||||
'local-datacenters': display('createInfrastructureDisplay', [
|
||||
'movers',
|
||||
'lines',
|
||||
'ground',
|
||||
]),
|
||||
'local-dams': display(createInfrastructureDisplay, [
|
||||
'local-dams': display('createInfrastructureDisplay', [
|
||||
'movers',
|
||||
'lines',
|
||||
'ground',
|
||||
]),
|
||||
'telegeography-submarine-cables': display(createCablesDisplay, [
|
||||
'telegeography-submarine-cables': display('createCablesDisplay', [
|
||||
'movers',
|
||||
'lines',
|
||||
'ground',
|
||||
]),
|
||||
'local-firms': display(createFirmsDisplay, ['movers', 'ground', 'imagery']),
|
||||
'local-firms': display('createFirmsDisplay', ['movers', 'ground', 'imagery']),
|
||||
});
|
||||
|
||||
/** The manifest entry of a layer, or null. */
|
||||
@@ -257,21 +243,42 @@ const entryAvailableOn = (entry, engineKind) => {
|
||||
return Object.hasOwn(entry.engines, engineKind);
|
||||
};
|
||||
|
||||
/** The import() loader of a layer on an engine kind, or null. */
|
||||
/** The engine-specific import() loader of a layer on an engine kind, or null. */
|
||||
const loaderOf = (entry, engineKind) => {
|
||||
const loader = entry.backends?.[engineKind] ?? entry.engines?.[engineKind];
|
||||
return typeof loader === 'function' ? loader : null;
|
||||
};
|
||||
|
||||
// What loadLayerRenderers resolved: engine kind → layer id → value (the
|
||||
// backend's options, or the engine-specific factory).
|
||||
/** Whether a layer has an import() to load on an engine kind. */
|
||||
const loadsOn = (entry, engineKind) =>
|
||||
entryAvailableOn(entry, engineKind) &&
|
||||
Boolean(entry.display || loaderOf(entry, engineKind));
|
||||
|
||||
/**
|
||||
* What a layer's import()s resolve to on an engine kind: its display with
|
||||
* the backend's options (`{ display, options }`), or the engine-specific
|
||||
* factory.
|
||||
*/
|
||||
const loadEntry = async (entry, engineKind) => {
|
||||
const loader = loaderOf(entry, engineKind);
|
||||
if (!entry.display) return loader();
|
||||
const [factory, options] = await Promise.all([
|
||||
entry.display(),
|
||||
loader ? loader() : {},
|
||||
]);
|
||||
return { display: factory, options };
|
||||
};
|
||||
|
||||
// What loadLayerRenderers resolved: engine kind → layer id → value
|
||||
// (loadEntry's).
|
||||
const loaded = new Map();
|
||||
const loading = new Map();
|
||||
|
||||
/**
|
||||
* Loads every import() the manifest has for `engineKind`, once per page:
|
||||
* concurrent calls share the load, and after a failure the next call loads
|
||||
* what is still missing.
|
||||
* Loads every import() the manifest has for `engineKind` (the displays and
|
||||
* that engine's renderers and backends), once per page: concurrent calls
|
||||
* share the load, and after a failure the next call loads what is still
|
||||
* missing.
|
||||
* @param {string} engineKind One of ENGINE_KINDS.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
@@ -283,8 +290,8 @@ export function loadLayerRenderers(engineKind) {
|
||||
const done = loaded.get(engineKind);
|
||||
const load = Promise.all(
|
||||
Object.entries(LAYER_MANIFEST).map(async ([id, entry]) => {
|
||||
const loader = loaderOf(entry, engineKind);
|
||||
if (loader && !done.has(id)) done.set(id, await loader());
|
||||
if (loadsOn(entry, engineKind) && !done.has(id))
|
||||
done.set(id, await loadEntry(entry, engineKind));
|
||||
}),
|
||||
).then(
|
||||
() => {
|
||||
@@ -338,15 +345,15 @@ export function rendererFor(layerId, engine, options = {}) {
|
||||
const standIn = standIns.get(engineKind)?.get(layerId);
|
||||
if (standIn) return standIn(engine, options);
|
||||
const entry = entryOf(LAYER_MANIFEST, layerId);
|
||||
if (!entryAvailableOn(entry, engineKind)) return null;
|
||||
const loader = loaderOf(entry, engineKind);
|
||||
const value = loader ? loaded.get(engineKind)?.get(layerId) : undefined;
|
||||
if (loader && value === undefined)
|
||||
if (!loadsOn(entry, engineKind)) return null;
|
||||
const value = loaded.get(engineKind)?.get(layerId);
|
||||
if (value === undefined)
|
||||
throw new Error(
|
||||
`Layer ${layerId} on ${engineKind}: its renderer is not loaded (loadLayerRenderers)`,
|
||||
);
|
||||
if (entry.display) return entry.display(engine, { ...options, ...value });
|
||||
return typeof value === 'function' ? value(engine, options) : null;
|
||||
if (entry.display)
|
||||
return value.display(engine, { ...options, ...value.options });
|
||||
return value(engine, options);
|
||||
}
|
||||
|
||||
/** Whether the application can show a layer on an engine kind. */
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
LAYER_MANIFEST,
|
||||
createLayerAvailability,
|
||||
layerAvailableOn,
|
||||
loadLayerRenderers,
|
||||
registerLayerRenderers,
|
||||
rendererFor,
|
||||
} from './renderers.js';
|
||||
@@ -118,6 +119,23 @@ test('the layers drawn through one display, and the ones that draw without one',
|
||||
});
|
||||
});
|
||||
|
||||
test('a display or an engine-specific renderer answers only after its engine loaded them', () => {
|
||||
const engine = createFakeEngine({ kind: 'navara' });
|
||||
// Nothing is loaded yet: the later tests load them.
|
||||
assert.throws(
|
||||
() => rendererFor('weather-radar', engine),
|
||||
/weather-radar on navara: its renderer is not loaded/,
|
||||
);
|
||||
assert.throws(() => rendererFor('cctv', engine), /not loaded/);
|
||||
const cesium = createFakeEngine();
|
||||
assert.throws(
|
||||
() => rendererFor('flights', cesium),
|
||||
/flights on cesium: its renderer is not loaded/,
|
||||
);
|
||||
cesium.destroy();
|
||||
engine.destroy();
|
||||
});
|
||||
|
||||
test('the layers drawn through one display get the same factory on every engine', async () => {
|
||||
const displays = {
|
||||
flights: ['flights', 'createFlightsDisplay'],
|
||||
@@ -164,11 +182,12 @@ test('the layers drawn through one display get the same factory on every engine'
|
||||
const factory = (
|
||||
await import(`../../layers/${directory}/render/display.js`)
|
||||
)[name];
|
||||
assert.equal(LAYER_MANIFEST[id].display, factory, id);
|
||||
assert.equal(await LAYER_MANIFEST[id].display(), factory, id);
|
||||
// Each display's own tests build it with its services; the aircraft
|
||||
// family needs none beyond an atlas.
|
||||
if (!['flights', 'military', 'local-adsb'].includes(id)) continue;
|
||||
for (const kind of ENGINE_KINDS) {
|
||||
await loadLayerRenderers(kind);
|
||||
const engine = createFakeEngine({ kind });
|
||||
const display = rendererFor(id, engine, { drawAtlas });
|
||||
assert.equal(display.engine, engine, `${id} on ${kind}`);
|
||||
@@ -194,17 +213,6 @@ test('a layer that draws itself has no renderer; an unknown engine none either',
|
||||
engine.destroy();
|
||||
});
|
||||
|
||||
test('an engine-specific renderer answers only after its engine loaded them', () => {
|
||||
const engine = createFakeEngine({ kind: 'navara' });
|
||||
// This test file never loads Navara's renderers.
|
||||
assert.throws(
|
||||
() => rendererFor('weather-radar', engine),
|
||||
/weather-radar on navara: its renderer is not loaded/,
|
||||
);
|
||||
assert.throws(() => rendererFor('cctv', engine), /not loaded/);
|
||||
engine.destroy();
|
||||
});
|
||||
|
||||
test('a test engine of its own kind brings its renderers', () => {
|
||||
const made = [];
|
||||
registerLayerRenderers('renderers-test', {
|
||||
|
||||
@@ -1291,6 +1291,11 @@ test('unsupported ALPR coverage suppresses the nearby count and names the extrac
|
||||
import { createGroundFloor } from '../services/groundFloor.js';
|
||||
import { createTerrainHeights } from '../services/terrainHeights.js';
|
||||
import { createApplicationRequestServices } from '../services/requests.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
test('slow ALPR floors share real terrain requests across preparation, render and pans; disable aborts', async () => {
|
||||
const requests = [];
|
||||
|
||||
@@ -10,6 +10,11 @@ import {
|
||||
_setBikeshareSelectionStateForTest,
|
||||
createBikeshareSelectedOverlayEntry,
|
||||
} from './bikeshare.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
function makeRecord() {
|
||||
return {
|
||||
|
||||
@@ -83,6 +83,11 @@ import {
|
||||
IDLE_CAMERA_COLOR,
|
||||
LIVE_CAMERA_COLOR,
|
||||
} from '../layers/cctv/policy.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const ASPECT = 16 / 9;
|
||||
const toRad = (deg) => (deg * Math.PI) / 180;
|
||||
|
||||
@@ -11,6 +11,11 @@ import cctvLayer, {
|
||||
_viewRecordIdsForTest,
|
||||
refreshHorizonCulling,
|
||||
} from './cctv.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const WIDTH = 800;
|
||||
const HEIGHT = 600;
|
||||
|
||||
@@ -20,6 +20,11 @@ import {
|
||||
installRenderGovernor,
|
||||
_resetRenderGovernorForTest,
|
||||
} from '../renderGovernor.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const FULL_RAW = {
|
||||
id: 'us7000abcd',
|
||||
|
||||
@@ -18,6 +18,11 @@ import { getLocale, setLocale } from '../i18n/index.js';
|
||||
import { reportMeshFloorCell, setMeshFloorPreferred } from './groundFloor.js';
|
||||
import { createCesiumMoversEngine } from '../testSupport/cesiumMoversEngine.mjs';
|
||||
import { createFakeEventHandlers } from '../globe/cesium/testing/fakeViewer.mjs';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const NOW = Date.UTC(2026, 6, 17, 4, 0);
|
||||
const H = 3600000;
|
||||
|
||||
@@ -26,6 +26,11 @@ import {
|
||||
import * as Cesium from 'cesium';
|
||||
import { getContextStore, registerEntityContext, selectEntityContext, getSelectedEntityContext, clearSelectedEntityContextForLayer } from './contextStore.js';
|
||||
import { createFakeEngine } from '../globe/testing/fakeEngine.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const LAYER_ID = 'military-installations';
|
||||
|
||||
|
||||
@@ -53,6 +53,11 @@ import {
|
||||
} from './radio.js';
|
||||
import { radioStationRow, withRadioLayer } from '../testSupport/radioLayerHarness.mjs';
|
||||
import { radioSelectedMarker, radioTestEngine } from '../testSupport/radioTestEngine.mjs';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const stations = [
|
||||
{ id: 'news', tags: ['News', 'Weather Radio', 'air traffic'] },
|
||||
|
||||
@@ -5,6 +5,11 @@ import { radioLayer } from './radio.js';
|
||||
import { setLocale } from '../i18n/index.js';
|
||||
import { renderRadioState } from '../ui/radioPresentation.js';
|
||||
import { radioStationRow, withRadioLayer } from '../testSupport/radioLayerHarness.mjs';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const READY = 'Ready — playback starts only from your action';
|
||||
const ids = [1, 2, 3].map((n) => `00000000-0000-4000-8000-00000000009${n}`);
|
||||
|
||||
@@ -20,6 +20,11 @@ import {
|
||||
import { RADIO_REJECTED_STATION_COUNT_MAX as SERVER_REJECTED_MAX } from '../../server/providers/radio/constants.js';
|
||||
import { RADIO_REJECTED_STATION_COUNT_MAX as CLIENT_REJECTED_MAX } from '../layers/radio/policy.js';
|
||||
import { radioTestEngine } from '../testSupport/radioTestEngine.mjs';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const UUID = '12345678-1234-4234-8234-123456789abc';
|
||||
const publicLookup = async () => [{ address: '93.184.216.34', family: 4 }];
|
||||
|
||||
@@ -66,6 +66,11 @@ import {
|
||||
satelliteCatalogModeChanged,
|
||||
scoreSatelliteNameMatch,
|
||||
} from './satellites.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const NOW = new Date('2026-07-27T00:00:00Z');
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ import {
|
||||
import satellitesLayer from './satellites.js';
|
||||
import { createTrackedOverlayEntry } from './trackedReadout.js';
|
||||
import { createFakeEngine } from '../globe/testing/fakeEngine.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const L1 =
|
||||
'1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927';
|
||||
|
||||
@@ -9,6 +9,11 @@ import {
|
||||
} from './satellites.js';
|
||||
import { setLocale } from '../i18n/index.js';
|
||||
import { createFakeEngine } from '../globe/testing/fakeEngine.js';
|
||||
import { loadLayerRenderers } from '../app/layers/renderers.js';
|
||||
|
||||
// The layers draw with the manifest's displays, which load through
|
||||
// import() (src/app/layers/renderers.js).
|
||||
await loadLayerRenderers('cesium');
|
||||
|
||||
const L1 =
|
||||
'1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927';
|
||||
|
||||
@@ -181,6 +181,10 @@ test('traffic timing pairs real ordering to the scheduling change and guards re-
|
||||
}],
|
||||
});
|
||||
const traffic = await server.ssrLoadModule('/src/data/traffic.js');
|
||||
// The layer draws with the manifest's display, which loads through
|
||||
// import() (src/app/layers/renderers.js), in this server's module graph.
|
||||
const renderers = await server.ssrLoadModule('/src/app/layers/renderers.js');
|
||||
await renderers.loadLayerRenderers('cesium');
|
||||
trafficLayer = traffic.default;
|
||||
|
||||
globalThis.document = { documentElement: { dataset: {} } };
|
||||
|
||||
@@ -15,12 +15,9 @@
|
||||
// choices (../rendering.js, ./style.js).
|
||||
|
||||
import * as geo from '../../../geo/index.js';
|
||||
import {
|
||||
bindTrackingClickGesture,
|
||||
isTrackingClickGesture,
|
||||
} from '../../../data/trackingClickGesture.js';
|
||||
import { GIZMO_ID_PREFIX } from '../../../data/cctvGizmo.js';
|
||||
import { CAMERA_ICON, IDLE_CAMERA_COLOR } from '../policy.js';
|
||||
import { bindCctvWorldClickGesture } from '../worldClick.js';
|
||||
import { createCctvMeshes } from './meshes.js';
|
||||
import {
|
||||
COVERAGE_DASH,
|
||||
@@ -87,18 +84,6 @@ export function planeOutline(shape, positions, orientation) {
|
||||
return [tl, corner(1, 1), corner(1, -1), corner(-1, -1), tl];
|
||||
}
|
||||
|
||||
/** The tracking click gesture over engine.input (the CCTV world click). */
|
||||
export function bindCctvWorldClickGesture(handler, onClick, options = {}) {
|
||||
bindTrackingClickGesture(
|
||||
handler,
|
||||
(click, gesture) => {
|
||||
if (!isTrackingClickGesture(gesture)) return;
|
||||
onClick(click);
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('../../../globe/contract.js').GlobeEngine} engine
|
||||
* @param {{ state: object, services: object, navaraMeshes?: Function }} options
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// The CCTV world click: a tracking click over engine.input, shared by the
|
||||
// display (render/display.js) and the application layer.
|
||||
|
||||
import {
|
||||
bindTrackingClickGesture,
|
||||
isTrackingClickGesture,
|
||||
} from '../../data/trackingClickGesture.js';
|
||||
|
||||
/** The tracking click gesture over engine.input (the CCTV world click). */
|
||||
export function bindCctvWorldClickGesture(handler, onClick, options = {}) {
|
||||
bindTrackingClickGesture(
|
||||
handler,
|
||||
(click, gesture) => {
|
||||
if (!isTrackingClickGesture(gesture)) return;
|
||||
onClick(click);
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user