@emuanalytics/flow-rdf-core 4.0.11 → 4.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/index.d.mts +2 -2
  2. package/dist/index.d.ts +2 -2
  3. package/dist/lib/map/flow-core-map.mjs +36 -12
  4. package/dist/lib/map/plugins/annotations/annotation.events.mjs +9 -0
  5. package/dist/lib/map/plugins/annotations/annotation.plugin.mjs +134 -2
  6. package/dist/lib/map/plugins/data-join.plugin.mjs +42 -1
  7. package/dist/lib/map/plugins/export/export.plugin.mjs +14 -0
  8. package/dist/lib/map/plugins/hover-effect.plugin.mjs +9 -0
  9. package/dist/lib/map/plugins/index.d.mts +738 -33
  10. package/dist/lib/map/plugins/index.d.ts +738 -33
  11. package/dist/lib/map/plugins/index.mjs +0 -1
  12. package/dist/lib/map/plugins/keyboard-shortcut-manager.mjs +6 -0
  13. package/dist/lib/map/plugins/map-plugin-base.mjs +5 -0
  14. package/dist/lib/map/plugins/plugin-manager.mjs +97 -0
  15. package/dist/lib/map/plugins/popup.plugin.mjs +12 -0
  16. package/dist/lib/map/plugins/selection/selection.events.mjs +3 -0
  17. package/dist/lib/map/plugins/selection/selection.plugin.mjs +75 -4
  18. package/dist/lib/map/plugins/selection/source-selection.mjs +50 -2
  19. package/dist/lib/map/support/map-events.mjs +19 -0
  20. package/dist/lib/map/support/map-popup.mjs +30 -5
  21. package/dist/lib/utils/index.d.mts +1 -0
  22. package/dist/lib/utils/index.d.ts +1 -0
  23. package/dist/package.json.mjs +1 -1
  24. package/dist/shared/{flow-rdf-core.08156446.d.mts → flow-rdf-core.3da5bd49.d.mts} +448 -17
  25. package/dist/shared/{flow-rdf-core.08156446.d.ts → flow-rdf-core.3da5bd49.d.ts} +448 -17
  26. package/package.json +2 -1
  27. package/dist/lib/map/plugins/url-sync.plugin.mjs +0 -55
@@ -1940,6 +1940,7 @@ declare class MapDataSource {
1940
1940
  private expandSrc;
1941
1941
  }
1942
1942
 
1943
+ /** Generates a new type by making a specified property of the original type `optional`. */
1943
1944
  type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
1944
1945
 
1945
1946
  declare class FlowMapError extends FlowCoreError {
@@ -1951,20 +1952,36 @@ interface MapSourceIdentifier {
1951
1952
  source: string;
1952
1953
  sourceLayer?: string;
1953
1954
  }
1955
+ /**
1956
+ * A MapFeatureIdentifier uniquely identifies a map feature by its ID and source.
1957
+ *
1958
+ * Used to uniquely identify a map feature when displaying popups or when setting/getting map feature state (see {@link FlowCoreMap.setFeatureState} and {@link FlowCoreMap.getFeatureState}).
1959
+ */
1954
1960
  interface MapFeatureIdentifier {
1961
+ /** Unique feature ID */
1955
1962
  id: MapFeatureId;
1963
+ /** ID of associated {@link MapDataSource} */
1956
1964
  source: string;
1965
+ /** Map data source layer. Only required for custom vector data sources. */
1957
1966
  sourceLayer?: string;
1958
1967
  }
1968
+ /** A map feature associated with a {@link MapDataSource}. */
1959
1969
  interface MapFeature {
1970
+ /** Feature geometry */
1960
1971
  geometry: GeoJSON.Geometry;
1972
+ /** Unique feature ID */
1961
1973
  id?: MapFeatureId;
1974
+ /** ID of associated {@link MapLayer}. */
1962
1975
  layer?: string;
1976
+ /** Feature properties */
1963
1977
  properties: {
1964
1978
  [key: string]: any;
1965
1979
  };
1980
+ /** ID of associated {@link MapDataSource} */
1966
1981
  source: string;
1982
+ /** Map data source layer. Only required for custom vector data sources. */
1967
1983
  sourceLayer?: string;
1984
+ /** Additional state associated with the feature. See {@link FlowCoreMap.setFeatureState}. */
1968
1985
  state?: {
1969
1986
  [key: string]: any;
1970
1987
  };
@@ -2019,7 +2036,7 @@ interface MapPaddingOptions {
2019
2036
  }
2020
2037
 
2021
2038
  /**
2022
- * This interface defines all event types emitted {@link FlowCoreMap} and
2039
+ * This interface defines all event types emitted by {@link FlowCoreMap} and
2023
2040
  * the type of the corresponding event handler.
2024
2041
  *
2025
2042
  * {@link FlowCoreMap} extends [EventEmitter](https://github.com/dashed/EventEmitter3) to provide
@@ -2117,15 +2134,41 @@ interface MapEventTypes {
2117
2134
  */
2118
2135
  error: (event: FlowMapError) => void;
2119
2136
  }
2137
+ /** The set of all map event types. */
2120
2138
  type MapEventType = keyof MapEventTypes;
2139
+ /**
2140
+ * Base class providing a common interface for all map events.
2141
+ *
2142
+ * @group Events
2143
+ *
2144
+ * @typeParam EventType The type of the event.
2145
+ * @typeParam TOrig The type of the original MapLibre event.
2146
+ */
2121
2147
  declare class MapEvent<EventType extends string = MapEventType, TOrig = unknown> {
2148
+ /** Event type */
2122
2149
  type: EventType;
2150
+ /** Map instance that generated event */
2123
2151
  map: FlowCoreMap;
2152
+ /** Original MapLibre event */
2124
2153
  originalEvent?: TOrig;
2154
+ /** Creates an event from an original MapLibre event. */
2125
2155
  static fromMaplibreEvent(type: string, map: FlowCoreMap, maplibreEvent: MapLibreEvent): MapEvent<any, unknown>;
2156
+ /**
2157
+ * Constructs a map event.
2158
+ *
2159
+ * @param type Event type
2160
+ * @param map Map instance that generated the event
2161
+ * @param originalEvent Original MapLibre event that triggered the event
2162
+ */
2126
2163
  constructor(type: EventType, map: FlowCoreMap, originalEvent?: TOrig);
2127
2164
  }
2165
+ /** Mouse event types. */
2128
2166
  type MapMouseEventType = 'click' | 'dblClick' | 'mouseMove' | 'mouseOut';
2167
+ /**
2168
+ * Mouse event class providing a common interface for all mouse events.
2169
+ *
2170
+ * @group Events
2171
+ */
2129
2172
  declare class MapMouseEvent extends MapEvent<MapMouseEventType, MouseEvent> {
2130
2173
  /**
2131
2174
  * The pixel coordinates of the mouse cursor, relative to the map and measured from the top left corner.
@@ -2135,23 +2178,48 @@ declare class MapMouseEvent extends MapEvent<MapMouseEventType, MouseEvent> {
2135
2178
  * The geographic location on the map of the mouse cursor.
2136
2179
  */
2137
2180
  lngLat: [number, number];
2181
+ /**
2182
+ * Features found at the mouse coordinate. Features are ordered by map layer with features higher in the layer stack appearing first in the `features` array.
2183
+ * Features from non-interactive layers are excluded.
2184
+ */
2138
2185
  features: MapFeature[];
2139
2186
  static fromMaplibreMouseEvent(type: MapMouseEventType, maplibreMouseEvent: MapMouseEvent$1, map: FlowCoreMap, features: MapFeature[]): MapMouseEvent;
2140
2187
  constructor(type: MapMouseEventType, map: FlowCoreMap, point: [number, number], lngLat: [number, number], features: MapFeature[], originalEvent: MouseEvent);
2141
2188
  }
2189
+ /** Source event types. */
2142
2190
  type SourceEventType = 'sourceAdded' | 'sourceRemoved' | 'beforeSourceAdded' | 'beforeSourceRemoved' | 'sourceFeatureState';
2191
+ /**
2192
+ * Source event class providing a common interface for all source events.
2193
+ *
2194
+ * @group Events
2195
+ */
2143
2196
  declare class MapSourceEvent extends MapEvent<SourceEventType> {
2197
+ /** Map data source ID */
2144
2198
  source: string;
2145
2199
  constructor(type: SourceEventType, map: FlowCoreMap, source: string);
2146
2200
  }
2201
+ /** Loading event types. */
2147
2202
  type LoadingEventType = 'loading';
2203
+ /**
2204
+ * Loading event class providing a common interface for all loading events.
2205
+ *
2206
+ * @group Events
2207
+ */
2148
2208
  declare class MapLoadingEvent extends MapEvent<LoadingEventType> {
2209
+ /** Indicates whether the map is currently loading data. */
2149
2210
  loading: boolean;
2150
2211
  constructor(map: FlowCoreMap, loading: boolean);
2151
2212
  }
2213
+ /**
2214
+ * Style change event types.
2215
+ *
2216
+ * @group Events
2217
+ */
2152
2218
  type StyleChangeEventType = 'beforeStyleChanged' | 'styleChanged';
2153
2219
  declare class MapStyleChangeEvent extends MapEvent<StyleChangeEventType> {
2220
+ /** Old map style before changes. */
2154
2221
  oldStyle: MapStyleSpecification;
2222
+ /** New map style after changes. */
2155
2223
  newStyle: MapStyleSpecification;
2156
2224
  constructor(type: StyleChangeEventType, map: FlowCoreMap, oldStyle: MapStyleSpecification, newStyle: MapStyleSpecification);
2157
2225
  }
@@ -2166,23 +2234,127 @@ interface RemoveListener {
2166
2234
  (): void;
2167
2235
  }
2168
2236
 
2237
+ /**
2238
+ * The plugin manager is responsible for managing the lifecycle of map plugins and forwarding map events to plugin handlers. Each FlowCoreMap
2239
+ * instance has a plugin manager associated with it, which is created when the map is initialized. The map instance provides the {@link FlowCoreMap.usePlugin}
2240
+ * and {@link FlowCoreMap.getPlugin} for interacting with the plugin manager.
2241
+ *
2242
+ * Typically, it is not necessary to interact with the plugin manager directly unless you are implementing a custom plugin.
2243
+ */
2169
2244
  declare class PluginManager {
2170
2245
  private _map;
2171
2246
  private _keyboardShortcutManager;
2172
2247
  private _plugins;
2173
2248
  private _initialized;
2174
2249
  private _exclusivePlugins;
2250
+ /** Returns the parent FlowCoreMap instance. */
2175
2251
  get map(): FlowCoreMap<StateStore>;
2252
+ /**
2253
+ * Constructs a plugin manager for the provided FlowCoreMap instance. Note that plugin manager construction is performed automatically when a
2254
+ * map is created.
2255
+ */
2176
2256
  constructor(map: FlowCoreMap);
2257
+ /**
2258
+ * Register a plugin for use with a map. This will create an instance of the plugin and call its `initialize` method.
2259
+ *
2260
+ * Note that this is typically called using the `usePlugin` method of a {@link FlowCoreMap} instance.
2261
+ *
2262
+ * @example
2263
+ * Register the HoverEffectPlugin for use with a map:
2264
+ ```js
2265
+ import { HoverEffectPlugin } from '@emuanalytics/flow-rdf-core/plugins';
2266
+ map.usePlugin(HoverEffectPlugin);
2267
+ ```
2268
+ *
2269
+ * @param plugin The plugin constructor to register. This must be a class that extends {@link MapPluginBase}
2270
+ * @param options Plugin-specific options (if any) to pass to the plugin constructor
2271
+ * @typeParam T Type of the plugin being registered
2272
+ * @returns The registered plugin instance
2273
+ */
2177
2274
  usePlugin<T extends MapPluginBase>(plugin: PluginConstructor<T>, options?: PluginOptionsType<T>): T;
2275
+ /**
2276
+ * Retrieve a plugin previously registered with a map. This is necessary to access plugin-specific methods or properties.
2277
+ *
2278
+ * Note that this is typically called using the {@link FlowCoreMap.getPlugin} method.
2279
+ *
2280
+ * @example
2281
+ * Retrieve the SelectionPlugin and clear all selections for a specified map data source:
2282
+ ```js
2283
+ const selectionPlugin = map.getPlugin(SelectionPlugin);
2284
+ selectionPlugin.selectFeatures('data-source', []);
2285
+ ```
2286
+ *
2287
+ * @param plugin The plugin to retrieve (identified by the plugin constructor or name)
2288
+ * @typeParam T Type of the plugin being retrieved
2289
+ * @returns The registered plugin instance
2290
+ */
2178
2291
  getPlugin<T extends MapPluginBase = MapPluginBase>(pluginOrName: PluginConstructor<T> | string): T;
2292
+ /**
2293
+ * Unregister the specified plugin.
2294
+ *
2295
+ * @param pluginOrName The plugin to unregister (identified by the plugin constructor or name)
2296
+ * @returns The plugin manager instance to allow method chaining
2297
+ * @typeParam T Type of the plugin being unregistered
2298
+ */
2179
2299
  removePlugin<T extends MapPluginBase>(pluginOrName: PluginConstructor<T> | string): this;
2300
+ /**
2301
+ * Unregister all plugins.
2302
+ *
2303
+ * @returns The plugin manager instance to allow method chaining
2304
+ */
2180
2305
  removeAllPlugins(): this;
2306
+ /**
2307
+ * Mark the specified plugin as 'exclusive'. This disables other non-exclusive plugins until the {@link removeExclusivePlugin} method is called.
2308
+ *
2309
+ * This is used by the annotation plugin to disable map selection and hover effects when annotation features are being drawn by the user.
2310
+ */
2181
2311
  setExclusivePlugin(plugin: MapPluginBase): this;
2312
+ /**
2313
+ * Remove the 'exclusive' flag from the specified plugin. This allows other non-exclusive plugins to receive events again.
2314
+ */
2182
2315
  removeExclusivePlugin(plugin: MapPluginBase): this;
2316
+ /**
2317
+ * This method is called by plugins to register keyboard shortcuts with the {@link KeyboardShortcutManager}.
2318
+ *
2319
+ * @example
2320
+ * Register keyboard shortcuts from a map plugin:
2321
+ ```js
2322
+ // Add shortcuts
2323
+ this.removeShortcuts = this.pluginManager.addKeyboardShortcuts({
2324
+ 'Enter,Escape': () => this.commit(),
2325
+ KeyP: () => this.createFeature('Polygon'),
2326
+ KeyL: () => this.createFeature('LineString'),
2327
+ KeyM: () => this.createFeature('Point'),
2328
+ KeyC: () => this.createFeature('Circle')
2329
+ });
2330
+
2331
+ ...
2332
+
2333
+ // Remove shortcuts
2334
+ this.removeShortcuts();
2335
+ ```
2336
+ *
2337
+ * @param keyboardShortcuts Key bindings to register
2338
+ * @param priority Key binding priority
2339
+ * @returns Function that can be called to remove the keyboard shortcuts
2340
+ */
2183
2341
  addKeyboardShortcuts(keyboardShortcuts: Bindings, priority?: number): RemoveListener;
2342
+ /**
2343
+ * This method is called internally to forward map events to active plugin handlers.
2344
+ *
2345
+ * @param eventName The event to forward
2346
+ * @param args Event arguments
2347
+ */
2184
2348
  forwardEvent<T extends keyof MapEventTypes>(eventName: T, ...args: Parameters<MapEventTypes[T]>): void;
2349
+ /**
2350
+ * This method is called internally to forward map style change events to active plugin handlers.
2351
+ *
2352
+ * @param eventName The event to forward
2353
+ */
2185
2354
  forwardStyleChangeEvent(event: MapStyleChangeEvent): MapStyleSpecification;
2355
+ /**
2356
+ * This method is called internally to forward exclusivity changes to registered plugins.
2357
+ */
2186
2358
  private forwardSetExclusivePlugin;
2187
2359
  }
2188
2360
 
@@ -2193,30 +2365,65 @@ type EventHandlers<T> = {
2193
2365
  [P in keyof T as P extends string ? `handle${Capitalize<P>}` : never]+?: T[P];
2194
2366
  };
2195
2367
  interface MapPluginBase<Options = any, Events extends EventEmitter.ValidEventTypes = string | symbol> {
2368
+ /** Implemented by a plugin to perform initialization tasks. This method is called by the {@link PluginManager} when a plugin is created. */
2196
2369
  initialize?(): void;
2370
+ /** Implemented by a plugin to perform clean-up tasks. This method is called by the {@link PluginManager} when a plugin is destroyed. */
2197
2371
  destroy?(): void;
2372
+ /** Implemented by a plugin to handle map click events. */
2198
2373
  handleClick?(event: MapMouseEvent): void;
2374
+ /** Implemented by a plugin to handle map double-click events. */
2199
2375
  handleDblClick?(event: MapMouseEvent): void;
2376
+ /** Implemented by a plugin to handle mouse move events. */
2200
2377
  handleMouseMove?(event: MapMouseEvent): void;
2378
+ /** Implemented by a plugin to handle mouse out events. */
2201
2379
  handleMouseOut?(event: MapEvent): void;
2380
+ /** Implemented by a plugin to handle map move end events. */
2202
2381
  handleMoveEnd?(event: MapEvent): void;
2382
+ /** Implemented by a plugin to handle source added events. */
2203
2383
  handleSourceAdded?(event: MapSourceEvent): void;
2384
+ /** Implemented by a plugin to handle source removed events. */
2204
2385
  handleSourceRemoved?(event: MapSourceEvent): void;
2386
+ /** Implemented by a plugin to handle before-source-added events. */
2205
2387
  handleBeforeSourceAdded?(event: MapSourceEvent): void;
2388
+ /** Implemented by a plugin to handle before-source-removed events. */
2206
2389
  handleBeforeSourceRemoved?(event: MapSourceEvent): void;
2390
+ /** Implemented by a plugin to handle feature state events.*/
2207
2391
  handleSourceFeatureState?(event: MapSourceEvent): void;
2392
+ /** Implemented by a plugin to handle before-style-changed events. */
2208
2393
  handleBeforeStyleChanged?(event: MapStyleChangeEvent): MapStyleSpecification | undefined;
2394
+ /** Implemented by a plugin to handle style changed events. */
2209
2395
  handleStyleChanged?(event: MapStyleChangeEvent): void;
2396
+ /** Implemented by a plugin to handle map loading events. */
2210
2397
  handleLoading?(event: MapLoadingEvent): void;
2398
+ /** Implemented by a plugin to handle map loading events. */
2211
2399
  handleSetExclusivePlugin?(exclusivePlugins: MapPluginBase[]): void;
2400
+ /** Implemented by a plugin to handle map error events. */
2212
2401
  handleError?(error: FlowMapError): void;
2213
2402
  }
2403
+ /**
2404
+ * Base class for map plugins. This provides a common interface for all map plugins and defines the available handlers that
2405
+ * a plugin can implement. The {@link PluginManager} is responsible for managing the lifecycle of plugins and calling the appropriate handlers when events occur.
2406
+ *
2407
+ * Flo.w RDF Core provides a number of built-in plugins that extend the functionality of the map, such as the {@link HoverEffectPlugin} and {@link PopupPlugin}.
2408
+ * Custom plugins can be created by extending {@link MapPluginBase} and implementing the desired handlers.
2409
+ *
2410
+ * @typeParam Options Type for plugin options. This is used to define the plugin-specific options that can be passed to the plugin when it is created.
2411
+ * @typeParam Events Type for plugin events. This is used to define the events that the plugin can emit.
2412
+ *
2413
+ * @noInheritDoc
2414
+ */
2214
2415
  declare abstract class MapPluginBase<Options extends object | undefined = any, Events extends EventEmitter.ValidEventTypes = string | symbol> extends EventEmitter<Events> {
2215
2416
  private _pluginManager;
2216
2417
  options: Options;
2418
+ /**
2419
+ * The map instance associated with this plugin.
2420
+ */
2217
2421
  get map(): FlowCoreMap<StateStore>;
2422
+ /** The {@link PluginManager} that is managing this plugin. */
2218
2423
  get pluginManager(): PluginManager;
2424
+ /** The name of this plugin. This is used as a unique identifier when registering and retrieving a plugin. */
2219
2425
  abstract readonly name: string;
2426
+ /** Constructs an plugin instance. Note this this is called internally when registering a plugin. */
2220
2427
  constructor(pluginManager: PluginManager, options?: Options);
2221
2428
  }
2222
2429
 
@@ -2236,7 +2443,31 @@ interface ImageRegistryEntry {
2236
2443
  *
2237
2444
  * The `ImageRegistry` is a container for map icon images.
2238
2445
  *
2239
- * Images can be registered and retrieved by ID.
2446
+ * Registered images can be used in `symbol` map layers by using the registered `is` as the `iconImage` style property.
2447
+ *
2448
+ * :::warning
2449
+ * To fully support recoloring and halo effects, the source image should be a SDF (signed distance field) image.
2450
+ * :::
2451
+ *
2452
+ * @example
2453
+ * Register and use a map icon image:
2454
+ ```ts
2455
+ // Register the image
2456
+ map.registerImage('aircraft','https://flow-cdn.emu-analytics.net/centralised-airports/vehicles/aircraft.png', 50, 50, 2, true);
2457
+
2458
+ // Use the image in a map layer
2459
+ const aircraftIcons = new MapLayer({
2460
+ id: 'aircraft_icons',
2461
+ type: 'symbol',
2462
+ source: 'aircraft_source',
2463
+ style: layerStyle('symbol')
2464
+ .iconImage('aircraft')
2465
+ .iconColor('red')
2466
+ });
2467
+ ```
2468
+ *
2469
+ *
2470
+ *
2240
2471
  */
2241
2472
  declare class ImageRegistry {
2242
2473
  private _registry;
@@ -2302,6 +2533,16 @@ interface FeatureStreamOptions {
2302
2533
  * A observable stream of map feature data. Subscribe to an instance of this class to receive
2303
2534
  * updates when map feature data changes.
2304
2535
  *
2536
+ * :::warning
2537
+ * If the map is panned or zoomed by the user, features that are no longer visible may be unloaded
2538
+ * from the map. If a feature that is being tracked is unloaded, it will be removed from
2539
+ * feature stream updates.
2540
+ *
2541
+ * If it is essential to track a feature even when it is unloaded, consider using a Flo.w reactive
2542
+ * query independently of map data.
2543
+ *
2544
+ * :::
2545
+ *
2305
2546
  * See {@link FlowCoreMap.featureStream } for usage information.
2306
2547
  */
2307
2548
  declare class MapFeatureStream {
@@ -2363,7 +2604,12 @@ declare class MapFeatureStream {
2363
2604
  interface MapOptions<TState extends StateStore = StateStore> extends Omit<MapOptions$1, 'style'> {
2364
2605
  /** Unique map identifier. */
2365
2606
  id?: string;
2366
- /** Base map style */
2607
+ /**
2608
+ * Base map style.
2609
+ *
2610
+ * Specify a pre-defined base style identifier or supply a complete Maplibre style specification.
2611
+ *
2612
+ */
2367
2613
  baseStyle?: string | MapStyleSpecification;
2368
2614
  /** Map container selector or element. This specifies where in the DOM the map will be inserted. */
2369
2615
  container: string | HTMLElement;
@@ -2380,8 +2626,58 @@ interface MapOptions<TState extends StateStore = StateStore> extends Omit<MapOpt
2380
2626
  contextId?: string;
2381
2627
  }
2382
2628
  /**
2629
+ * The core map class providing a high-level declarative API for creating and updating interactive maps.
2630
+ *
2631
+ * {@link FlowCoreMap} wraps the [Maplibre GL JS](https://maplibre.org/maplibre-gl-js/docs/) API to add reactive updating
2632
+ * and declarative map data sources and layers. FlowCoreMap integrates with Flo.w reactive queries and reactive state to
2633
+ * ensure that the map is in sync with the underlying data.
2383
2634
  *
2635
+ * :::info
2636
+ * FlowCoreMap provides basic map functionality. Other features such as popups, selection, and exporting map images are
2637
+ * provided by plugins. See {@link FlowCoreMap.usePlugin} for more information.
2638
+ * :::
2384
2639
  *
2640
+ * @example
2641
+ * Creating a basic map:
2642
+ ```ts
2643
+ import { FlowCoreMap } from '@emuanalytics/flow-rdf-core';
2644
+
2645
+ // Create a new map instance
2646
+ const map = new FlowCoreMap({
2647
+ id: 'air-quality-map',
2648
+ container: '#map-container',
2649
+ baseStyle: 'fjord',
2650
+ });
2651
+
2652
+ // Wait for the map to be initialized
2653
+ map.initialized.then(() => {
2654
+
2655
+ // Create a map data source that loads geospatial data from the `airquality` Flo.w dataset.
2656
+ const source = new MapDataSource({
2657
+ id: 'airquality-source',
2658
+ type: 'vector',
2659
+ src: 'airquality',
2660
+ featureId: 'label'
2661
+ });
2662
+
2663
+ // Create a map layer that uses the data source and displays circles for each feature.
2664
+ const circleLayer = new MapLayer({
2665
+ id: 'circle-layer',
2666
+ type: 'circle',
2667
+ source: 'airquality-source',
2668
+ style: layerStyle('circle')
2669
+ .circleColor('red)
2670
+ .circleRadius(10)
2671
+ .build()
2672
+ });
2673
+
2674
+ // Add the data source and layer to the map.
2675
+ map.transaction(() => {
2676
+ map.addSource(source);
2677
+ map.addLayer(circleLayer);
2678
+ });
2679
+ });
2680
+ ```
2385
2681
  */
2386
2682
  declare class FlowCoreMap<TState extends StateStore = StateStore> extends EventEmitter$1<MapEventTypes> {
2387
2683
  private static _defaultOptions;
@@ -2627,7 +2923,31 @@ declare class FlowCoreMap<TState extends StateStore = StateStore> extends EventE
2627
2923
  * Register a map icon image.
2628
2924
  *
2629
2925
  * The image can be used on [symbol-type map layers](/flow-rdf-core/layer-reference/symbol) by specifying the image ID
2630
- * as the [`icon-image`](/flow-rdf-core/layer-reference/symbol#icon-image) property.
2926
+ * as the [`iconImage`](/flow-rdf-core/layer-reference/symbol#icon-image) property.
2927
+ *
2928
+ * :::warning
2929
+ * To fully support recoloring and halo effects, the source image should be a SDF (signed distance field) image.
2930
+ *
2931
+ * See [MapLibre Sprite](https://maplibre.org/maplibre-style-spec/sprite/#sprite-source-format) documentation.
2932
+ * :::
2933
+ *
2934
+ * @example
2935
+ * Register and use a map icon image:
2936
+ ```ts
2937
+ // Register the image
2938
+ map.registerImage('aircraft','https://flow-cdn.emu-analytics.net/centralised-airports/vehicles/aircraft.png', 50, 50, 2, true);
2939
+
2940
+ // Use the image in a map layer
2941
+ const aircraftIcons = new MapLayer({
2942
+ id: 'aircraft_icons',
2943
+ type: 'symbol',
2944
+ source: 'aircraft_source',
2945
+ style: layerStyle('symbol')
2946
+ .iconImage('aircraft')
2947
+ .iconColor('red')
2948
+ });
2949
+ ```
2950
+ *
2631
2951
  *
2632
2952
  * @param id Image ID.
2633
2953
  * @param src Image source URL.
@@ -2796,32 +3116,110 @@ declare class FlowCoreMap<TState extends StateStore = StateStore> extends EventE
2796
3116
  private updateMapStyle;
2797
3117
  }
2798
3118
 
3119
+ /**
3120
+ * A template function for rendering popup content. The function receives the associated
3121
+ * map feature and the reactive state store as arguments. The function can reference
3122
+ * feature properties and reactive state properties to render the popup content.
3123
+ *
3124
+ * The function should return popup content in one of the following formats:
3125
+ * - An HTML string (set as the innerHTML of the popup)
3126
+ * - An HTML node (appended to the popup)
3127
+ * - A [lit-html](https://lit.dev/docs/v1/lit-html/introduction/) template
3128
+ *
3129
+ * The template function is called reactively whenever the feature or state changes to
3130
+ * re-render the popup content. If a lit-html template is returned, the popup will be re-rendered
3131
+ * efficiently using a minimal set of DOM updates.
3132
+ *
3133
+ * @param feature The map feature associated with the popup
3134
+ * @param state The reactive state store to access reactive properties
3135
+ *
3136
+ */
2799
3137
  type MapPopupTemplateFn<TState extends StateStore = StateStore> = (feature: MapFeature | null, state: TState) => string | Node | lit.TemplateResult;
3138
+ /** Popup events emitted by {@link MapPopup} */
2800
3139
  interface MapPopupEvents {
2801
3140
  closed: (popup: MapPopup) => void;
2802
3141
  }
2803
3142
  /**
2804
- * [[MapPopup]] options.
3143
+ * Creation options for a {@link MapPopup}.
2805
3144
  */
2806
3145
  interface MapPopupOptions {
2807
3146
  /** Specify a CSS class to add to the popup. */
2808
3147
  class?: string;
2809
- /** Enable 'close' button. */
3148
+ /** Enable the popup's 'close' button. */
2810
3149
  closeButton?: boolean;
2811
- /** Enable closing popup on click on map. */
3150
+ /** Enable closing the popup when the user clicks the map. */
2812
3151
  closeOnClick?: boolean;
2813
- /** Enable closing pop when map is moved. */
3152
+ /** Enable closing the popup when the map is moved. */
2814
3153
  closeOnMove?: boolean;
2815
- /** Specify popup content as HTML string or HTML node. */
3154
+ /** Specify the popup content as an HTML string, HTML node or a template function. */
2816
3155
  content: string | Node | MapPopupTemplateFn;
2817
3156
  /** Maximum width of popup in CSS units. */
2818
3157
  maxWidth?: string;
3158
+ /** Enable repositioning the popup when its associated map feature moves. (default true) */
2819
3159
  trackFeature?: boolean;
2820
3160
  }
2821
3161
  /**
2822
- * Core functionality for Flo.w map popups.
3162
+ * A {@link MapPopup} instance is used to display information about a map feature as a popup on a {@link FlowCoreMap}. The content of the popup
3163
+ * can be defined as static HTML or a template function that has access to the map feature's properties and the reactive state store.
3164
+ *
3165
+ * ## Rendering popup content
3166
+ *
3167
+ * Popup content can be defined at time of creation in one of the following ways:
3168
+ * - An HTML string
3169
+ * - An HTML node
3170
+ * - A template function that returns one of the above **or** a [lit-html](https://lit.dev/docs/v1/lit-html/introduction/) template
3171
+ *
3172
+ * If content is provided using a template function, the function is called reactively whenever the associated map feature or state changes.
3173
+ * The popup will be re-rended using the updated content returned from the template function. If using a lit-html template, the popup will be re-rendered
3174
+ * efficiently using a minimal set of DOM updates. If the template function returns a static HTML string or node, the popup content will be replaced with the
3175
+ * new content.
3176
+ *
3177
+ * ## Automatic feature tracking
2823
3178
  *
3179
+ * A popup is usually anchored to its associated map feature, which is specified when opening the popup. Following a map data source update, if the feature has
3180
+ * moved then the popup will be repositioned to the new location. This is enabled by default using the `trackFeature` option. Set `trackFeature` to `false` to disable
3181
+ * this behavior.
2824
3182
  *
3183
+ * :::info
3184
+ * It is usually more convenient to use the {@link PopupPlugin} to create and manage popups automatically when features are selected by the user.
3185
+ * {@link MapPopup} can be used directly for custom use cases.
3186
+ * :::
3187
+ *
3188
+ * @example
3189
+ * Create a popup and open manually at a specific location:
3190
+ ```js
3191
+ import { MapPopup } from '@emuanalytics/flow-rdf-core';
3192
+
3193
+ const popup = new MapPopup(map, {
3194
+ content: 'Hello World',
3195
+ closeButton: true,
3196
+ maxWidth: '200px'
3197
+ });
3198
+
3199
+ popup.open([-1, 51.5]);
3200
+ ...
3201
+ popup.close();
3202
+ ```
3203
+ *
3204
+ * Create a popup following a mouse click event to track a map feature:
3205
+ ```js
3206
+ import { MapPopup, html } from '@emuanalytics/flow-rdf-core';
3207
+
3208
+ map.on('click', (event) => {
3209
+ if (event.features.length > 0) {
3210
+ // Feature clicked
3211
+ const feature = event.features[0];
3212
+ const popup = new MapPopup(event.map, {
3213
+ // Content specified as a lit-html template function
3214
+ content: (feature) => html`Clicked on ${feature?.properties.name}`,
3215
+ closeButton: true
3216
+ });
3217
+
3218
+ // Open the popup at location of mouse click and attach it to the clicked feature
3219
+ popup.open(event);
3220
+ }
3221
+ });
3222
+ ```
2825
3223
  */
2826
3224
  declare class MapPopup extends EventEmitter$1<MapPopupEvents> {
2827
3225
  readonly map: FlowCoreMap;
@@ -2832,35 +3230,68 @@ declare class MapPopup extends EventEmitter$1<MapPopupEvents> {
2832
3230
  private _maplibrePopup;
2833
3231
  private _featureStreamDisposer?;
2834
3232
  /**
2835
- * Constructs a new `MapPopup` instance.
3233
+ * Constructs a new {@link MapPopup} instance.
2836
3234
  *
2837
- * This is called by the `FlowMap::openPopup` method.
3235
+ * Typically, a popup is created by interacting with the PopupPlugin or SelectionPlugin rather than instantiating a popup directly.
2838
3236
  *
2839
- * @param map Parent Flo.w map.
2840
- * @param options Popup options.
3237
+ * @param map Parent map
3238
+ * @param options Popup options
2841
3239
  */
2842
3240
  constructor(map: FlowCoreMap, options: MapPopupOptions);
3241
+ /**
3242
+ * Get the map feature associated with the popup.
3243
+ */
2843
3244
  get feature(): MapFeatureIdentifier | undefined;
2844
3245
  /**
2845
3246
  * Close the popup.
2846
3247
  */
2847
3248
  close(): void;
2848
3249
  /**
2849
- * Move the popup to a new location.
3250
+ * Move the popup to the specified location.
2850
3251
  *
2851
3252
  * @param lngLat New location.
2852
3253
  */
2853
3254
  moveTo(lngLat: [number, number]): void;
2854
3255
  /**
2855
- * Open the popup at the specified location.
3256
+ * Open the popup by providing a mouse event.
3257
+ *
3258
+ * The popup position and associated map feature are determined from the event.
2856
3259
  *
2857
- * @param lngLat Popup location.
3260
+ * @param event Mouse event triggering the popup
2858
3261
  */
2859
3262
  open(event: MapMouseEvent): void;
3263
+ /**
3264
+ * Open the popup by providing a location and associated map feature to display in the popup.
3265
+ *
3266
+ * @param lngLat Coordinate at which to display the popup
3267
+ * @param feature Map feature to associate with the popup
3268
+ */
2860
3269
  open(lngLat: [number, number], feature?: MapFeatureIdentifier): void;
3270
+ /**
3271
+ * Returns CSS classes to add to the popup.
3272
+ */
2861
3273
  private cssClasses;
3274
+ /**
3275
+ * Update the popup in response to feature data changes.
3276
+ *
3277
+ * The popup may be moved or re-rendered depending on the nature of the
3278
+ * feature changes.
3279
+ *
3280
+ * @param feature Map feature associated with the popup
3281
+ */
2862
3282
  private handleFeatureUpdate;
3283
+ /**
3284
+ * Called when the popup is closed to clean up resources.
3285
+ */
2863
3286
  private popupCloseHandler;
3287
+ /**
3288
+ * Render the popup content.
3289
+ *
3290
+ * If the content is defined using a template function, the function is called passing
3291
+ * in the associated map feature and the reactive state store.
3292
+ *
3293
+ * @param feature The map feature associated with the popup.
3294
+ */
2864
3295
  private renderContent;
2865
3296
  }
2866
3297