Skip to content

Map SDK API

Package: @agastyadreamspty/map-sdk

This document is the developer reference for integrating the reusable Map SDK into Angular applications.

It is written for engineers who need to:

  • understand the supported public API
  • embed the full host or individual widgets
  • wire custom adapters or renderers
  • control runtime behavior through configuration
  • verify which responsibilities belong to the SDK versus the consumer app

The SDK is designed to be composable, so consumers can adopt:

  • the full map explorer page
  • filters only
  • legend only
  • parcel search only
  • zoom and layer status only
  • a custom map renderer
  • a custom backend adapter

The package name is SDK-first, but some exported contract names still use the MapFeature* prefix for compatibility with the current codebase.

Public Surface

The long-term supported entry points are:

  • MapFeatureConfig
  • MapFeatureZoomPolicy
  • MapFeatureAdapter
  • MapFeatureAuthAdapter
  • MapFeaturePermissionAdapter
  • MapFeatureRendererAdapter
  • MapFeatureProviderOptions
  • MapFeatureAngularAdapter
  • MapFeatureRuntimeConfig
  • MapFeatureHttpConfig
  • MapFeatureThemeVars
  • FeatureEventBus
  • FeatureSdkEvent
  • FeatureSdkSelectionEvent
  • FeatureSdkLayerVisibilityEvent
  • MapFeatureLayerClickEvent
  • FeatureError
  • FeatureErrorCode
  • provideMapSdk(...)
  • provideMapFeatureRuntimeConfig(...)
  • provideMapFeatureHttpConfig(...)
  • provideMapFeatureAdapter(...)
  • provideMapFeatureDataSource(...)
  • provideMapFeatureRendererAdapter(...)
  • MapSdkHostComponent
  • MapSdkHostShellComponent
  • MapSdkFiltersComponent
  • MapSdkLegendPanelComponent
  • MapSdkParcelSearchComponent
  • MapSdkZoomLayerStatusComponent
  • MapSdkDetailDialogData
  • MapFeatureFilterOption
  • MapFeatureParcelSearchSuggestion
  • MapFeatureGeometryResponse
  • MapFeatureLegendGroup
  • MapFeatureLegendItem
  • MapLegendResponse
  • MapLegendGroupApi
  • MapLegendEntryApi
  • MapLegendStyling
  • MapLegendMatching
  • MAP_FEATURE_DATA_SOURCE
  • MAP_FEATURE_RUNTIME_CONFIG
  • MAP_FEATURE_HTTP_CONFIG
  • MAP_SDK_RENDERER

Everything else should be treated as implementation detail unless it is documented here.

Package Philosophy

The SDK is responsible for:

  • backend data loading
  • legend grouping and normalization
  • zoom thresholds and layer visibility
  • parcel search behavior
  • popup data normalization
  • theming variables
  • common events and callbacks

The consumer app is responsible for:

  • the surrounding page layout
  • the host app chrome
  • any custom map vendor if they do not want the full-page host
  • local wrapper components
  • app-specific styling overrides

Capability Matrix

Use this table to choose the right SDK mode for your app.

Capability Full host Widgets only Custom renderer Headless
Province and municipality filters Yes Yes Yes No
Boundary rendering Yes Yes Yes No
Parcel rendering Yes Yes Yes No
Parcel search Yes Yes Yes No
Legend panel Yes Yes Yes No
Built-in Leaflet canvas Yes Yes No No
Custom map vendor Optional Optional Yes Yes
SDK event bus Yes Yes Yes Yes
SDK fetches backend data Yes Yes Yes Yes

Typical usage:

  • Full host: use when you want the SDK to behave like the warehouse map explorer.
  • Widgets only: use when your app owns layout but wants the SDK filters, legend, and search.
  • Custom renderer: use when your app already owns the map canvas but wants SDK data and behavior.
  • Headless: use when your app wants data, events, and policy logic without any default UI.

Architectural Overview

The SDK sits between the consumer app and the map backend. In the default mode, the SDK owns data loading and rendering while the consumer owns the page shell.

flowchart LR
  subgraph Consumer["Consumer App"]
    A["Route / Page Shell"]
    B["Theme Wrapper"]
    C["Event Handlers"]
    D["Optional Custom Renderer"]
  end

  subgraph SDK["Map SDK"]
    E["MapSdkHostComponent"]
    F["MapSdkHostShellComponent"]
    G["Widgets\nFilters - Legend - Search - Status"]
    H["Providers\nConfig - Adapter - Renderer"]
    I["FeatureEventBus"]
  end

  subgraph Backend["Map Backend API"]
    J["Provinces"]
    K["Municipalities"]
    L["Legends"]
    M["Parcel Search"]
    N["Geometry + Popup Data"]
  end

  A --> E
  A --> G
  B --> E
  C --> I
  D --> H
  E --> H
  G --> H
  H --> Backend
  Backend --> N
  H --> I

Fishbone View

This fishbone-style diagram shows the main responsibility branches that make up the SDK experience.

flowchart LR
  SDK["Map SDK"]

  Consumer["Consumer Shell\nRoute - Layout - Theme"]
  Data["Data Contract\nAPI base URL - adapter - runtime config"]
  UI["UI Widgets\nFilters - Legend - Search - Status"]
  Render["Rendering\nLeaflet host - custom renderer"]
  Events["Events\noutputs - event bus - layer clicks"]
  Policy["Policy\nzoom rules - visibility - gating"]
  Docs["Docs + Deployment\nAPI - integration - theming"]

  Consumer --- SDK
  Data --- SDK
  UI --- SDK
  Render --- SDK
  Events --- SDK
  Policy --- SDK
  Docs --- SDK

Configuration

MapFeatureZoomPolicy

Controls when each boundary or parcel family becomes visible.

export interface MapFeatureZoomPolicy {
  provinceBoundaryZoom: number;
  districtBoundaryZoom: number;
  municipalityBoundaryZoom: number;
  suburbBoundaryZoom: number;
  parcelZoom: number;
  labelZoomByKind: Record<MapLayerKind, number>;
}

Default values:

  • province boundary: 7
  • district boundary: 8
  • municipality boundary: 9
  • suburb boundary: 10
  • parcel zoom: 12

MapFeatureConfig

This is the top-level host configuration.

export interface MapFeatureConfig {
  apiBaseUrl: string;
  includeInactive: boolean;
  zoomPolicy: Partial<MapFeatureZoomPolicy>;
  features: MapFeatureFeatureFlags;
  ui: MapFeatureUiConfig;
  search: MapFeatureSearchConfig;
  legend: MapFeatureLegendConfig;
}

Key fields

  • apiBaseUrl
  • Base URL used by the SDK when it talks to the backend.
  • Default: /api
  • Common runtime examples:
    • local: http://localhost:8080/api
    • production: https://api-warehouse.idti.dev/api
  • includeInactive
  • Whether inactive legend entries should be returned or hidden.
  • zoomPolicy
  • Partial override of the default zoom thresholds.
  • features
  • Feature gate block that turns major SDK behaviors on or off.
  • ui
  • Host labels, theming class, container ID, and mount mode.
  • search
  • Search prompt, debounce, and limit behavior.
  • legend
  • Legend toggles and default collapsed state.

MapFeatureFeatureFlags

These gates let the consumer decide which behaviors are active.

  • legend
  • search
  • provinceFilters
  • municipalityFilters
  • selectedMunicipalityOverlay
  • refreshButton
  • boundaries
  • parcels

MapFeatureUiConfig

export interface MapFeatureUiConfig {
  title: string;
  subtitle: string;
  themeClass: string;
  mapContainerId: string;
  showStatusBanner: boolean;
  showLoadingOverlay: boolean;
  mountMode: MapFeatureMountMode;
}

Supported mountMode values:

  • full-page
  • widgets
  • headless

Default UI values:

  • title: Map Explorer
  • subtitle: Browse boundaries, parcels, and live legend layers.
  • theme class: map-sdk-theme
  • map container ID: leaflet-map
  • mount mode: full-page

MapFeatureSearchConfig

export interface MapFeatureSearchConfig {
  placeholder: string;
  minLength: number;
  debounceMs: number;
  resultLimit: number;
}

Default search values:

  • placeholder: Search parcels by LPI, SG number, or description
  • minimum length: 2
  • debounce: 300ms
  • result limit: 8

MapFeatureLegendConfig

export interface MapFeatureLegendConfig {
  allowVisibilityToggle: boolean;
  allowColorEdit: boolean;
  defaultCollapsed: boolean;
}

Default legend behavior:

  • visibility toggle enabled
  • color editing enabled
  • legend expanded by default

Data Contracts

MapFeatureAdapter

MapFeatureAdapter is the main backend data contract. It is an alias for MapFeatureDataSource.

Use it when you want the SDK to fetch data from your API, but you need to replace the HTTP layer or adapt to your own backend.

Required method:

  • loadLegend(provinceId, includeInactive?, municipalityId?)

Optional methods:

  • loadProvinces()
  • loadMunicipalities(provinceId)
  • getParcelDetail(provinceId, parcelType, sourceId)
  • getProvinceGeometry(provinceId)
  • getMunicipalityGeometry(provinceId, municipalityId)
  • searchParcels(provinceId, municipalityId, search, limit?)
  • getParcelGeometryBySuggestion(provinceId, suggestion)
  • getAdminBoundaryDetails(sourceKind, provinceId, sourceId?, displayName?, locationId?)

Common request intent:

Method Purpose
loadLegend(...) Load visible legend groups and colors for the current scope
loadProvinces() Populate province dropdowns
loadMunicipalities(provinceId) Populate municipality dropdowns after a province is selected
getProvinceGeometry(provinceId) Render or refresh the selected province overlay
getMunicipalityGeometry(provinceId, municipalityId) Render or refresh the selected municipality overlay
searchParcels(...) Return parcel suggestions for the search panel
getParcelGeometryBySuggestion(...) Render the selected searched parcel geometry
getParcelDetail(...) Load the popup record for a clicked parcel
getAdminBoundaryDetails(...) Load the popup record for a clicked boundary or administrative feature

Example adapter sketch:

export class AppMapAdapter implements MapFeatureAdapter {
  loadLegend(provinceId: string, includeInactive = false, municipalityId?: string) {
    return this.http.get<MapLegendResponse>(
      `${this.baseUrl}/map/legend/${provinceId}`,
      { params: { includeInactive, municipalityId: municipalityId ?? '' } }
    );
  }

  searchParcels(provinceId: string, municipalityId: string, search: string, limit = 8) {
    return this.http.get<MapFeatureParcelSearchResponse>(
      `${this.baseUrl}/map/parcels/search`,
      { params: { provinceId, municipalityId, q: search, limit } }
    );
  }

  getParcelGeometryBySuggestion(provinceId: string, suggestion: MapFeatureParcelSearchSuggestion) {
    return this.http.get<MapFeatureGeometryResponse>(
      `${this.baseUrl}/map/parcels/${provinceId}/geometry`,
      { params: { lpi: suggestion.lpi, parcelType: suggestion.parcelType } }
    );
  }
}

MapFeatureAuthAdapter

export interface MapFeatureAuthAdapter {
  getAccessToken?(): Promise<string | null> | string | null;
  getUserId?(): string | null;
}

Use this when the SDK needs identity context for future auth-aware features or auditing.

MapFeaturePermissionAdapter

export interface MapFeaturePermissionAdapter {
  canAccessFeature?(permission: string): boolean | Promise<boolean>;
}

Use this when the consumer app wants to let the SDK ask whether a feature is allowed.

MapFeatureRendererAdapter

Use this when the consumer wants the SDK to drive a custom map vendor instead of Leaflet.

Methods:

  • mount(container)
  • setViewport(viewport)
  • setZoomPolicy(policy)
  • setLayerVisibility(layerId, visible)
  • setLayerLabelsVisible(layerId, visible)
  • setLayerStyle(layerId, style)
  • renderLayer(layerId, geometry, descriptor?)
  • clearLayer(layerId)
  • clearAll()
  • destroy()
  • optional getZoomState()

This is the cleanest integration point for consumers who want to keep their own map canvas but still reuse the SDK data model.

MapFeatureApiClient

Minimal HTTP abstraction:

  • get<TResponse>(url)
  • post<TResponse, TBody>(url, body)

MapFeatureProviderOptions

Options accepted by provideMapSdk(...).

export interface MapFeatureProviderOptions {
  adapter?: MapFeatureAdapter | null;
  rendererAdapter?: MapFeatureRendererAdapter | null;
  runtimeConfig?: Partial<MapFeatureRuntimeConfig> | null;
  httpConfig?: Partial<MapFeatureHttpConfig> | null;
}

MapFeatureAngularAdapter

Angular-specific adapter surface for auth and permission hooks:

  • getAccessToken?()
  • getUserId?()
  • canAccessFeature?(permission)

FeatureEventBus

Lightweight typed event channel for SDK-wide signaling.

export class FeatureEventBus {
  readonly events$: Observable<FeatureSdkEvent>;
  emit(event: FeatureSdkEvent): void;
}

Events

FeatureSdkEvent

Generic event envelope:

export interface FeatureSdkEvent<TPayload = unknown> {
  type: string;
  payload: TPayload;
}

FeatureSdkSelectionEvent

Selection-specific envelope:

export interface FeatureSdkSelectionEvent<TPayload = unknown> extends FeatureSdkEvent<TPayload> {
  type: 'selection';
}

FeatureSdkLayerVisibilityEvent

Emitted when a layer is shown or hidden.

export interface FeatureSdkLayerVisibilityEvent {
  layerId: string;
  visible: boolean;
  reason?: 'legend' | 'zoom' | 'selection' | 'refresh' | 'api' | 'consumer';
}

MapFeatureLayerClickEvent

Emitted when a boundary or parcel feature is clicked.

export interface MapFeatureLayerClickEvent {
  layerId: string;
  kind: string;
  sourceId: string;
  displayName: string;
  featureId?: string | number | null;
  properties: Record<string, unknown>;
  latLng?: [number, number] | null;
}

Event Lifecycle

User action Main SDK events Typical UI update
Select province selection + visibility updates Refresh municipality list, reload legend, refresh overlays
Select municipality selection + visibility updates Focus map, redraw selected boundary, reload parcel scope
Toggle a legend item layerVisibility Show or hide the target boundary or parcel layer
Zoom the map visibility update reason zoom Show or hide zoom-gated layers and labels
Search and select a parcel selection + layer click Render parcel geometry and open popup
Click a boundary or parcel layerClick Open popup with the normalized record data
Refresh map layers visibility update reason refresh Reload current legend and visible geometry

Angular Providers

provideMapSdk(...)

The top-level Angular helper for environment providers.

provideMapSdk({
  runtimeConfig,
  httpConfig,
  adapter,
  rendererAdapter
});

Use it when you want the SDK to be bootstrapped once at the application level.

provideMapFeatureRuntimeConfig(...)

Injects base URL and default legend endpoint values.

provideMapFeatureHttpConfig(...)

Injects the HTTP config override path.

provideMapFeatureAdapter(...)

Registers a custom backend adapter.

provideMapFeatureDataSource(...)

Registers a MapFeatureDataSource directly.

provideMapFeatureRendererAdapter(...)

Registers a custom renderer adapter for headless/custom-map usage.

Injection Tokens

  • MAP_FEATURE_DATA_SOURCE
  • MAP_FEATURE_RUNTIME_CONFIG
  • MAP_FEATURE_HTTP_CONFIG
  • MAP_SDK_RENDERER

UI Components

MapSdkHostComponent

Selector: dw-map-sdk-host

This is the main full-page host that wraps the explorer experience.

Inputs:

  • config
  • adapter
  • includeInactive
  • zoomPolicy
  • themeClass
  • mapContainerId
  • showLegend
  • showSearch
  • defaultProvinceId

Outputs:

  • provinceChange
  • municipalityChange
  • layerVisibilityChange
  • layerClick

Use this component when the SDK should own:

  • data loading
  • map canvas
  • legend rendering
  • search rendering
  • layer visibility rules

MapSdkHostShellComponent

Selector: dw-map-sdk-host-shell

This is the layout shell used by the host. It is useful when you want to compose around the SDK UI pieces but still keep the default explorer shell structure.

Inputs:

  • config
  • adapter
  • headerTitle
  • headerSubtitle
  • hostThemeClass
  • hostMapContainerId
  • provinceOptions
  • municipalityOptions
  • selectedProvinceId
  • selectedMunicipalityId
  • provinceLoading
  • municipalityLoading
  • includeInactive
  • zoom
  • legendResponse
  • mapLoading
  • mapLoadingLabel
  • zoomPolicy
  • showLegend
  • showSearch

Outputs:

  • provinceChange
  • municipalityChange
  • zoomChange
  • layerVisibilityChange
  • layerClick

MapSdkFiltersComponent

Selector: dw-map-sdk-filters

Inputs:

  • provinceOptions
  • municipalityOptions
  • selectedProvinceId
  • selectedMunicipalityId
  • provinceLoading
  • municipalityLoading
  • title
  • subtitle

Outputs:

  • provinceChange
  • municipalityChange

MapSdkLegendPanelComponent

Selector: dw-map-sdk-legend-panel

Inputs:

  • title
  • subtitle
  • groups
  • adminMode

Outputs:

  • legendVisibilityToggle
  • legendActiveToggle
  • legendColorChange

MapSdkParcelSearchComponent

Selector: dw-map-sdk-parcel-search

Inputs:

  • query
  • suggestions
  • loading
  • status
  • placeholder
  • autocompleteOpen
  • activeSuggestionIndex
  • isFocused

Outputs:

  • queryChange
  • focus
  • blur
  • keydown
  • clear
  • suggestionSelect

The suggestionSelect event returns:

{
  suggestion: MapFeatureParcelSearchSuggestion;
  event?: Event | MouseEvent | PointerEvent;
}

MapSdkZoomLayerStatusComponent

Selector: dw-map-sdk-zoom-layer-status

Inputs:

  • zoom
  • policy
  • summary

MapSdkDetailDialogData

The detail dialog is currently represented as a simple data contract:

export interface MapSdkDetailDialogData {
  title: string;
  body: string;
}

Response and DTO Models

These models are part of the public data contract and are useful when the consumer wants to understand the shape of backend responses or typed widget data.

Filter and search models

  • MapFeatureFilterOption
  • used for province and municipality dropdowns
  • fields: id, name, optional code, optional parentId
  • MapFeatureParcelSearchSuggestion
  • represents a parcel suggestion row
  • includes lpi, sgNo, displayLabel, sourceSchema, sourceTable, and location fields
  • MapFeatureParcelSearchResponse
  • contains suggestions and an optional reason

Geometry models

  • MapFeatureGeometryResponse
  • wraps a geometry payload plus status metadata
  • includes layerAvailable, status, reason, minZoom, and featureCollection
  • MapFeatureGeometryFeatureCollection
  • lightweight GeoJSON-style collection wrapper used by the SDK

Legend models

  • MapLegendResponse
  • the backend legend response shape
  • MapLegendGroupApi
  • backend legend group DTO
  • MapLegendEntryApi
  • backend legend entry DTO
  • MapLegendMatching
  • matching keys that determine when a legend entry applies
  • MapLegendStyling
  • backend styling rules for color, opacity, and icon
  • MapFeatureLegendGroup
  • normalized group used by the UI widgets
  • MapFeatureLegendItem
  • normalized legend item used by the UI widgets

Default Runtime Behavior

If a consumer does not override anything, the SDK will:

  • load provinces and municipalities from its configured backend
  • load legends from the configured backend
  • show the full-page explorer host
  • apply the default theme token set
  • enforce zoom thresholds for boundaries and parcels
  • keep parcel rendering gated behind the parcel zoom policy

Default Backend URLs

The SDK uses its own backend config and does not require the consumer app to fetch map payloads directly.

  • local: http://localhost:8080/api
  • production: https://api-warehouse.idti.dev/api

Template Extension Points

The SDK currently does not expose native content projection slots such as custom <ng-template> inputs.

Instead, consumers extend the SDK by composing the exported Angular widgets in their own wrapper component.

Example:

<section class="my-map-page">
  <header class="my-map-page__header">
    <app-my-toolbar></app-my-toolbar>
  </header>

  <dw-map-sdk-filters
    [provinceOptions]="provinceOptions"
    [municipalityOptions]="municipalityOptions"
    [selectedProvinceId]="selectedProvinceId"
    [selectedMunicipalityId]="selectedMunicipalityId"
    (provinceChange)="onProvinceChange($event)"
    (municipalityChange)="onMunicipalityChange($event)"
  />

  <dw-map-sdk-host
    [config]="mapFeatureConfig"
    [adapter]="mapAdapter"
    [showLegend]="true"
    [showSearch]="true"
    (layerClick)="onLayerClick($event)"
  />
</section>

If you later want fully projected slots, treat that as a future SDK enhancement rather than a current API.

Theming

Consumers can override the SDK tokens through a wrapper class:

.smoc-map-theme {
  --map-feature-surface: #ffffff;
  --map-feature-surface-elevated: #f6f8fc;
  --map-feature-border: rgba(15, 23, 42, 0.12);
  --map-feature-text: #0f172a;
  --map-feature-muted-text: #475569;
  --map-feature-accent: #0f766e;
  --map-feature-accent-strong: #115e59;
  --map-feature-chip-surface: rgba(15, 118, 110, 0.12);
  --map-feature-chip-text: #0f172a;
}

Build and Pack

From H:\workspace\data-warehouse\frontend:

npm run build:lib
npm pack

The package name is:

@agastyadreamspty/map-sdk

Consumer Guidance

Use the full host if you want the SDK to own the whole map explorer experience.

Use the widgets and adapters if you want:

  • only filters
  • only legend rendering
  • only parcel search
  • only layer status
  • a custom map vendor
  • custom event handling
  • app-specific layout and chrome

The SDK should remain the source of truth for:

  • API fetch behavior
  • legend gating
  • search gating
  • zoom thresholds
  • popup data normalization
  • layer visibility decisions
  • theming tokens

Troubleshooting

Layers do not appear after zooming

  • Confirm the active zoom policy still allows the layer to render.
  • Confirm the selected province and municipality are valid for the current API response.
  • Confirm the consumer is not hiding the layer via legend visibility.

Legend or search appears behind the map

  • Put the SDK host and overlay containers in a stacking context above the canvas.
  • Make sure the consumer wrapper does not reset the SDK z-index tokens.
  • Keep search and legend panels outside any container that clips overflow.

Search suggestions appear but clicking them does nothing

  • Confirm the consumer is using the SDK click handler, not a mouse-down override.
  • Confirm the adapter implements getParcelGeometryBySuggestion(...).
  • Confirm the parcel geometry endpoint returns a non-empty feature collection.
  • Confirm the active province and municipality are passed into the adapter request.
  • Confirm the backend response matches the current filter scope.
  • Confirm the consumer is not reusing cached popup data from a previous selection.