import { IControl } from 'maplibre-gl'; import { Map as Map_2 } from 'maplibre-gl'; /** * A layer that has been added to the map through the control. */ export declare interface AddedLayer { /** Unique identifier for this entry */ id: string; /** MapLibre source id */ sourceId: string; /** MapLibre layer id */ layerId: string; /** The EnviroAtlas service the layer comes from */ service: ServiceRef; /** Sublayer id when a single MapServer sublayer was added */ sublayerId?: number; /** Display label shown in the added layers list */ label: string; /** Whether the layer is currently visible */ visible: boolean; /** Current raster opacity (0 to 1) */ opacity: number; /** Geographic bounds of the service data, when known */ bounds?: LngLatBoundsArray; } /** * An ArcGIS extent object (subset). */ declare interface ArcGISExtent { xmin: number; ymin: number; xmax: number; ymax: number; spatialReference?: { wkid?: number; latestWkid?: number; wkt?: string; wkt2?: string; }; } /** Placeholder MapLibre replaces with the tile bounding box (EPSG:3857) */ export declare const BBOX_PLACEHOLDER = "{bbox-epsg-3857}"; /** * Builds the catalog root URL returning the folder list. * * @param servicesUrl - The ArcGIS REST services root * @returns The catalog JSON URL */ export declare function buildCatalogUrl(servicesUrl?: string): string; /** * Builds an ImageServer exportImage tile template for use as a * MapLibre raster source `tiles` entry. * * @param service - The ImageServer service reference * @param options - Tile size and image format options * @param servicesUrl - The ArcGIS REST services root * @returns The exportImage tile URL template */ export declare function buildExportImageUrl(service: ServiceRef, options?: ExportUrlOptions, servicesUrl?: string): string; /** * Builds a MapServer dynamic export tile template for use as a * MapLibre raster source `tiles` entry. The `{bbox-epsg-3857}` * placeholder is substituted by MapLibre per tile request. * * @param service - The MapServer service reference * @param sublayerId - Optional layer (or group layer) id to render exclusively * @param options - Tile size and image format options * @param servicesUrl - The ArcGIS REST services root * @returns The export tile URL template */ export declare function buildExportUrl(service: ServiceRef, sublayerId?: number, options?: ExportUrlOptions, servicesUrl?: string): string; /** * Builds the URL listing services within a folder. * * @param folder - The folder name (e.g. "Communities") * @param servicesUrl - The ArcGIS REST services root * @returns The folder JSON URL */ export declare function buildFolderUrl(folder: string, servicesUrl?: string): string; /** * Builds the legend URL for a service. * * @param service - The service reference * @param servicesUrl - The ArcGIS REST services root * @returns The legend JSON URL */ export declare function buildLegendUrl(service: ServiceRef, servicesUrl?: string): string; /** * Builds the metadata URL for a service (layer list, description, ...). * * @param service - The service reference * @param servicesUrl - The ArcGIS REST services root * @returns The service metadata JSON URL */ export declare function buildServiceUrl(service: ServiceRef, servicesUrl?: string): string; /** * Builds the raster tile template for any service type. * * @param service - The service reference * @param sublayerId - Optional MapServer sublayer id (ignored for ImageServers) * @param options - Tile size and image format options * @param servicesUrl - The ArcGIS REST services root * @returns The tile URL template for a MapLibre raster source */ export declare function buildTileTemplate(service: ServiceRef, sublayerId?: number, options?: ExportUrlOptions, servicesUrl?: string): string; /** * Client for browsing the EnviroAtlas services catalog with caching. */ export declare class CatalogClient { private readonly _servicesUrl; private readonly _excludedFolders; private readonly _prefetchConcurrency; private _folders?; private readonly _services; private readonly _metadata; private readonly _legends; private _prefetchAll?; private _abortController; /** * Creates a new catalog client. * * @param options - Client configuration */ constructor(options?: CatalogClientOptions); /** The ArcGIS REST services root this client reads from. */ get servicesUrl(): string; /** * Lists catalog folders (cached after the first call). * * @returns Folder names, excluding configured folders */ listFolders(): Promise; /** * Lists services within a folder (cached per folder). * * @param folder - The folder name * @returns Service references in the folder */ listServices(folder: string): Promise; /** * Fetches metadata (layer list) for a service (cached per service). * * @param service - The service reference * @returns Parsed service metadata */ getServiceMetadata(service: ServiceRef): Promise; /** * Returns cached metadata for a service if already fetched. * * @param service - The service reference * @returns The cached metadata promise or undefined */ getCachedMetadata(service: ServiceRef): Promise | undefined; /** * Fetches the legend for a service (cached per service). * * @param service - The service reference * @returns Per-layer legends, empty when the service has none */ getLegend(service: ServiceRef): Promise; /** * Lists all services across all folders (cached). * * @returns All service references in the catalog */ listAllServices(): Promise; /** * Prefetches layer metadata for all MapServer services so sublayer * search has data. Runs once; subsequent calls return the same promise. * * @param onProgress - Called after each service's metadata resolves * @returns A promise resolving when all metadata is fetched */ prefetchAllLayers(onProgress?: () => void): Promise; /** * Clears all cached data so the next calls re-fetch from the server. */ clearCache(): void; /** * Aborts all in-flight requests and resets the abort controller. */ abort(): void; private _fetchJson; } /** * Options for creating a {@link CatalogClient}. */ export declare interface CatalogClientOptions { /** ArcGIS REST services root @default DEFAULT_SERVICES_URL */ servicesUrl?: string; /** Folder names to hide @default DEFAULT_EXCLUDED_FOLDERS */ excludedFolders?: string[]; /** Max concurrent requests when prefetching layer lists @default 6 */ prefetchConcurrency?: number; } /** * 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; /** Folders hidden from the catalog by default */ export declare const DEFAULT_EXCLUDED_FOLDERS: string[]; /** Default EnviroAtlas ArcGIS REST services root */ export declare const DEFAULT_SERVICES_URL = "https://enviroatlas.epa.gov/arcgis/rest/services"; /** * A MapLibre GL control for searching and adding EPA EnviroAtlas * web services to the map. * * The control renders as a 29x29 toggle button (matching the * navigation control) that expands into a floating panel with a * catalog tree, search, and a management section for added layers. * * @example * ```typescript * const control = new EnviroAtlasControl({ * collapsed: false, * theme: 'auto', * }); * map.addControl(control, 'top-right'); * control.on('layeradd', (event) => console.log('Added', event.layer)); * ``` */ export declare class EnviroAtlasControl implements IControl { private _map?; private _mapContainer?; private _container?; private _panel?; private _options; private _state; private _eventHandlers; private _catalog?; private _layerManager?; private _panelView?; private _treeView?; private _resultsView?; private _addedView?; /** Resolved layer metadata available for synchronous search */ private readonly _metadataCache; private _allServices; private _prefetchStarted; private _searchEpoch; private _noticeTimer; private _debouncedSearch?; /** Layers handed to restoreLayers before the control was added to a map */ private _pendingRestore; private _resizeHandler; private _mapResizeHandler; private _clickOutsideHandler; private _clickCaptureHandler; private _mapErrorHandler; /** Whether the panel was expanded when the current click dispatch began */ private _expandedAtClickStart; /** Suppresses the click fired when a resize drag ends outside the panel */ private _suppressNextClickOutside; /** * Creates a new EnviroAtlasControl 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(): EnviroAtlasState; /** * Updates the control state. * * @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; /** * Sets the panel width in pixels (clamped to the map width). * * @param width - The new panel width */ setPanelWidth(width: number): void; /** * Sets the color theme of the control. * * @param theme - The theme to apply */ setTheme(theme: EnviroAtlasTheme): void; /** * Adds a service (or a single MapServer sublayer) to the map. * * The service extent is fetched (and cached) to limit tile requests * to the data area and, unless `fitBoundsOnAdd` is disabled, to zoom * the map to the added layer. * * @param service - The service to add * @param sublayerId - Optional MapServer sublayer id * @param label - Optional display label (defaults to the service name) * @returns The added layer entry, or the existing entry when already added */ addServiceLayer(service: ServiceRef, sublayerId?: number, label?: string): Promise; /** * Re-registers layers that were previously added and persisted by a * host application. * * Host applications that save and restore map state (for example a * project file) typically recreate the native MapLibre source and * layer for each persisted {@link AddedLayer} themselves and then need * to hand those layers back to the control so it tracks them again. * This method does exactly that without duplicating the natives: when * the source/layer already exist they are reused (and opacity and * visibility reconciled), otherwise they are created. * * Entries that are already tracked, or that match an existing layer by * service and sublayer, are skipped. Unlike {@link addServiceLayer}, * this method never fits the map bounds and shows no notices. * * When the control has not been added to a map yet the entries are * stored and applied automatically in {@link onAdd}. * * @param entries - The persisted added-layer entries to restore */ restoreLayers(entries: AddedLayer[]): void; /** * Removes a layer previously added through the control. * * @param id - The added-layer id */ removeLayer(id: string): void; /** * Sets the opacity of an added layer. * * @param id - The added-layer id * @param opacity - New opacity (0 to 1) */ setLayerOpacity(id: string, opacity: number): void; /** * Sets the visibility of an added layer. * * @param id - The added-layer id * @param visible - Whether the layer should be visible */ setLayerVisibility(id: string, visible: boolean): void; /** * Clears the catalog cache and reloads the folder tree. */ refreshCatalog(): void; /** * Registers an event handler. * * @param event - The event type to listen for * @param handler - The callback function */ on(event: EnviroAtlasControlEvent, handler: EnviroAtlasControlEventHandler): void; /** * Removes an event handler. * * @param event - The event type * @param handler - The callback function to remove */ off(event: EnviroAtlasControlEvent, handler: EnviroAtlasControlEventHandler): 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; /** * Emits an event to all registered handlers. * * @param event - The event type to emit * @param extra - Extra payload (layer or error) */ private _emit; private _handleError; private _showNotice; /** * Applies the current theme via a data-theme attribute on both the * control container and the floating panel. In 'auto' mode no * attribute is set, letting the prefers-color-scheme media query * drive the palette. */ private _applyTheme; private _treeContext; /** * Handles (debounced) search input: shows the tree when the query * is empty, otherwise filters the catalog and renders flat results. * * @param query - The raw search query */ private _runSearch; /** * Starts the one-time sublayer metadata prefetch used for deep search. * * @param onUpdate - Called as metadata resolves and when done * @returns True when a prefetch is currently running */ private _startPrefetch; /** * 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, browse region, * and the added layers section. * * @returns The panel element */ private _createPanel; /** * Populates the "Insert before" select with the map's current style * layers, keeping the active selection when still present. */ private _refreshBeforeSelect; /** * Wires the resize handle: dragging it horizontally adjusts the * panel width. The growth direction follows the panel anchor (a * left-anchored panel grows rightward, a right-anchored panel grows * leftward), so resizing works in every control corner. * * @param panelView - The panel view holding the resizer element */ private _setupResize; /** * 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, and caps the panel height to the map container so the * content scrolls vertically on small screens. */ private _updatePanelPosition; } /** * Event types emitted by the EnviroAtlas control */ export declare type EnviroAtlasControlEvent = 'collapse' | 'expand' | 'statechange' | 'layeradd' | 'layerremove' | 'layerchange' | 'error'; /** * Payload passed to event handlers. */ export declare interface EnviroAtlasControlEventData { /** The event type */ type: EnviroAtlasControlEvent; /** A snapshot of the control state */ state: EnviroAtlasState; /** The affected layer for layer events */ layer?: AddedLayer; /** The error for 'error' events */ error?: Error; } /** * Event handler function type */ export declare type EnviroAtlasControlEventHandler = (event: EnviroAtlasControlEventData) => void; /** * Options for configuring the EnviroAtlasControl */ export declare interface EnviroAtlasControlOptions { /** * 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 'US EPA EnviroAtlas' */ title?: string; /** * Width of the control panel in pixels (capped to the viewport on small screens) * @default 360 */ panelWidth?: number; /** * Custom CSS class name for the control container */ className?: string; /** * Color theme for the control UI * @default 'auto' */ theme?: EnviroAtlasTheme; /** * ArcGIS REST services root to browse * @default 'https://enviroatlas.epa.gov/arcgis/rest/services' */ servicesUrl?: string; /** * Catalog folders to hide from browsing and search * @default ['test_services', 'Utilities', 'monitor'] */ excludedFolders?: string[]; /** * Initial opacity for newly added layers (0 to 1) * @default 1 */ defaultOpacity?: number; /** * How added layers are rendered. * * - `'image'` (default): one export request covers the visible map * area and refreshes when the view settles. Dynamic ArcGIS * services render each request server-side, so a single * viewport-sized request is much faster and more reliable than * dozens of tile requests. * - `'tiles'`: a raster tile source requesting one export per tile. * @default 'image' */ renderMode?: 'image' | 'tiles'; /** * Raster tile size in pixels (tiles render mode) * @default 256 */ tileSize?: number; /** * ArcGIS export image format * @default 'png32' */ imageFormat?: string; /** * Attribution string attached to added raster sources * @default 'U.S. EPA EnviroAtlas' */ attribution?: string; /** * Id of an existing map layer to insert added layers before * (e.g. a label layer so EnviroAtlas rasters render below labels). * When omitted or not found, layers are added on top. */ beforeId?: string; /** * Debounce delay for the search input in milliseconds * @default 250 */ searchDebounceMs?: number; /** * Whether to zoom the map to a layer's extent when it is added * @default true */ fitBoundsOnAdd?: boolean; /** * Whether to keep transient EnviroAtlas tile failures out of the * console. The EPA server occasionally answers tile requests * without CORS headers or with gateway timeouts; with this enabled * the control handles the map's error events for EnviroAtlas URLs * (emitting its own 'error' event instead) and logs all other map * errors as MapLibre would by default. * @default true */ quietTileErrors?: boolean; } /** * Props for the React wrapper component */ export declare interface EnviroAtlasControlReactProps extends EnviroAtlasControlOptions { /** * MapLibre GL map instance */ map: Map_2; /** * Callback fired when the control state changes */ onStateChange?: (state: EnviroAtlasState) => void; /** * Callback fired when a layer is added to the map */ onLayerAdd?: (layer: AddedLayer) => void; /** * Callback fired when a layer is removed from the map */ onLayerRemove?: (layer: AddedLayer) => void; /** * Callback fired when a catalog or network error occurs */ onError?: (error: Error) => void; } /** * Internal state of the EnviroAtlas control */ export declare interface EnviroAtlasState { /** * Whether the control panel is currently collapsed */ collapsed: boolean; /** * Current panel width in pixels */ panelWidth: number; /** * Current color theme */ theme: EnviroAtlasTheme; /** * Current search query */ query: string; /** * Layers added to the map through the control */ addedLayers: AddedLayer[]; /** * Any custom state data */ data?: Record; } /** * Color theme for the control UI. * * - `'light'` and `'dark'` force a palette. * - `'auto'` follows the user's `prefers-color-scheme` setting. */ export declare type EnviroAtlasTheme = 'light' | 'dark' | 'auto'; /** * Options shared by the raster export URL builders. */ export declare interface ExportUrlOptions { /** Tile size in pixels @default 256 */ tileSize?: number; /** ArcGIS image format @default 'png32' */ imageFormat?: string; } /** * Filters the catalog against a search query. * * Matches are case-insensitive substring matches against service * names (folder-qualified) and, when layer metadata is available in * `layerCache`, sublayer names within MapServer services. * * @param query - The raw user query * @param services - All known service references * @param layerCache - Resolved metadata keyed by service fullName * @param limit - Maximum number of results @default 200 * @returns Matching services first, then matching sublayers */ export declare function filterCatalog(query: string, services: ServiceRef[], layerCache: ReadonlyMap, limit?: number): SearchResult[]; /** * 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; /** * Legend information for one layer of a service. */ export declare interface LayerLegend { /** The layer id within the service */ layerId: number; /** The layer name */ layerName: string; /** Legend swatches for the layer */ legend: LegendEntry[]; } /** * A single legend swatch entry for a layer. */ export declare interface LegendEntry { /** Legend label text */ label: string; /** Base64-encoded PNG image data */ imageData: string; /** Image content type (e.g. "image/png") */ contentType: string; /** Swatch width in pixels */ width: number; /** Swatch height in pixels */ height: number; } /** * Converts ArcGIS service extents to geographic (EPSG:4326) bounds. * * EnviroAtlas services publish extents in Web Mercator, geographic * coordinates, or one of several Albers Equal Area projections (the * server's GeometryServer project endpoint is unavailable, so the * inverse projection is computed client-side with a spherical * approximation, then padded). The resulting bounds are used both to * limit raster tile requests (the server times out with a 504 on * far-out-of-extent exports) and to zoom the map to newly added layers. */ /** Geographic bounds as [west, south, east, north] */ declare type LngLatBoundsArray = [number, number, number, number]; /** * Manages MapLibre raster sources and layers created from * EnviroAtlas services. Pure map mutation, no UI concerns. */ export declare class MapLayerManager { private readonly _map; private readonly _options; private readonly _layers; private _viewHandler; /** * Creates a manager bound to a map instance. * * @param map - The MapLibre GL map * @param options - Source creation options */ constructor(map: Map_2, options: MapLayerManagerOptions); /** All layers currently managed, in insertion order. */ getLayers(): AddedLayer[]; /** * Finds an existing entry for the same service and sublayer. * * @param service - The service reference * @param sublayerId - Optional sublayer id * @returns The matching entry or undefined */ findLayer(service: ServiceRef, sublayerId?: number): AddedLayer | undefined; /** * Adds a service (or a single MapServer sublayer) to the map. * * In 'image' mode (default) a single export request covers the * visible map area and is refreshed when the view settles; in * 'tiles' mode a raster tile source requests one export per tile. * * @param service - The service to add * @param label - Display label for the added layer * @param sublayerId - Optional MapServer sublayer id * @param opacity - Initial raster opacity (0 to 1) * @param bounds - Optional geographic bounds limiting requests * @returns The created added-layer entry */ addLayer(service: ServiceRef, label: string, sublayerId?: number, opacity?: number, bounds?: LngLatBoundsArray): AddedLayer; /** * Re-registers a previously persisted layer, reusing native source * and layer objects the host application may have already recreated. * * Host applications that persist {@link AddedLayer} entries (for * example in a saved project) often recreate the native MapLibre * source and layer themselves before re-activating the control. This * method hands those layers back to the manager without duplicating * the natives: existing source/layer objects are kept and only the * missing ones are created, while opacity and visibility are * reconciled to match the entry. * * @param entry - The persisted added-layer entry to restore * @returns The tracked added-layer entry (an existing one when the id * was already managed, otherwise the newly registered copy) */ restoreLayer(entry: AddedLayer): AddedLayer; /** * Creates the native MapLibre source for an added layer according to * the current render mode. * * @param entry - The added layer to create a source for */ private _createSource; /** * Creates the native MapLibre raster layer for an added layer, * removing the source if layer creation fails. * * @param entry - The added layer to create a layer for */ private _createLayer; /** * Removes a managed layer and its source from the map. * * @param id - The added-layer id * @returns The removed entry or undefined when unknown */ removeLayer(id: string): AddedLayer | undefined; /** * Updates the raster opacity of a managed layer. * * @param id - The added-layer id * @param opacity - New opacity (0 to 1) * @returns The updated entry or undefined when unknown */ setOpacity(id: string, opacity: number): AddedLayer | undefined; /** * Toggles the visibility of a managed layer. * * @param id - The added-layer id * @param visible - Whether the layer should be visible * @returns The updated entry or undefined when unknown */ setVisibility(id: string, visible: boolean): AddedLayer | undefined; /** * Changes the layer that added layers are inserted before, moving * the already-added layers accordingly. * * @param beforeId - The target layer id, or undefined for top of map */ setBeforeId(beforeId?: string): void; /** * Removes all managed layers and sources from the map. */ removeAll(): void; /** * Computes the export request and image placement for the current * map view, clamped to the layer bounds. * * @param entry - The added layer * @returns The export url and image corner coordinates, or null when * the layer is entirely outside the current view */ private _computeView; /** * Refreshes the export image of a single layer for the current view. * * @param entry - The added layer */ private _updateImageLayer; /** Registers the shared view listener that refreshes image layers. */ private _ensureViewHandler; /** Removes the shared view listener. */ private _removeViewHandler; } /** * Options for creating a {@link MapLayerManager}. */ export declare interface MapLayerManagerOptions { /** ArcGIS REST services root */ servicesUrl: string; /** Raster tile size in pixels (tiles mode) */ tileSize: number; /** ArcGIS export image format */ imageFormat: string; /** Attribution attached to raster sources */ attribution: string; /** * How layers are rendered. 'image' issues a single export request * per map view (fast against dynamic ArcGIS services); 'tiles' * requests one export per 256px tile. */ renderMode: RenderMode; /** Existing layer id to insert added layers before (skipped when absent) */ beforeId?: string; } /** * Parses the catalog root response into a folder list, applying exclusions. * * @param json - The catalog root JSON response * @param excludedFolders - Folder names to filter out * @returns Folder names sorted alphabetically */ export declare function parseFolderList(json: unknown, excludedFolders?: string[]): string[]; /** * Parses a legend response into per-layer legends. * * @param json - The legend JSON response * @returns Legends keyed by layer, empty when unavailable */ export declare function parseLegend(json: unknown): LayerLegend[]; /** * Parses a folder listing response into service references. * * @param json - The folder JSON response * @param folder - The folder that was listed * @returns Service references for supported service types */ export declare function parseServiceList(json: unknown, folder: string): ServiceRef[]; /** * Parses a service metadata response into {@link ServiceMetadata}. * * @param json - The service JSON response * @returns Parsed metadata with a normalized layer list */ export declare function parseServiceMetadata(json: unknown): ServiceMetadata; /** How each added layer is rendered */ export declare type RenderMode = 'image' | 'tiles'; /** * A search result entry. Either a whole service or a single * sublayer within a MapServer service. */ export declare type SearchResult = { kind: 'service'; service: ServiceRef; } | { kind: 'sublayer'; service: ServiceRef; layer: ServiceLayer; }; /** * A single layer inside a MapServer service. */ export declare interface ServiceLayer { /** Numeric layer id used in `layers=show:{id}` export requests */ id: number; /** Human readable layer name */ name: string; /** Parent layer id, -1 for root layers */ parentLayerId: number; /** Child layer ids when this is a group layer */ subLayerIds: number[] | null; } /** * Metadata for a MapServer or ImageServer service (subset of the * ArcGIS JSON response). */ export declare interface ServiceMetadata { /** Display name reported by the server */ mapName?: string; /** Service description */ description?: string; /** Flat list of layers (empty for ImageServers) */ layers: ServiceLayer[]; /** Service extent (fullExtent for MapServers, extent for ImageServers) */ extent?: ArcGISExtent; } /** * A reference to a single ArcGIS service in the catalog. */ export declare interface ServiceRef { /** Folder the service lives in (e.g. "Communities") */ folder: string; /** Short service name without the folder prefix (e.g. "Community_BGmetrics") */ name: string; /** Full service name as returned by the server (e.g. "Communities/Community_BGmetrics") */ fullName: string; /** The ArcGIS service type */ type: ServiceType; } /** * The kind of ArcGIS service exposed by the EnviroAtlas server. */ export declare type ServiceType = 'MapServer' | 'ImageServer'; /** * 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 { }