mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
155 lines
6.9 KiB
JavaScript
155 lines
6.9 KiB
JavaScript
import { createPerimetersCesiumRenderer } from '../../layers/perimeters/render/cesium.js';
|
|
import { createGnssCesiumRenderer } from '../../layers/gnss/render/cesium.js';
|
|
import { createAirQualityCesiumRenderer } from '../../layers/airQuality/render/cesium.js';
|
|
import { createFirmsCesiumRenderer } from '../../layers/firms/render/cesium.js';
|
|
import { createEarthquakesCesiumRenderer } from '../../layers/earthquakes/render/cesium.js';
|
|
import { createLaunchesCesiumRenderer } from '../../layers/launches/render/cesium.js';
|
|
// Which engine draws which layer: the layer renderer registry (plan, "layer
|
|
// renderer interface") and the layer availability API built on it.
|
|
//
|
|
// A renderer factory `(engine, options) => renderer` draws one layer on one
|
|
// engine kind (`render/cesium.js`, `render/navara.js` of a layer). Cesium
|
|
// layers still draw themselves until their render/cesium.js is extracted
|
|
// (the *a tasks): they are registered as CESIUM_BUILTIN. Cesium entries are
|
|
// registered here, statically (main chunk); Navara factories are registered
|
|
// by the Navara mode after its import() (src/app/navaraMode.js).
|
|
//
|
|
// ## Layer availability (stable API, used by phase 4's layer list)
|
|
//
|
|
// import { createLayerAvailability } from './app/layers/renderers.js';
|
|
// const availability = createLayerAvailability(engine.kind);
|
|
// availability.engine // 'cesium' | 'navara'
|
|
// availability.isAvailable(id) // can this engine show layer `id`?
|
|
// availability.available() // [{ id, name }] in catalog order
|
|
// availability.unavailable() // [{ id, name }] the catalog leaves out
|
|
//
|
|
// The object is frozen; available() and unavailable() return fresh arrays.
|
|
// It reads the registry when called, so a Navara factory registered later
|
|
// (after the Navara mode loads) shows up. `name` is the layer's display name
|
|
// (src/app/layers/directory.js). Phase 4 injects it as its `availability`
|
|
// provider (`{ engine, unavailable() }` is the part it reads).
|
|
|
|
import { APPLICATION_LAYER_DIRECTORY } from './directory.js';
|
|
import { createFlightsCesiumRenderer } from '../../layers/flights/render/cesium.js';
|
|
import { createMilitaryCesiumRenderer } from '../../layers/military/render/cesium.js';
|
|
import { createLocalAdsbCesiumRenderer } from '../../layers/localAdsb/render/cesium.js';
|
|
import { createSatellitesCesiumRenderer } from '../../layers/satellites/render/cesium.js';
|
|
import { createVesselsCesiumRenderer } from '../../layers/vessels/render/cesium.js';
|
|
|
|
const ENGINE_KINDS = new Set(['cesium', 'navara']);
|
|
|
|
/** The layer draws itself on Cesium (no separate renderer yet). */
|
|
export const CESIUM_BUILTIN = Object.freeze({ builtin: 'cesium' });
|
|
|
|
const isFactory = (value) =>
|
|
typeof value === 'function' || value === CESIUM_BUILTIN;
|
|
|
|
/** A registry of layer renderers per engine kind. */
|
|
export function createRendererRegistry() {
|
|
const byEngine = new Map();
|
|
const entries = (engineKind) => byEngine.get(engineKind) ?? new Map();
|
|
return {
|
|
/** Adds `{ [layerId]: factory }` for an engine kind; one per layer. */
|
|
register(engineKind, factories) {
|
|
if (typeof engineKind !== 'string' || !engineKind)
|
|
throw new TypeError('registerLayerRenderers needs an engine kind');
|
|
let map = byEngine.get(engineKind);
|
|
if (!map) byEngine.set(engineKind, (map = new Map()));
|
|
for (const [layerId, factory] of Object.entries(factories ?? {})) {
|
|
if (!isFactory(factory))
|
|
throw new TypeError(
|
|
`Layer renderer for ${layerId} on ${engineKind} is not a factory`,
|
|
);
|
|
if (map.has(layerId))
|
|
throw new Error(
|
|
`Layer ${layerId} already has a renderer on ${engineKind}`,
|
|
);
|
|
map.set(layerId, factory);
|
|
}
|
|
},
|
|
/**
|
|
* The renderer of a layer on `engine` (factory(engine, options)), or null
|
|
* when the engine has none or the layer still draws itself (Cesium).
|
|
*/
|
|
rendererFor(layerId, engine, options = {}) {
|
|
const factory = entries(engine?.kind).get(layerId);
|
|
return typeof factory === 'function' ? factory(engine, options) : null;
|
|
},
|
|
layerAvailableOn: (layerId, engineKind) => entries(engineKind).has(layerId),
|
|
availableIds: (engineKind) => [...entries(engineKind).keys()],
|
|
};
|
|
}
|
|
|
|
const defaultRegistry = createRendererRegistry();
|
|
|
|
/** Registers layer renderers on the application's registry. */
|
|
export const registerLayerRenderers = (engineKind, factories) =>
|
|
defaultRegistry.register(engineKind, factories);
|
|
/** The application registry's renderer of a layer on an engine, or null. */
|
|
export const rendererFor = (layerId, engine, options) =>
|
|
defaultRegistry.rendererFor(layerId, engine, options);
|
|
/** Whether the application can show a layer on an engine kind. */
|
|
export const layerAvailableOn = (layerId, engineKind) =>
|
|
defaultRegistry.layerAvailableOn(layerId, engineKind);
|
|
|
|
/** Cesium renderers extracted from their layers (render/cesium.js). */
|
|
export const CESIUM_LAYER_RENDERERS = Object.freeze({
|
|
earthquakes: createEarthquakesCesiumRenderer,
|
|
'air-quality': (_engine, options) => createAirQualityCesiumRenderer(options),
|
|
'gnss-integrity': (_engine, options) => createGnssCesiumRenderer(options),
|
|
'fire-perimeters': (_engine, options) => createPerimetersCesiumRenderer(options),
|
|
'local-firms': createFirmsCesiumRenderer,
|
|
'rocket-launches': createLaunchesCesiumRenderer,
|
|
satellites: createSatellitesCesiumRenderer,
|
|
flights: createFlightsCesiumRenderer,
|
|
military: createMilitaryCesiumRenderer,
|
|
'local-adsb': createLocalAdsbCesiumRenderer,
|
|
'ais-live-vessels': createVesselsCesiumRenderer,
|
|
});
|
|
|
|
// The other application layers still draw themselves on Cesium.
|
|
registerLayerRenderers(
|
|
'cesium',
|
|
Object.fromEntries(
|
|
APPLICATION_LAYER_DIRECTORY.map(({ id }) => [
|
|
id,
|
|
CESIUM_LAYER_RENDERERS[id] ?? CESIUM_BUILTIN,
|
|
]),
|
|
),
|
|
);
|
|
|
|
/**
|
|
* @typedef {object} LayerAvailability
|
|
* @property {'cesium' | 'navara'} engine
|
|
* @property {(layerId: string) => boolean} isAvailable
|
|
* @property {() => { id: string, name: string }[]} available
|
|
* @property {() => { id: string, name: string }[]} unavailable
|
|
*/
|
|
|
|
/**
|
|
* The layers an engine kind can show (stable API; see the module comment).
|
|
* @param {'cesium' | 'navara'} engineKind
|
|
* @param {{ registry?: object, directory?: { id: string, name: string }[] }} [options]
|
|
* Test seams: the registry and the layer directory.
|
|
* @returns {LayerAvailability}
|
|
*/
|
|
export function createLayerAvailability(
|
|
engineKind,
|
|
{ registry = defaultRegistry, directory = APPLICATION_LAYER_DIRECTORY } = {},
|
|
) {
|
|
if (!ENGINE_KINDS.has(engineKind))
|
|
throw new TypeError(`Unknown engine kind for layers: ${engineKind}`);
|
|
const isAvailable = (layerId) =>
|
|
registry.layerAvailableOn(layerId, engineKind);
|
|
const rows = (wanted) =>
|
|
directory
|
|
.filter(({ id }) => isAvailable(id) === wanted)
|
|
.map(({ id, name }) => ({ id, name }));
|
|
return Object.freeze({
|
|
engine: engineKind,
|
|
isAvailable,
|
|
available: () => rows(true),
|
|
unavailable: () => rows(false),
|
|
});
|
|
}
|