Skip to content

Architecture

Module Hierarchy

graph TD
    A[index.js] --> B[index_maps.js]
    A --> C[index_indoor.js]
    B --> D[Map]
    B --> E[Marker / InfoWindow / OverlayView]
    B --> F[Geometry — Polygon, Polyline, Circle, Rectangle]
    B --> G[Data Layer — GeoJSON features]
    B --> H[Services — Distance, Stores, Localities, etc.]
    B --> I[Directions — Service + Renderer]
    B --> J[Overlays — StoresOverlay, DatasetsOverlay]
    B --> K[ImageMapType — Tile layers]
    C --> L[IndoorRenderer]
    C --> M[IndoorService]

    D --> N[MVCObject]
    E --> N
    F --> N
    G --> N

    style A fill:#4051b5,color:#fff
    style B fill:#4051b5,color:#fff
    style C fill:#4051b5,color:#fff

Initialization Flow

sequenceDiagram
    participant Browser
    participant Config
    participant Map
    participant MapboxGL
    participant Worker

    Browser->>Config: Parse script tag params (key, language, libraries)
    Browser->>Map: new Map(div, options)
    Map->>MapboxGL: Initialize mbgl.Map with default style
    MapboxGL->>Worker: Spawn tile processing web worker
    Map->>Map: Apply gestureHandling overlay
    Map->>Map: Bind Data layer
    Map->>Map: Initialize MVCObject properties
    Map-->>Browser: Fire 'tilesloaded' event
    Map-->>Browser: Fire 'idle' event

Source Organization

src/
├── index.js                  # Main entry (Maps + Indoor)
├── index_maps.js             # Maps-only exports
├── index_indoor.js           # Indoor exports
├── index_services.js         # Services-only entry
├── map.js                    # Map class
├── marker.js                 # Marker class
├── infowindow.js             # InfoWindow class
├── overlay-view.js           # OverlayView base class
├── latlng.js                 # LatLng, LatLngBounds
├── mvcobject.js              # MVCObject (observable properties)
├── mvcarray.js               # MVCArray (observable array)
├── config.js                 # Global config singleton
├── directions-service.js     # DirectionsService
├── directions-renderer.js    # DirectionsRenderer
├── stores-overlay.js         # StoresOverlay
├── datasets-overlay.js       # DatasetsOverlay
├── geometry/                 # Polygon, Polyline, Circle, Rectangle
├── data/                     # GeoJSON data layer, symbols, feature styling
├── services/                 # API clients
│   ├── distance/
│   ├── stores/
│   ├── localities/
│   ├── datasets/
│   ├── transit/
│   └── query/
├── indoor/                   # Indoor renderer and service
├── widgets/                  # Preact UI components
│   ├── navigation/           # Navigation control
│   └── indoor/               # Indoor panel
├── drawing/                  # Drawing tools (wraps mapbox-gl-draw)
├── map-style/                # MapStyleSpec processing
├── map-type/                 # ImageMapType tile overlays
├── css/                      # PostCSS source
└── utils/                    # Network, caching, errors, image processing

MVCObject Pattern

MVCObject is the base class for most map objects. It implements a Key-Value Observer pattern inspired by Google Maps:

class MVCObject {
    get(key)                          // Get property value
    set(key, value)                   // Set property and notify listeners
    addListener(event, handler)       // Listen for property changes
    bindTo(key, target, targetKey)    // Bind property to another MVCObject
}

When a property changes, the object fires a {key}_changed event. Bound properties propagate changes bidirectionally.

Classes that extend MVCObject: Map, Marker, InfoWindow, OverlayView, Polygon, Polyline, Circle, Rectangle, Data, and more.

Global Namespace Assembly

The entry points assemble exports into window.woosmap.map:

graph LR
    A[index_maps.js] -->|Object.assign| C[window.woosmap.map]
    B[index_indoor.js] -->|Object.assign| C
    C -->|alias| D[window.ninja.maps]

The services.js bundle exports a subset (services only) to the same namespace, allowing headless API usage without loading the map renderer.

Styling Pipeline

Map styling follows this flow:

  1. User calls map.setMapStyle(styles: MapStyleSpec[])
  2. Styles are validated against the spec (feature types, element types, styler properties)
  3. MapStyle iterates styles and applies transforms via applyStylers()
  4. Transforms modify Mapbox GL layer paint properties (color, weight, visibility)
  5. A style_update event fires when processing completes

Data Flow

graph LR
    A[User Input] --> B[Map / Service API]
    B --> C[Config — URL construction]
    C --> D[REQUESTER — HTTP client]
    D --> E[Woosmap API]
    E --> D
    D --> B
    B --> F[MVCObject — property update]
    F --> G[Event listeners / UI update]

Services use the REQUESTER utility for all HTTP communication. The Config singleton constructs API URLs based on the build environment and API key format.