The Lifecycle Contract for Data Overlays in the DataLayerManager: 4 States Explained
The DataLayerManager in the gods-eye-view repository enforces a strict lifecycle contract that moves every data overlay through disabled, enabling, enabled, and disabling states, using a serial queue and deterministic event pipeline to prevent race conditions and guarantee safe transitions.
The DataLayerManager class defined in src/data/manager.js governs every real-time data overlay rendered on the CesiumJS globe in bilawalsidhu/gods-eye-view. Its lifecycle contract for data overlays specifies exactly how an overlay advances from initialization through activation to teardown, while an “uncertain” flag captures any transition that fails or aborts. Understanding these states and their enforcement mechanisms is essential for building reliable UI controls and custom data modules.
Four Primary Lifecycle States
The contract defines four mutually exclusive states stored in the lifecycleState field, declared at src/data/manager.js#L78-L88.
disabled
This is the default and terminal rest state. An overlay in the disabled state is fully off, releases resources, and does not render. The manager sets this state after a successful disable() call or during initialization.
enabling
The enabling state means the manager is actively executing the enable sequence: init → enable → first update. The helper _setLifecycleTransition at src/data/manager.js#L62-L71 records this transition and immediately notifies listening UI panels via _refreshTogglePanel.
enabled
Once the enable sequence completes without error, _settleLifecycle at src/data/manager.js#L74-L85 finalizes the entry as enabled. In this state the overlay is visible, actively polling for periodic updates, and fully integrated with the CesiumJS globe.
disabling
The disabling state indicates an in-progress teardown. The manager enters this state through _setLifecycleTransition(..., 'disabling') while the overlay module’s disable logic runs.
lifecycleUncertain Flag
Whenever a lifecycle step throws an exception or returns false—such as a rejected enable, disable, or init—the manager sets entry.lifecycleUncertain = true. According to the contract comment block at src/data/manager.js#L15-L21, this flag signals that the overlay’s authoritative state cannot be trusted and the transition should be treated as failed.
Serial Queue and Phase Pipeline Enforcement
The lifecycle contract is enforced by a serial queue stored on each overlay entry as entry.toggleChain. This queue guarantees that only one lifecycle transition runs at a time for a given overlay, eliminating race conditions like double-polling or rapid enable-then-disable glitches.
Each transition follows a deterministic six-phase pipeline:
- Visibility-Will-Change – The manager emits a
visibility-will-changeevent so listeners can prepare. - Guard Check –
_visibilityBlockReasonmay abort the transition before any module code runs. - Lifecycle Transition –
_setLifecycleTransitionrecords the new state (enablingordisabling) and refreshes toggle panels. - Module Lifecycle Calls – The overlay’s module receives ordered calls such as
entry.module.init(),entry.module.enable(),entry.module.update(), orentry.module.disable(). Concrete implementations like the OpenSky traffic feed insrc/data/traffic.jsimplement these hooks. - Error Handling – Any thrown exception or rejected promise triggers a
visibility-failedevent and setsentry.lifecycleUncertain = true. - Settlement – On success,
_settleLifecyclerecords the finalenabledordisabledstate and clears uncertainty.
Event emission for these phases is centralized at src/data/manager.js#L490-L517.
Public API for Data Overlay Lifecycle Control
The contract is surfaced through two public methods that both return promises resolving only after the lifecycle settles.
setEnabled
setEnabled(layerId, shouldEnable, options) requests an absolute state change. Pass true to activate an overlay or false to deactivate it.
// Enable the OpenSky traffic overlay
await dataManager.setEnabled('openSky', true, {
origin: 'user',
notificationToken: 'ui-button',
});
// Disable the same overlay
await dataManager.setEnabled('openSky', false, {
origin: 'user',
notificationToken: 'ui-button',
});
toggle
toggle(layerId, options) flips the current effective visibility without requiring the caller to know the existing state. Implemented at src/data/manager.js#L174-L190, it delegates to the same internal pipeline used by setEnabled.
// Toggle the overlay relative to its current state
await dataManager.toggle('openSky', { origin: 'user' });
Both methods return a promise that resolves after the manager has moved through the appropriate lifecycle phases, guaranteeing the overlay is either fully active or fully inactive.
Event-Driven State Synchronization
UI components such as those in src/ui.js consume a structured event stream to stay synchronized with the lifecycle contract. The manager emits the following events during transitions:
visibility-will-change– Fired before the guard check and module calls begin.visibility– Fired after successful settlement.visibility-failed– Fired when a lifecycle step throws or rejects.visibility-cancelled– Fired when a transition is aborted by user action or logic.visibility-blocked– Fired when_visibilityBlockReasonprevents the transition.
Listeners can use these events to update toggle buttons, persist user preferences, or display error indicators without polling the manager directly.
Summary
- The DataLayerManager in
src/data/manager.jsdefines a strict lifecycle contract for data overlays with four primary states:disabled,enabling,enabled, anddisabling. - A serial queue (
entry.toggleChain) prevents concurrent transitions and eliminates race conditions. - The six-phase pipeline includes event emission, guard checks, state recording via
_setLifecycleTransition, module hooks, error handling, and final settlement via_settleLifecycle. - The uncertain flag (
entry.lifecycleUncertain) marks entries where a lifecycle step failed or returnedfalse. - Public methods
setEnabledandtogglereturn promises that resolve only after the lifecycle settles, providing a safe async boundary for UI code.
Frequently Asked Questions
What happens if an overlay fails during the enable sequence?
If init, enable, or the first update throws or returns false, the manager emits a visibility-failed event and sets entry.lifecycleUncertain = true according to src/data/manager.js#L74-L85. The overlay does not reach the enabled state, and the entry remains in an untrustworthy condition until the next successful transition.
How does the DataLayerManager prevent rapid toggle race conditions?
Each overlay entry owns a serial queue (entry.toggleChain) that chains lifecycle transitions sequentially. Because the pipeline enforces one transition at a time, rapid calls to setEnabled or toggle cannot overlap or execute out of order, preventing double-polling and visual glitches.
What is the difference between setEnabled and toggle?
setEnabled(layerId, shouldEnable) drives the overlay toward an absolute boolean state and is used when the caller already knows the desired outcome. toggle(layerId), defined at src/data/manager.js#L174-L190, determines the current effective visibility and then delegates to the same internal pipeline to flip it, making it ideal for simple button interactions.
Which lifecycle events should a UI panel listen for?
Panels should listen for visibility-will-change to show loading indicators, visibility to confirm active state, visibility-failed to display errors, and visibility-blocked to explain why a transition was prevented. The src/ui.js file demonstrates this pattern by reacting to these events to refresh controls and panels.
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 →