import { IControl } from 'maplibre-gl'; import { Map as Map_2 } from 'maplibre-gl'; /** * State of a single GIBS layer instance added to the map. * * A time-enabled layer can be added multiple times with different dates; * each addition is a separate instance identified by `key`. */ export declare interface AddedLayerState { /** * Unique instance key (e.g. "MODIS_..._TrueColor@2024-06-01"). * Use this with removeLayer/setLayerDate/setLayerOpacity/setLayerVisibility. */ key: string; /** * GIBS layer identifier */ id: string; /** * Selected ISO 8601 date (for time-enabled layers) */ date?: string; /** * Layer opacity (0 to 1) */ opacity: number; /** * Whether the layer is currently visible on the map */ visible: boolean; } /** * Builds a MapLibre-compatible XYZ tile URL template from a GIBS layer. * * Substitutes {Time} with the given date (or the layer's default date), * {TileMatrixSet} with the layer's tile matrix set, and maps the WMTS * placeholders {TileMatrix}/{TileRow}/{TileCol} to {z}/{y}/{x}. * * @param layer - The GIBS layer to build a URL for * @param time - Optional ISO 8601 date overriding the layer's default date * @returns A tile URL template usable in a MapLibre raster source */ export declare function buildTileUrl(layer: GibsLayer, time?: string): string; /** * Clamps a value between a minimum and maximum. * * @param value - The value to clamp * @param min - The minimum allowed value * @param max - The maximum allowed value * @returns The clamped value * * @example * ```typescript * clamp(5, 0, 10); // returns 5 * clamp(-5, 0, 10); // returns 0 * clamp(15, 0, 10); // returns 10 * ``` */ export declare function clamp(value: number, min: number, max: number): number; /** * Creates a CSS class string from an object of class names. * * @param classes - Object with class names as keys and boolean values * @returns A space-separated string of class names * * @example * ```typescript * classNames({ active: true, disabled: false, visible: true }); * // returns "active visible" * ``` */ export declare function classNames(classes: Record): string; /** * Debounces a function call. * * @param fn - The function to debounce * @param delay - The delay in milliseconds * @returns A debounced version of the function * * @example * ```typescript * const debouncedUpdate = debounce(() => updateMap(), 100); * window.addEventListener('resize', debouncedUpdate); * ``` */ export declare function debounce void>(fn: T, delay: number): (...args: Parameters) => void; /** * Default URL of the NASA GIBS WMTS capabilities document (EPSG:3857, "best" imagery). */ export declare const DEFAULT_CAPABILITIES_URL = "https://gibs.earthdata.nasa.gov/wmts/epsg3857/best/1.0.0/WMTSCapabilities.xml"; /** * Formats a numeric value with appropriate decimal places based on step size. * * @param value - The value to format * @param step - The step size to determine decimal places * @returns The formatted value as a string * * @example * ```typescript * formatNumericValue(5, 1); // returns "5" * formatNumericValue(0.5, 0.1); // returns "0.5" * formatNumericValue(0.55, 0.01); // returns "0.55" * ``` */ export declare function formatNumericValue(value: number, step: number): string; /** * Generates a unique ID string. * * @param prefix - Optional prefix for the ID * @returns A unique ID string * * @example * ```typescript * generateId('control'); // returns "control-abc123" * generateId(); // returns "abc123" * ``` */ export declare function generateId(prefix?: string): string; /** * Parsed GIBS capabilities document. */ export declare interface GibsCapabilities { /** * All parsed layers, sorted by title. */ layers: GibsLayer[]; /** * Timestamp (ms since epoch) when the document was parsed. */ fetchedAt: number; } /** * Fetches, parses, and caches the NASA GIBS WMTS capabilities document. * * Concurrent calls to {@link GibsClient.getCapabilities} are deduplicated: * the document is fetched and parsed at most once unless `force` is passed. * * @example * ```typescript * const client = new GibsClient(); * const { layers } = await client.getCapabilities(); * const matches = client.search('temperature'); * ``` */ export declare class GibsClient { private _url; private _includeVector; private _capabilities?; private _pending?; /** * Creates a new GibsClient. * * @param options - Client options */ constructor(options?: GibsClientOptions); /** * Fetches and parses the capabilities document, caching the result. * * @param force - If true, refetch even if a cached result exists * @returns The parsed capabilities */ getCapabilities(force?: boolean): Promise; /** * Returns the cached capabilities, if already loaded. */ getCachedCapabilities(): GibsCapabilities | undefined; /** * Searches the cached layers by title or identifier. * Returns an empty array if capabilities have not been loaded yet. * * @param query - The search query */ search(query: string): GibsLayer[]; /** * Looks up a cached layer by identifier. * * @param id - The layer identifier */ getLayer(id: string): GibsLayer | undefined; } /** * Options for creating a GibsClient. */ export declare interface GibsClientOptions { /** * URL of the WMTS capabilities document. * @default DEFAULT_CAPABILITIES_URL */ url?: string; /** * Whether to include vector-tile (MVT) layers. * @default false */ includeVector?: boolean; } /** * A single WMTS layer parsed from the GIBS capabilities document. */ export declare interface GibsLayer { /** * Layer identifier (ows:Identifier), e.g. "MODIS_Terra_CorrectedReflectance_TrueColor". */ id: string; /** * Human-readable layer title (ows:Title). */ title: string; /** * Category the layer belongs to, derived from the platform/instrument * prefix of the identifier (e.g. "MODIS", "VIIRS", "MERRA2"). */ category: string; /** * Image format of the layer tiles. */ format: GibsLayerFormat; /** * File extension used in tile URLs (derived from the resource template). */ fileExtension: string; /** * TileMatrixSet identifier, e.g. "GoogleMapsCompatible_Level9". */ tileMatrixSet: string; /** * Maximum native zoom level (parsed from the TileMatrixSet name). */ maxZoom: number; /** * WGS84 bounding box as [west, south, east, north], if advertised. */ bbox?: [number, number, number, number]; /** * Raw tile ResourceURL template with {Time}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol} placeholders. */ resourceTemplate: string; /** * Time dimension, if the layer is time-enabled. */ time?: GibsTimeDimension; /** * URL of the first advertised legend image, if any. */ legendUrl?: string; } /** * Image format of a GIBS layer. */ export declare type GibsLayerFormat = "png" | "jpeg" | "mvt"; /** * Time dimension metadata for a GIBS layer. */ export declare interface GibsTimeDimension { /** * Default date (ISO 8601) advertised by the capabilities document. */ default: string; /** * Raw time domain values. Each entry is either a single date or a * "start/end/period" range (e.g. "2002-07-04/2026-06-01/P1D"). */ values: string[]; } /** * A MapLibre GL control for searching and adding NASA GIBS (Global Imagery * Browse Services) WMTS layers to the map. * * The control renders a collapsible button. When expanded, it fetches the * GIBS capabilities document, lets the user search the layer catalog, and * add/remove raster layers with per-layer date and opacity controls. * * @example * ```typescript * const control = new NasaEarthdataControl({ * title: 'NASA Earthdata', * collapsed: false, * }); * map.addControl(control, 'top-right'); * control.on('layeradd', (e) => console.log('Added', e.layer?.id)); * ``` */ export declare class NasaEarthdataControl implements IControl { private _map?; private _mapContainer?; private _container?; private _panel?; private _options; private _state; private _eventHandlers; private _client; private _capabilities?; private _loading; private _addedLayers; private _searchInput?; private _metaEl?; private _resultsEl?; private _addedEl?; private _insertSelect?; private _expandedCategories; private _openLegends; private _insertBefore; private _resizeHandler; private _mapResizeHandler; private _clickOutsideHandler; /** * Creates a new NasaEarthdataControl instance. * * @param options - Configuration options for the control */ constructor(options?: Partial); /** * Called when the control is added to the map. * Implements the IControl interface. * * @param map - The MapLibre GL map instance * @returns The control's container element */ onAdd(map: Map_2): HTMLElement; /** * Called when the control is removed from the map. * Implements the IControl interface. */ onRemove(): void; /** * Gets the current state of the control. * * @returns The current control state */ getState(): NasaEarthdataState; /** * Updates the control state. Changes to `addedLayers` are reconciled * against the map: missing layers are added, extra layers are removed, * and date/opacity changes are applied. * * @param newState - Partial state to merge with current state */ setState(newState: Partial): void; /** * Toggles the collapsed state of the control panel. */ toggle(): void; /** * Expands the control panel. */ expand(): void; /** * Collapses the control panel. */ collapse(): void; /** * Registers an event handler. * * @param event - The event type to listen for * @param handler - The callback function */ on(event: NasaEarthdataEvent, handler: NasaEarthdataEventHandler): void; /** * Removes an event handler. * * @param event - The event type * @param handler - The callback function to remove */ off(event: NasaEarthdataEvent, handler: NasaEarthdataEventHandler): void; /** * Gets the map instance. * * @returns The MapLibre GL map instance or undefined if not added to a map */ getMap(): Map_2 | undefined; /** * Gets the control container element. * * @returns The container element or undefined if not added to a map */ getContainer(): HTMLElement | undefined; /** * Fetches and caches the GIBS capabilities document. * * @param force - If true, refetch even if cached * @returns The parsed capabilities */ getCapabilities(force?: boolean): Promise; /** * Searches the loaded GIBS layers by title or identifier. * Returns an empty array if the capabilities have not been loaded yet. * * @param query - The search query * @returns Matching layers */ search(query: string): GibsLayer[]; /** * Gets the state of all layers currently added to the map. * * @returns Added layer states */ getAddedLayers(): AddedLayerState[]; /** * Adds a GIBS layer to the map as a raster source and layer. * Requires the capabilities to be loaded (call getCapabilities() first * when using the control programmatically). * * @param layerId - The GIBS layer identifier * @param options - Optional date, opacity, visibility, and insertion position */ addLayer(layerId: string, options?: { date?: string; opacity?: number; visible?: boolean; before?: string; key?: string; }): void; /** * Builds a unique instance key for a layer/date pair. Non-time layers can * only be added once; time-enabled layers get one instance per addition, * so a numeric suffix disambiguates repeated adds at the same date. */ private _instanceKey; /** * Resolves an instance key or a GIBS layer identifier to instances. * An exact key match wins; otherwise all instances of the layer match. */ private _resolveInstances; /** * Removes added GIBS layer instances from the map. Pass an instance key * to remove a single instance, or a GIBS layer identifier to remove all * instances of that layer. * * @param keyOrId - An instance key or a GIBS layer identifier */ removeLayer(keyOrId: string): void; /** * Changes the date of an added time-enabled layer instance. * * @param keyOrId - An instance key or a GIBS layer identifier * @param date - The new ISO 8601 date */ setLayerDate(keyOrId: string, date: string): void; /** * Changes the opacity of an added layer instance. * * @param keyOrId - An instance key or a GIBS layer identifier * @param opacity - The new opacity (0 to 1) */ setLayerOpacity(keyOrId: string, opacity: number): void; /** * Toggles the visibility of an added layer instance on the map. * * @param keyOrId - An instance key or a GIBS layer identifier * @param visible - Whether the layer should be visible */ setLayerVisibility(keyOrId: string, visible: boolean): void; /** * Removes the map source and layer for an instance key, if present. */ private _removeMapLayer; /** * Mirrors the internal added-layers map into the serializable state. */ private _syncAddedLayersState; /** * Reconciles a desired added-layers list against the map: * adds missing layers, removes extras, and applies date/opacity changes. */ private _reconcileAddedLayers; /** * Loads the capabilities document (once) and renders the results list. */ private _loadCapabilities; /** * Emits an event to all registered handlers. * * @param event - The event type to emit * @param extra - Extra payload fields (layer, error) */ private _emit; /** * Emits an 'error' event. */ private _emitError; /** * Returns the theme class for the configured theme, if explicit. */ private _themeClass; /** * Creates the main container element for the control. * Contains a toggle button (29x29) matching navigation control size. * * @returns The container element */ private _createContainer; /** * Creates the panel element with header, search box, and results list. * Panel is positioned as a dropdown below the toggle button. * * @returns The panel element */ private _createPanel; /** * Returns the maximum panel width that fits the map container. */ private _maxPanelWidth; /** * Clamps the panel width to the map container. Applied whenever the panel * is (re)positioned so a saved width survives map shrinking. */ private _applyPanelWidthBounds; /** * Starts a panel width drag-resize. The drag direction is derived from * the control corner so resizing works whether the panel is anchored to * the left or the right edge of the map. */ private _startResize; /** * Shows a status message (loading or error) in the results area. */ private _renderStatus; /** * Groups layers by category, merging categories with fewer layers than * the threshold into "Other". Returns entries sorted alphabetically * with "Other" last. */ private _groupByCategory; /** * Renders the (filtered) layer catalog grouped by category. */ private _renderResults; /** * Creates a collapsible category group with a count badge. */ private _createCategoryGroup; /** * Creates a single catalog layer row with title, badges, and an action * button. Non-time layers toggle add/remove; time-enabled layers always * offer "Add" so additional instances with different dates can be added. * Per-layer controls live in the added-layers section. */ private _createLayerRow; /** * Renders the "Added layers" management section: visibility checkbox, * legend toggle, remove button, opacity slider, and date picker. */ private _renderAddedSection; /** * Creates a management card for one added layer. */ private _createAddedRow; /** * Refreshes the "Insert before" dropdown with the map's current layers. */ private _refreshInsertOptions; /** * Derives the min/max selectable dates from a layer's time domain values. */ private _timeRange; /** * Setup event listeners for panel positioning and click-outside behavior. */ private _setupEventListeners; /** * Detect which corner the control is positioned in. * * @returns The position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' */ private _getControlPosition; /** * Update the panel position based on button location and control corner. * Positions the panel next to the button, expanding in the appropriate direction. */ private _updatePanelPosition; } /** * Options for configuring the NasaEarthdataControl */ export declare interface NasaEarthdataControlOptions { /** * Whether the control panel should start collapsed (showing only the toggle button) * @default true */ collapsed?: boolean; /** * Position of the control on the map * @default 'top-right' */ position?: "top-left" | "top-right" | "bottom-left" | "bottom-right"; /** * Title displayed in the control header * @default 'NASA Earthdata' */ title?: string; /** * Initial width of the control panel in pixels. The panel can also be * resized by dragging its outer edge. * @default 320 */ panelWidth?: number; /** * Custom CSS class name for the control container */ className?: string; /** * URL of the WMTS capabilities document * @default DEFAULT_CAPABILITIES_URL */ capabilitiesUrl?: string; /** * Whether to include vector-tile (MVT) layers in search results * @default false */ includeVector?: boolean; /** * Whether to show an opacity slider for added layers * @default true */ showOpacity?: boolean; /** * Attribution string applied to added raster sources * @default 'NASA EOSDIS GIBS' */ attribution?: string; /** * Color theme of the control. 'auto' follows the OS preference. * @default 'auto' */ theme?: "auto" | "light" | "dark"; } /** * Event types emitted by the NASA Earthdata control */ export declare type NasaEarthdataEvent = "collapse" | "expand" | "statechange" | "layeradd" | "layerremove" | "capabilitiesload" | "error"; /** * Event handler function type */ export declare type NasaEarthdataEventHandler = (event: NasaEarthdataEventPayload) => void; /** * Payload passed to NASA Earthdata event handlers */ export declare interface NasaEarthdataEventPayload { /** * The event type */ type: NasaEarthdataEvent; /** * Snapshot of the control state at the time of the event */ state: NasaEarthdataState; /** * The GIBS layer involved (for 'layeradd' and 'layerremove') */ layer?: GibsLayer; /** * The error that occurred (for 'error') */ error?: Error; } /** * Internal state of the NASA Earthdata control */ export declare interface NasaEarthdataState { /** * Whether the control panel is currently collapsed */ collapsed: boolean; /** * Current panel width in pixels */ panelWidth: number; /** * Current search query */ query: string; /** * Layers currently added to the map */ addedLayers: AddedLayerState[]; } /** * Parses a WMTS GetCapabilities XML document into a GibsCapabilities object. * * Layers without a usable tile resource template are skipped. Vector-tile * (MVT) layers are skipped unless `options.includeVector` is true. * * @param xml - The raw WMTSCapabilities.xml document text * @param options - Parse options * @returns Parsed capabilities with layers sorted by title */ export declare function parseCapabilities(xml: string, options?: ParseOptions): GibsCapabilities; /** * Options for parsing the capabilities document. */ export declare interface ParseOptions { /** * Whether to include vector-tile (MVT) layers in the result. * @default false */ includeVector?: boolean; } /** * Filters GIBS layers by a free-text query. * * Performs a case-insensitive substring match against the layer title and * identifier. An empty or whitespace-only query returns all layers. * * @param layers - The layers to search * @param query - The search query * @returns Layers whose title or identifier contains the query */ export declare function searchLayers(layers: GibsLayer[], query: string): GibsLayer[]; /** * Throttles a function call. * * @param fn - The function to throttle * @param limit - The minimum time between calls in milliseconds * @returns A throttled version of the function * * @example * ```typescript * const throttledScroll = throttle(() => handleScroll(), 100); * window.addEventListener('scroll', throttledScroll); * ``` */ export declare function throttle void>(fn: T, limit: number): (...args: Parameters) => void; export { }