npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

maplibre-gl-fema-wms

v0.1.2

Published

MapLibre GL JS plugin for searching and adding FEMA National Flood Hazard Layer (NFHL) WMS layers to a map

Downloads

4,969

Readme

maplibre-gl-fema-wms

A MapLibre GL JS plugin for searching and adding FEMA National Flood Hazard Layer (NFHL) WMS layers to a map. Ships as a compact, collapsible map control with TypeScript types and an optional React wrapper.

npm version License: MIT

Features

  • Layer search: filter the NFHL layers (Flood Hazard Zones, FIRM Panels, LOMAs, Base Flood Elevations, and more) by name
  • One-click add/remove: each checked layer becomes its own MapLibre raster source and layer
  • Per-layer opacity slider
  • Legend display: per-layer GetLegendGraphic images, loaded on demand
  • Feature info: click the map to query active layers via GetFeatureInfo and view attributes in a popup
  • Zoom to layer extent from the capabilities bounding box
  • Insert before: a dropdown (and beforeId option) to insert WMS layers below an existing map layer, e.g. labels
  • Resizable panel: drag the panel edge to adjust its width from any control corner
  • Dark and light mode: follows prefers-color-scheme automatically, or force a theme with a dark/light class
  • Small-screen friendly: the panel caps its size to the viewport and scrolls vertically
  • Works with any WMS: the FEMA NFHL endpoint is the default, but url accepts any WMS service
  • TypeScript-first with fully exported types, plus a React wrapper component
  • GeoLibre Bundle Output: builds a zip with root plugin.json, bundled ESM, and CSS for GeoLibre Desktop

Installation

npm install maplibre-gl-fema-wms

maplibre-gl (>= 3.0.0) is a peer dependency. React (>= 18) is optional and only needed for the React wrapper.

Quick Start

Vanilla JavaScript/TypeScript

import maplibregl from "maplibre-gl";
import { FemaWmsControl } from "maplibre-gl-fema-wms";
import "maplibre-gl-fema-wms/style.css";

const map = new maplibregl.Map({
  container: "map",
  style: "https://tiles.openfreemap.org/styles/positron",
  center: [-95.37, 29.76], // Houston, TX
  zoom: 11,
});

map.on("load", () => {
  const control = new FemaWmsControl({
    collapsed: false,
    defaultLayers: ["12"], // Flood Hazard Zones
  });

  map.addControl(control, "top-right");
});

React

import { FemaWmsControlReact } from "maplibre-gl-fema-wms/react";
import "maplibre-gl-fema-wms/style.css";

function MyMap({ map }) {
  return (
    <FemaWmsControlReact
      map={map}
      collapsed={false}
      defaultLayers={["12"]}
      onStateChange={(state) => console.log(state.activeLayers)}
      onFeatureInfo={(result) => console.log(result.features)}
    />
  );
}

Options

| Option | Type | Default | Description | | --- | --- | --- | --- | | url | string | FEMA NFHL WMS | WMS endpoint. ArcGIS REST-style URLs (.../arcgis/rest/services/...) are normalized automatically. | | version | '1.3.0' \| '1.1.1' | '1.3.0' | WMS protocol version. | | defaultLayers | string[] | [] | Layer names to activate once capabilities load (e.g. ['12']). | | attribution | string | 'FEMA National Flood Hazard Layer' | Attribution added to raster sources. | | beforeId | string | - | Id of an existing map layer to insert WMS layers before (e.g. a label layer). Also selectable at runtime from the panel's "Insert before" dropdown. | | featureInfo | boolean | true | Query active layers on map click and show a popup. | | onFeatureInfo | (result) => void | - | Callback with each GetFeatureInfo result. | | collapsed | boolean | true | Start with only the toggle button visible. | | position | string | 'top-right' | Control corner: top-left, top-right, bottom-left, bottom-right. | | title | string | 'FEMA NFHL WMS' | Panel header title. | | panelWidth | number | 300 | Panel width in pixels (capped to the viewport on small screens). | | className | string | - | Extra CSS class for the control container. |

API

const control = new FemaWmsControl(options);

control.addLayer("12");             // add a WMS layer to the map
control.removeLayer("12");          // remove it
control.removeAllLayers();
control.setLayerOpacity("12", 0.5); // 0..1
control.zoomToLayer("12");          // fit map to the layer's bounding box
control.setSearchQuery("flood");    // filter the layer list
control.setBeforeId("label-place"); // insert/move WMS layers below a map layer
control.getBeforeId();
control.getLayers();                // all layers from capabilities
control.getActiveLayers();          // layers currently on the map
control.getCapabilities();          // parsed capabilities document
control.getState();                 // full control state
control.expand();                   // open the panel
control.collapse();                 // close the panel

control.on("layeradd", handler);    // events: collapse | expand | statechange |
control.off("layeradd", handler);   //   capabilitiesload | layeradd | layerremove |
                                    //   opacitychange | featureinfo | error

Low-level WMS helpers are also exported for advanced use: fetchCapabilities, parseCapabilities, buildGetMapTileUrl, buildLegendUrl, buildGetFeatureInfoUrl, normalizeWmsBaseUrl, pickInfoFormat, lngLatToMeters, and the FEMA_NFHL_WMS_URL constant.

All option, state, and event types are exported from both entry points: FemaWmsControlOptions, FemaWmsState, FemaWmsEvent, ActiveLayer, FeatureInfoResult, WmsCapabilities, WmsLayerInfo, and more.

Using a different WMS service

The control works with any WMS endpoint that accepts EPSG:3857 GetMap requests:

const control = new FemaWmsControl({
  url: "https://example.com/geoserver/wms",
  title: "My WMS",
});

Note: the FEMA capabilities document only advertises geographic CRSs, but the server accepts EPSG:3857 requests, which MapLibre requires for raster tiles. The control always requests EPSG:3857.

Dark mode

The control follows the operating system theme via prefers-color-scheme. To force a theme regardless of the OS setting, add a dark or light class to the map container (or any ancestor):

<div id="map" class="dark"></div>

Legend images are always rendered on a light backdrop so they stay readable in dark mode.

FEMA NFHL layers

Commonly used layer names (from the NFHL WMS capabilities):

| Name | Title | | --- | --- | | 12 | Flood Hazard Zones | | 13 | Flood Hazard Boundaries | | 23 | Base Flood Elevations | | 24 | Cross-Sections | | 28 | LOMAs | | 29 | LOMRs | | 30 | FIRM Panels | | 31 | NFHL Availability |

Call control.getLayers() for the complete, current list.

Known limitations

  • Feature info popups are skipped while the map is rotated or pitched (the WMS pixel query assumes an unrotated viewport).
  • WMS layers keep the order in which they were added relative to each other; use the "Insert before" dropdown or beforeId to position them relative to the basemap layers.

Build a GeoLibre plugin zip

GeoLibre Desktop loads external plugins from an app data plugins/ directory. The zip must contain plugin.json at the root, plus a bundled ESM entry and optional CSS file.

npm install
npm run package:geolibre

This creates:

geolibre-plugin/maplibre-gl-fema-wms-0.1.0.zip

The generated zip contains:

plugin.json
dist/index.js
dist/style.css

Copy the zip into GeoLibre Desktop's app data plugins/ directory and restart GeoLibre. On Linux with the default app identifier, that directory is usually:

~/.local/share/org.geolibre.desktop/plugins/

For the GeoLibre web app, serve the unpacked plugin with CORS enabled:

npm run package:geolibre
npm run serve:geolibre -- 8000

Then add this manifest URL in GeoLibre Settings > Plugins:

http://localhost:8000/plugin.json

Using python -m http.server for this cross-origin web app case is not enough because it does not send Access-Control-Allow-Origin.

Development

npm install
npm run dev             # dev server with the examples
npm test                # vitest unit tests
npm run lint            # eslint
npm run build           # library (ESM + CJS + types) and GeoLibre bundle
npm run build:examples  # static example site (GitHub Pages)

Docker

docker build -t maplibre-gl-fema-wms .
docker run -p 8080:80 maplibre-gl-fema-wms
# open http://localhost:8080/maplibre-gl-fema-wms/

Project structure

src/
├── index.ts                    # Main entry point
├── react.ts                    # React entry point
├── geolibre.ts                 # GeoLibre Desktop plugin wrapper
└── lib/
    ├── core/
    │   ├── FemaWmsControl.ts        # The WMS control
    │   ├── FemaWmsControlReact.tsx  # React wrapper
    │   ├── PluginControl.ts         # Generic collapsible control base
    │   ├── wms.ts                   # WMS capabilities/URL helpers
    │   └── types.ts                 # Shared types
    ├── hooks/                  # React hooks
    ├── styles/                 # Control styles (light/dark theming)
    └── utils/                  # Generic helpers

License

MIT. See LICENSE.

FEMA NFHL data is provided by the Federal Emergency Management Agency. Check FEMA's terms for data usage requirements.