# Map Stack Controller in God's Eye View: Purpose, Architecture, and Implementation

> Discover the Map Stack Controller in God's Eye View. Learn how it manages basemap selection, availability, and terrain providers asynchronously for seamless map integration.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: architecture
- Published: 2026-09-06

---

**The Map Stack Controller is the central orchestration layer in God's Eye View that manages basemap selection, availability checks, attribution requirements, and terrain provider switching in an asynchronous-safe manner.**

This article explains how the `MapStackController` class in [`src/mapStackController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/mapStackController.js) functions as the single source of truth for globe visualization, abstracting Cesium imagery providers and terrain handling into a robust, UI-friendly API.

---

## Core Responsibilities of the Map Stack Controller

The Map Stack Controller addresses four critical concerns in God's Eye View:

1. **Stack definition** — Declares supported basemaps (Google 3D, Bing Aerial, Bing Labels, Esri Satellite, OSM) with metadata
2. **Availability enforcement** — Prevents selection of stacks requiring unavailable credentials or tilesets
3. **Safe asynchronous switching** — Prevents race conditions during network-heavy provider changes
4. **Attribution and terrain coordination** — Manages legal credits and elevation data alongside imagery

All higher-level code—including UI widgets, data layers, and testing scripts—interacts with the controller rather than directly with Cesium APIs.

---

## Map Stack Definitions and Configuration

The controller declares its supported stacks in the `MAP_STACKS` array near the top of [`src/mapStackController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/mapStackController.js) (lines 19-57). Each stack specifies:

- `id` and `label` for UI rendering
- `requiresToken` flags for Cesium Ion or Google 3D dependencies
- Attribution requirements (notably for Esri)

```javascript
// Simplified excerpt from MAP_STACKS definition
const MAP_STACKS = [
  { id: 'photoreal', label: 'Google 3D', requiresGoogleTileset: true },
  { id: 'bing-aerial', label: 'Bing Aerial', requiresCesiumToken: true },
  { id: 'esri-satellite', label: 'Esri Satellite', requiresAttribution: true },
  // ... additional stacks
];

```

This declarative approach allows the controller to compute availability dynamically based on runtime configuration rather than hardcoded logic.

---

## Tracking the Active Map Stack

The constructor (lines 90-103) establishes the controller's central state:

- `_activeId` stores the currently selected stack identifier
- `_providerCache` lazily instantiates and reuses Cesium imagery providers
- `_switchGen` implements a monotonic counter for race-condition prevention

```javascript
// From src/mapStackController.js constructor
this._activeId = initialStack || MAP_STACKS[0].id;
this._switchGen = 0;
this._providerCache = new Map();

```

The `_activeId` field serves as the canonical state that all UI components observe through `getActiveId()` (lines 36-49).

---

## Availability Checking with isStackAvailable

Before any switch operation, the controller validates prerequisites through `isStackAvailable` (lines 95-101). This method checks:

- Presence of Cesium Ion tokens for Bing-based stacks
- Existence of Google 3D tileset for photorealistic mode
- Feature flags for experimental providers

**Unavailability propagates meaningfully**: the `getStacks()` method enriches each stack object with an `available` boolean and optional `unavailableReason` string, enabling UI components to show disabled states with explanatory tooltips.

---

## The setStack API: Safe Asynchronous Switching

The `setStack(id, opts)` method (lines 203-256) is the controller's primary public interface for changing basemaps. Its implementation demonstrates sophisticated async handling:

### Race-Condition Prevention via Generation Counting

```javascript
// From setStack implementation
const thisGen = ++this._switchGen;

// ... async provider creation ...

// Before applying, verify this is still the latest request
if (this._switchGen !== thisGen) {
  return { activeId: this._prevId, status: 'superseded' };
}

```

This **M7 pattern** ensures that a slow Bing Aerial network request cannot overwrite a subsequent user-initiated switch to OSM. The monotonic `_switchGen` counter effectively tags each operation; stale operations self-abort.

### Error Handling and State Reporting

Failed switches propagate through the `onError` callback injected at construction, with structured return values for programmatic handling:

```javascript
const result = await mapStackController.setStack('bing-aerial');
// result = { activeId, status: 'success' | 'error' | 'superseded', error? }

```

---

## Imagery Provider Creation and Caching

The `_getImageryProvider` private method (lines 336-379) implements lazy instantiation with fallback logic:

1. Check cache for existing provider instance
2. Create Cesium imagery provider based on stack type (`BingMapsImageryProvider`, `ArcGisMapServerImageryProvider`, `OpenStreetMapImageryProvider`, etc.)
3. **Graceful degradation**: Esri Satellite falls back to OSM on connection failure
4. Cache successful provider for reuse

```javascript
// Usage pattern from UI code
async function handleMapStackSelect(stackId) {
  const resultState = await mapStackController.setStack(stackId);
  console.log('Switched to', resultState.activeId);
}

```

---

## Attribution Management for Esri Compliance

The Esri Satellite stack requires specific attribution that must appear when active and be removed when inactive. The `_syncEsriAttribution` method (lines 319-334) handles this:

- Adds "Powered by Esri" credit to Cesium's `creditDisplay` when Esri stack activates
- Removes credit on deactivation or switch to non-Esri stack
- Handles edge cases like rapid consecutive switches

This ensures legal compliance without polluting the UI for other basemaps.

---

## Terrain Provider Coordination

Beyond imagery, the controller manages elevation data through `_setWorldTerrainEnabled` (lines 443-458):

| Scenario | Terrain Provider Used |
|----------|---------------------|
| Cesium Ion token present | `CesiumWorldTerrain` with ion access |
| No token available | Re:Earth keyless terrain provider |
| Both unavailable | Flat ellipsoid (no terrain) |

The terrain switch is atomic with imagery changes, preventing visual mismatches where, for example, satellite imagery appears over flat terrain while elevation data loads.

---

## Integration Points in God's Eye View

### Instantiation in main.js

Lines 174-186 in [`src/main.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js) demonstrate production usage:

```javascript
import { MapStackController } from './mapStackController.js';

const mapStackController = new MapStackController(viewer, {
  googleTileset,                // optional Google 3D tileset
  cesiumToken: process.env.CESIUM_ION_TOKEN,
  initialStack: 'photoreal',
  onChange: (state) => console.log('Map stack changed', state),
  onError: (msg, stack) => console.warn('Map stack error:', msg, stack),
});

```

### UI Rendering in mapStackChips.js

The `mapStackChips` component queries available stacks and renders selection chips:

```javascript
const stacks = mapStackController.getStacks(); // [{id, label, available, ...}, …]
renderMapStackChips(container, stacks, {
  activeId: mapStackController.getActiveId(),
  onSelect: handleMapStackSelect,
});

```

### Event Integration in ui.js

Lines 3487-3510 in [`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js) wire the controller into the broader interface, ensuring other subsystems (traffic visualization, submarine cable overlays) respond to basemap changes appropriately.

---

## Key Implementation Files

| File | Responsibility |
|------|--------------|
| [`src/mapStackController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/mapStackController.js) | Core controller with stack definitions, switching logic, attribution, terrain handling |
| [`src/main.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js) | Controller instantiation and Cesium viewer wiring |
| [`src/mapStackChips.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/mapStackChips.js) | UI component for stack selection |
| [`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js) | High-level UI initialization and cross-subsystem coordination |

---

## Summary

- **The Map Stack Controller centralizes basemap management** in God's Eye View, providing a single API for stack selection, availability checking, and safe asynchronous switching
- **Race-condition prevention** via generation counting ensures UI responsiveness despite slow network providers
- **Lazy provider caching** optimizes performance while supporting fallback chains for reliability
- **Attribution and terrain coordination** handles legal requirements and elevation data automatically
- **Clear separation of concerns** allows UI components, data layers, and tests to interact with abstracted stack concepts rather than raw Cesium APIs

---

## Frequently Asked Questions

### What happens if I try to select a Map Stack that requires a token I don't have?

The `setStack` method will reject the operation and return an error state. Before attempting the switch, `getStacks()` marks the stack as `available: false` with an `unavailableReason` explaining the missing credential, allowing your UI to disable the option and show explanatory text.

### How does the Map Stack Controller prevent race conditions during slow network requests?

Each `setStack` call increments a monotonic `_switchGen` counter. When a provider eventually resolves, the method checks whether its generation matches the current counter. Mismatches indicate a superseded request, and the stale result is discarded without applying to the viewer.

### Can I use the Map Stack Controller without Google 3D tiles?

Yes. The `googleTileset` parameter is optional in the constructor. Stacks requiring it (like `photoreal`) will report themselves unavailable if the tileset is omitted, while Bing, Esri, and OSM stacks function normally with just a Cesium Ion token or no credentials at all.

### Where should I instantiate the Map Stack Controller in my own God's Eye View deployment?

Follow the pattern in [`src/main.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js) lines 174-186: create the controller immediately after Cesium viewer initialization, passing the viewer instance, optional tokens, your preferred initial stack, and callback handlers for change notifications and errors.