mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
Traffic roads come from OpenFreeMap vector tiles, or TomTom flow tiles with a key (Hybrid by default). Military areas use OpenFreeMap polygons with a bundled worldwide name index; wide views show named points. ALPR reads an hourly OpenStreetMap extract. Cockpit place context and country, state and US county outlines use bundled Natural Earth and US Census data. Overpass is used only when an operator configures their own endpoint. Also: camera arrivals no longer land below ground, keyless terrain retries on 429, bounded relation geometry for configured Overpass, one shared OpenStreetMap credit, and separate tile and API transports for embedders. Co-authored-by: theGaryLarson <[email protected]> Co-authored-by: Milan Khanal <[email protected]>
209 lines
7.6 KiB
JavaScript
209 lines
7.6 KiB
JavaScript
import { createWeatherClock } from '../layers/weather/clock.js';
|
|
import { createWeatherLayer } from '../layers/weather/index.js';
|
|
import { createCyclonesLayer } from '../layers/cyclones/index.js';
|
|
import { createWindLayer } from '../layers/wind/index.js';
|
|
import { createLayerCatalog } from './catalog.js';
|
|
import { LAYER_STATE_REGISTRY } from '../data/layerState.js';
|
|
import { createMilitaryRegistry } from '../layers/aircraft/classification.js';
|
|
import { createApplicationFlights } from './layers/flights.js';
|
|
import { createApplicationMilitary } from './layers/militaryFlights.js';
|
|
import { createApplicationVessels } from './layers/aisLiveVessels.js';
|
|
import { createApplicationCctv } from './layers/cctv.js';
|
|
import { createApplicationRadio } from './layers/radio.js';
|
|
import { createApplicationTraffic } from './layers/traffic.js';
|
|
import { createApplicationBikeshare } from './layers/bikeshare.js';
|
|
import { createApplicationDirections } from './layers/directions.js';
|
|
import { createApplicationRecentImagery } from './layers/recentImagery.js';
|
|
import { createApplicationTransit } from './layers/transit.js';
|
|
import { createApplicationInstallations } from './layers/militaryInstallations.js';
|
|
import { createApplicationSatellites } from './layers/satellites.js';
|
|
import { createApplicationLaunches } from './layers/rocketLaunches.js';
|
|
import { createApplicationAlpr } from './layers/alprCameras.js';
|
|
import { createApplicationLocalAdsb } from './layers/localAdsb.js';
|
|
import { createApplicationAwareness } from './layers/militaryAwareness.js';
|
|
import { createApplicationFirms } from './layers/firms.js';
|
|
import { createApplicationEarthquakes } from './layers/earthquakes.js';
|
|
import { createApplicationFirePerimeters } from './layers/perimeters.js';
|
|
import { createApplicationCables } from './layers/submarineCables.js';
|
|
import { createInfrastructureLayers } from '../data/infrastructure.js';
|
|
import { localGeoJsonServices } from './localGeojsonServices.js';
|
|
import { createBhoteKoshiEventLayer } from '../data/bhoteKoshiEvent.js';
|
|
import { createBhoteKoshiLocatorLayer } from '../data/bhoteKoshiLocator.js';
|
|
|
|
const SOURCE_METHODS = Object.freeze({
|
|
flights: ['getSnapshot'],
|
|
military: ['getSnapshot'],
|
|
vessels: ['getSnapshot'],
|
|
cctv: ['getCatalog', 'getHealth', 'getFrameUrl', 'getMediaUrl'],
|
|
radio: ['getDirectory', 'recordClick'],
|
|
traffic: [
|
|
'requestRoads',
|
|
'getStatus',
|
|
'fetchFlowForBounds',
|
|
'getFlowSessionStats',
|
|
'resetFlowTileCache',
|
|
],
|
|
bikeshare: ['getStations'],
|
|
installations: ['getMappedSites', 'searchNearby'],
|
|
satellites: ['readGroup'],
|
|
launches: ['getLaunches', 'getActiveTle'],
|
|
alpr: ['fetch'],
|
|
firms: ['getSnapshot'],
|
|
wind: ['getSnapshot'],
|
|
weather: ['getSnapshot'],
|
|
cyclones: ['getSnapshot'],
|
|
earthquakes: ['getSnapshot'],
|
|
'fire-perimeters': ['getSnapshot'],
|
|
cables: ['fetch'],
|
|
});
|
|
|
|
/**
|
|
* Hardware-local layers are registered like any other but never enter share
|
|
* links or stored layer state: another browser cannot have this receiver.
|
|
*/
|
|
export const LOCAL_ONLY_LAYER_METADATA = Object.freeze([
|
|
Object.freeze({ id: 'local-adsb', disposition: 'local-only' }),
|
|
]);
|
|
|
|
/** Serialization metadata for every layer the application catalog constructs. */
|
|
export const APPLICATION_LAYER_METADATA = Object.freeze([
|
|
...LAYER_STATE_REGISTRY,
|
|
...LOCAL_ONLY_LAYER_METADATA,
|
|
]);
|
|
|
|
/** Construct the current catalog without choosing any source provider.
|
|
* Scene engines remain page-owned; layers and classification have this app's lifetime.
|
|
* The manager owns layer destruction, while abort releases classification even if startup fails.
|
|
*/
|
|
export function createApplicationCatalog({
|
|
surface,
|
|
sources,
|
|
signal,
|
|
metadata = APPLICATION_LAYER_METADATA,
|
|
vesselOptions,
|
|
resolveAsset,
|
|
nepalBoundaryResolver,
|
|
}) {
|
|
if (!signal?.addEventListener)
|
|
throw new TypeError('An application lifetime signal is required');
|
|
signal.throwIfAborted();
|
|
if (!surface?.groundFloor || !surface?.terrain)
|
|
throw new TypeError('Application surface services are required');
|
|
|
|
for (const [name, methods] of Object.entries(SOURCE_METHODS)) {
|
|
if (
|
|
methods.some((method) => typeof sources?.[name]?.[method] !== 'function')
|
|
)
|
|
throw new TypeError(`Invalid catalog source: ${name}`);
|
|
}
|
|
const militaryRegistry = createMilitaryRegistry();
|
|
const weatherClock = createWeatherClock();
|
|
const dispose = () => {
|
|
signal.removeEventListener('abort', dispose);
|
|
militaryRegistry.dispose();
|
|
weatherClock.destroy();
|
|
};
|
|
signal.addEventListener('abort', dispose, { once: true });
|
|
try {
|
|
militaryRegistry.configureSource(sources.military, { signal });
|
|
const flights = createApplicationFlights({
|
|
surface,
|
|
source: sources.flights,
|
|
militaryRegistry,
|
|
resolveAsset,
|
|
});
|
|
const military = createApplicationMilitary({
|
|
surface,
|
|
source: sources.military,
|
|
militaryRegistry,
|
|
resolveAsset,
|
|
});
|
|
const vessels = createApplicationVessels({
|
|
source: sources.vessels,
|
|
options: vesselOptions,
|
|
});
|
|
const installations = createApplicationInstallations({
|
|
surface,
|
|
source: sources.installations,
|
|
});
|
|
const satellites = createApplicationSatellites({
|
|
source: sources.satellites,
|
|
});
|
|
const catalog = createLayerCatalog(
|
|
[
|
|
createBhoteKoshiEventLayer(),
|
|
createBhoteKoshiLocatorLayer({
|
|
boundaryResolver: nepalBoundaryResolver,
|
|
}),
|
|
flights,
|
|
military,
|
|
createApplicationLocalAdsb({
|
|
surface,
|
|
enrichment: sources.flights,
|
|
displayParams: () => flights.getParams(),
|
|
...(resolveAsset ? { resolveAsset } : {}),
|
|
}),
|
|
createApplicationEarthquakes({ source: sources.earthquakes }),
|
|
createApplicationFirePerimeters({
|
|
source: sources['fire-perimeters'],
|
|
}),
|
|
createApplicationAlpr({ surface, source: sources.alpr }),
|
|
satellites,
|
|
createApplicationLaunches({ source: sources.launches, satellites }),
|
|
createApplicationTraffic({ source: sources.traffic, surface }),
|
|
createApplicationCctv({ surface, source: sources.cctv }),
|
|
createApplicationRadio({ surface, source: sources.radio }),
|
|
createApplicationTransit({ surface, source: sources.transit }),
|
|
createApplicationBikeshare({ source: sources.bikeshare }),
|
|
createApplicationDirections(),
|
|
createApplicationRecentImagery(),
|
|
vessels,
|
|
installations,
|
|
createApplicationAwareness({
|
|
flights,
|
|
military,
|
|
vessels,
|
|
installations,
|
|
}),
|
|
createWindLayer({ feed: sources.wind, clock: weatherClock }),
|
|
createWeatherLayer({
|
|
feed: sources.weather,
|
|
id: 'weather-radar',
|
|
clock: weatherClock,
|
|
}),
|
|
createWeatherLayer({
|
|
feed: sources.weather,
|
|
id: 'weather-satellite',
|
|
clock: weatherClock,
|
|
}),
|
|
createWeatherLayer({
|
|
feed: sources.weather,
|
|
id: 'weather-lightning',
|
|
clock: weatherClock,
|
|
}),
|
|
createCyclonesLayer({ feed: sources.cyclones }),
|
|
...createInfrastructureLayers(localGeoJsonServices),
|
|
createApplicationCables({ source: sources.cables }),
|
|
createApplicationFirms({
|
|
surface,
|
|
id: 'local-firms',
|
|
name: 'FIRMS Active Fires',
|
|
icon: '▲',
|
|
source: 'NASA FIRMS · LIVE',
|
|
feed: sources.firms,
|
|
}),
|
|
],
|
|
metadata,
|
|
);
|
|
return Object.freeze({
|
|
...catalog,
|
|
militaryRegistry,
|
|
surface,
|
|
weatherClock,
|
|
});
|
|
} catch (error) {
|
|
dispose();
|
|
throw error;
|
|
}
|
|
}
|