God's Eye View Data Layer Interface: Complete Implementation Guide
The God's Eye View data layer interface is a plain JavaScript contract consisting of init(viewer, options?), enable(), disable(), update(dt), destroy(), and an optional getStats() method that every visual layer must implement.
Every dataset rendered in God's Eye View—whether traffic, CCTV feeds, flights, or satellites—conforms to this unified interface. The architecture decouples data sources from the rendering engine, allowing the layer manager to treat all visual layers identically. This guide examines the interface specification, walks through concrete implementations, and shows how to create custom layers.
Core Interface Methods
The data layer interface requires five mandatory methods and one optional method. These are defined in the header comment of src/data/traffic.js and enforced by convention across all layer files.
init(viewer, options?)
Asynchronously initializes the layer's internal state and attaches it to the Cesium viewer.
- Parameters:
viewer(the global Cesium viewer instance), optionaloptionsobject - Returns:
Promise<void>orvoid - Purpose: Create entities, set up network connections, configure initial state
// From src/data/traffic.js - typical init pattern
async init(viewer, options = {}) {
this.viewer = viewer;
this.signal = options.signal; // AbortController for cancellation
this.entities = [];
// ... fetch initial data, create Cesium entities
}
enable()
Activates the layer for visibility. Called after init() completes successfully.
- Transitions layer from initialized to active state
- Typically sets
entity.show = trueor starts animations - Must be idempotent (safe to call multiple times)
disable()
Deactivates the layer without destroying resources.
- Hides visual elements:
entity.show = false - Pauses network polling or data updates
- Preserves state for quick re-enabling
update(dt)
Called on every animation frame with elapsed time in milliseconds.
- Parameter:
dt— delta time since last frame in milliseconds - Use cases: animate entities, fetch fresh data, cull distant features, update labels
update(dt) {
// Throttle network updates
this.accumulator += dt;
if (this.accumulator > 5000) { // Every 5 seconds
this.fetchNewData();
this.accumulator = 0;
}
// Animate existing entities based on dt
this.entities.forEach(e => e.updatePosition(dt));
}
destroy()
Synchronously or asynchronously cleans up all resources.
- Removes Cesium entities:
viewer.entities.remove(this.entity) - Aborts pending
fetch()requests viaAbortController - Clears timers, event listeners, and WebGL resources
- Must be safe to call even if
init()failed partially
getStats() (Optional)
Returns a diagnostic object for debugging and performance monitoring.
getStats() {
return {
entityCount: this.entities.length,
lastFetch: this.lastFetchTime,
bytesTransferred: this.totalBytes,
errorCount: this.errors.length
};
}
Layer Manager Integration
The layer manager at src/data/manager.js orchestrates all registered layers by invoking interface methods in strict order.
Lifecycle Sequence
import layerManager from "./data/manager.js";
// 1. Initialize all registered layers
await layerManager.loadAll(viewer);
// 2. Enable specific layer
layerManager.enable("traffic");
// 3. Per-frame updates (called in render loop)
layerManager.updateAll(deltaTime);
// 4. Disable when hidden
layerManager.disable("traffic");
// 5. Cleanup on application exit
await layerManager.destroyAll();
Internal Manager Implementation
// src/data/manager.js - simplified excerpt
const layerRegistry = {
traffic: () => import("./traffic.js"),
cctv: () => import("./cctv.js"),
flights: () => import("./flights.js"),
// ... additional layers
};
class LayerManager {
async loadAll(viewer, options = {}) {
for (const [name, loader] of Object.entries(layerRegistry)) {
const module = await loader();
const layer = module.default;
await layer.init(viewer, { signal: options.signal });
this.layers.set(name, layer);
}
}
enable(name) {
const layer = this.layers.get(name);
if (layer?.enable) layer.enable();
}
disable(name) {
const layer = this.layers.get(name);
if (layer?.disable) layer.disable();
}
updateAll(dt) {
for (const layer of this.layers.values()) {
if (layer.update) layer.update(dt);
}
}
async destroyAll() {
for (const [name, layer] of this.layers) {
await layer.destroy?.();
this.layers.delete(name);
}
}
getStats(name) {
return this.layers.get(name)?.getStats?.();
}
}
Built-In Layer Implementations
God's Eye View ships with several reference implementations demonstrating the interface in production contexts.
Traffic Layer (src/data/traffic.js)
The primary example documented in source comments. Implements real-time vehicle tracking with:
- WebSocket connection for live position updates
- Entity pooling to minimize garbage collection
- Distance-based LOD (level-of-detail) rendering
CCTV Layer (src/data/cctv.js)
Surveillance camera feeds using:
- Video texture projection onto Cesium polygons
- Frustum visualization for camera sight lines
- Modal/popup integration on click events
Flights Layer (src/data/flights.js)
Aircraft tracking via ADS-B data:
- Great-circle interpolation between position reports
- Altitude-based coloring and scaling
- Trail/ghost rendering for flight paths
Creating Custom Data Layers
Any JavaScript module exporting an object with the interface methods can be registered as a layer.
Complete Custom Layer Example
// src/data/weatherRadar.js
export default {
// Internal state
viewer: null,
entities: [],
lastUpdate: 0,
rotation: 0,
async init(viewer, options = {}) {
this.viewer = viewer;
this.signal = options.signal;
// Create radar sweep entity
this.sweepEntity = viewer.entities.add({
name: "Weather Radar",
position: Cesium.Cartesian3.fromDegrees(-95.7129, 37.0902, 0),
ellipse: {
semiMinorAxis: 100000, // 100km radius
semiMajorAxis: 100000,
material: new Cesium.ColorMaterialProperty(
new Cesium.Color(0.0, 0.6, 1.0, 0.3)
),
rotation: new Cesium.CallbackProperty(() => this.rotation, false)
}
});
this.entities.push(this.sweepEntity);
await this.fetchRadarData();
},
enable() {
this.entities.forEach(e => e.show = true);
this.active = true;
},
disable() {
this.entities.forEach(e => e.show = false);
this.active = false;
},
update(dt) {
if (!this.active) return;
// Animate radar sweep rotation
this.rotation += dt * 0.001; // 1 radian per second
// Poll for new data every 5 minutes
this.lastUpdate += dt;
if (this.lastUpdate > 300000) {
this.fetchRadarData().catch(console.error);
this.lastUpdate = 0;
}
},
async fetchRadarData() {
const response = await fetch("/api/weather/radar", {
signal: this.signal
});
const data = await response.json();
// Update entity appearances based on precipitation intensity
this.updateVisualization(data);
},
updateVisualization(data) {
// Implementation: color mapping based on dBZ values
},
async destroy() {
// Clean up entities
for (const entity of this.entities) {
this.viewer.entities.remove(entity);
}
this.entities = [];
// Abort any pending fetches
if (this.signal?.abort) {
this.signal.abort();
}
},
getStats() {
return {
entityCount: this.entities.length,
sweepAngleRad: this.rotation,
sweepAngleDeg: Cesium.Math.toDegrees(this.rotation) % 360,
lastDataFetch: this.lastUpdate
};
}
};
Registration in Layer Manager
// src/data/manager.js - add to registry
import weatherRadar from "./weatherRadar.js";
const layerRegistry = {
traffic: () => import("./traffic.js"),
cctv: () => import("./cctv.js"),
flights: () => import("./flights.js"),
satellites: () => import("./satellites.js"),
weatherRadar, // Static import for custom layer
};
Error Handling and Edge Cases
Robust layer implementations follow these patterns found in src/data/traffic.js:
- Defensive
init(): Check for Cesium viewer availability, handle missing WebGL contexts - Graceful
destroy(): Use optional chaining (this.entity?.remove()) to handle partial initialization update()throttling: Prevent frame drops from synchronous network I/O- AbortController integration: Pass
signalthrough allfetch()calls for cancellation on layer disable
Summary
- God's Eye View data layer interface mandates five methods—
init(),enable(),disable(),update(dt),destroy()—plus optionalgetStats() - The layer manager in
src/data/manager.jsorchestrates lifecycle across all registered layers uniformly - Built-in layers (
traffic.js,cctv.js,flights.js) serve as reference implementations of production-quality code - Custom layers require only a plain JavaScript object with the interface methods; no inheritance or framework classes needed
- The architecture enables hot-swappable data sources without modifying core rendering or application logic
Frequently Asked Questions
What happens if a layer doesn't implement all required methods?
The layer manager defensively checks for method existence before invocation (layer.update?.(dt)), so missing methods are silently skipped. However, omitting init() or destroy() typically causes runtime errors or resource leaks. Always implement all five core methods for reliable operation.
Can data layers use async/await throughout their lifecycle?
Yes. init() and destroy() support async operations natively. The update() method may also be async, though the manager does not await its completion to maintain frame rate—fire-and-forget patterns with Promise.catch() are recommended for network calls inside update().
How does God's Eye View handle layer performance monitoring?
The optional getStats() method returns diagnostic objects consumed by the debug UI. Built-in layers expose entity counts, network latency, and memory usage. Aggregate statistics across all active layers are available via layerManager.getAllStats() for identifying bottlenecks.
Is TypeScript support available for the data layer interface?
The codebase uses pure JavaScript without type definitions. For TypeScript projects, you can define the interface as:
interface DataLayer {
init(viewer: Viewer, options?: { signal?: AbortSignal }): Promise<void> | void;
enable(): void;
disable(): void;
update(dt: number): void;
destroy(): Promise<void> | void;
getStats?(): Record<string, unknown>;
}
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →