Skip to content

<SpatialMap> Container Shell

The <SpatialMap> component is the central container for the BloomSpark indoor mapping suite. It instantiates the underlying MapLibre GL JS map instance, registers the PMTiles protocol exactly once, manages the controlled or uncontrolled viewport camera state, and exposes context to hooks and child overlay components.


⚙️ Component Props API

typescript
import maplibregl from 'maplibre-gl';

export interface SpatialMapProps {
  /** Array of building data structures serving this map view. */
  buildings: Building[];
  
  /** Controlled active building ID. Exploded floors and details are visible for this building. */
  activeBuildingId?: string;
  
  /** Callback fired when the active building switches (e.g. via zoom DynamicFocus threshold). */
  onActiveBuildingChange?: (id: string) => void;
  
  /** Uncontrolled initial viewport camera coordinates. */
  initialViewState?: ViewState;
  
  /** Controlled viewport camera coordinates. Pair with onViewStateChange. */
  viewState?: ViewState;
  
  /** Fired when coordinates or zoom values update during camera motions. */
  onViewStateChange?: (vs: ViewState) => void;
  
  /** Style mode selection. Extrudes 3D structures or locks to pitch-0 topdown plan. */
  mode?: '2d' | '3d';
  
  /** Fired when mode switches between 2D and 3D. */
  onModeChange?: (m: '2d' | '3d') => void;
  
  /** MapLibre style JSON specification or direct CDN string. Defaults to a bundled Protomaps light spec. */
  mapStyle?: maplibregl.StyleSpecification | string;
  
  /** Set to true to require a two-finger swipe to pan on mobile web views. */
  cooperativeGestures?: boolean;
  
  /** Enable or disable standard vector attribution credits overlay. Default is true. */
  attributionControl?: boolean;
  
  /** Maximum camera pitch allowed in degrees. Default is 70. */
  maxPitch?: number;
  
  /** Custom HTML className applied to the root wrapper. */
  className?: string;
  
  /** Inline React CSS variables applied to the root wrapper. */
  style?: React.CSSProperties;
  
  /** Child overlays and panels. */
  children?: React.ReactNode;
}

export interface ViewState {
  longitude: number;
  latitude: number;
  zoom: number;
  pitch: number;
  bearing: number;
}

export interface Building {
  id: string;
  name: Record<string, string>;
  levels: Level[];
  homography?: Homography;
}

export interface Level {
  id: string;
  ordinal: number;
  name: Record<string, string>;
  short_name: Record<string, string>;
}

export type Homography = readonly [
  number, number, number,
  number, number, number,
  number, number, number
];

🏢 Multi-Building Campus Architecture

The SDK supports single-building environments as well as massive campus footprints containing dozens of structures:

  • Vector Footprints: Footprints of all loaded buildings are rendered on the basemap at low-level zoom scales.
  • Active Focusing: Exploiting the activeBuildingId controls which building is selected and expanded.
  • Automatic Transition: <DynamicFocus /> handles automatic viewport-to-floor selection transitions when zoom ranges pass defined thresholds (zoom ≥18 locks on the building interior; zoom <16 fades back to outdoor basemaps).

🎨 MapLibre Layer Z-Ordering

Below is the authoritative layout hierarchy inside <SpatialMap> and <FloorLayers>. deck.gl layers share MapLibre's WebGL context via MapboxOverlay, preventing dual rendering delays:

Layer Z-IndexLayer IdentifierSource TypeDescription
0basemap-*PMTiles VectorStatic external Protomaps vectors
100building-extrusion-3dGeoJSON Footprint3D oblique structures
200floorplan-imageWebGL homography rasterScanned blueprint canvas overlays
300floor-fillGeoJSON PolygonIMDF Unit fills
310floor-outlineGeoJSON LineStringUnit boundaries
320wall-3dfill-extrusionExtruded building partitions
400door-*, opening-*GeoJSON LineStringExit paths / architectural openings
500fixture-*GeoJSON PolygonInside furniture / custom assets
600amenity-iconsSymbol/CircleAnchor point representations
700data-layer-*GeoJSON or deck.glCustomer point/icon telemetry layers
800heatmap-*deck.gl InterleavedHistorical activity aggregation
900wayfinding-routeGeoJSON LineStringDirected A* path paths
950rtls-traildeck.gl TripsLayerReal-time moving particle vectors
980bluedotSymbol/CircleFocused personal locator beacon
990selection-highlightGeoJSON LineStringActive click/select bounds

🧼 Cleanup Protocols

<SpatialMap> handles system bindings transparently during unmounting:

  • Removes pmtiles:// custom transport handlers using maplibregl.removeProtocol('pmtiles').
  • Disconnects active Web Worker transport channels safely.
  • Destroys local IndexedDB caching allocations for temporary viewState variables.

Released under commercial licensing.