Skip to content

opengeos/maplibre-gl-overture-maps

Repository files navigation

MapLibre GL Overture Maps

A MapLibre GL JS plugin for visualizing Overture Maps PMTiles themes. It adds a collapsible map control with a release selector and per-theme visibility and opacity controls, rendering an "x-ray" style overlay similar to explore.overturemaps.org. A React wrapper and a GeoLibre Desktop plugin bundle are included.

npm version License: MIT Open in CodeSandbox Open in StackBlitz

Features

  • All six Overture themes - Addresses, base, buildings, divisions, places, and transportation, each loaded from the official Overture PMTiles distribution
  • Dynamic releases - Fetches the latest Overture release list at runtime, with a dropdown to switch releases and an option to pin one
  • Theme controls - Checkbox, color swatch, and opacity slider per theme
  • Feature inspection - Click any rendered Overture feature to see its properties in a popup (can be disabled)
  • Dark and light mode - The control UI follows prefers-color-scheme by default and can be forced light or dark
  • Small-screen friendly - The panel stays within the viewport and scrolls vertically when space is tight
  • TypeScript Support - Full TypeScript support with exported type definitions
  • React Integration - React wrapper component and custom hook
  • GeoLibre Bundle Output - Builds a zip with root plugin.json, bundled ESM, and CSS for GeoLibre Desktop
  • Modern Build Setup - Vite-based library and GeoLibre bundle builds
  • Testing - Vitest setup with React Testing Library
  • CI/CD Ready - GitHub Actions for npm publishing, GitHub Pages, and Docker

Installation

npm install maplibre-gl-overture-maps

maplibre-gl (>=3.0.0) is a peer dependency. The pmtiles package is bundled as a regular dependency, and the control registers the pmtiles:// protocol with MapLibre automatically when added to a map.

Quick Start

Vanilla JavaScript/TypeScript

import maplibregl from "maplibre-gl";
import { OvertureMapsControl } from "maplibre-gl-overture-maps";
import "maplibre-gl-overture-maps/style.css";

const map = new maplibregl.Map({
  container: "map",
  style: "https://tiles.openfreemap.org/styles/positron",
  center: [-74.006, 40.7128],
  zoom: 14,
});

map.on("load", () => {
  const control = new OvertureMapsControl({
    collapsed: false,
    visibleThemes: ["buildings", "transportation", "places"],
  });

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

React

import { useEffect, useRef, useState } from "react";
import maplibregl, { Map } from "maplibre-gl";
import {
  OvertureMapsControlReact,
  useOvertureMapsState,
} from "maplibre-gl-overture-maps/react";
import "maplibre-gl-overture-maps/style.css";

function App() {
  const mapContainer = useRef<HTMLDivElement>(null);
  const [map, setMap] = useState<Map | null>(null);
  const { state, toggle } = useOvertureMapsState();

  useEffect(() => {
    if (!mapContainer.current) return;

    const mapInstance = new maplibregl.Map({
      container: mapContainer.current,
      style: "https://tiles.openfreemap.org/styles/positron",
      center: [-74.006, 40.7128],
      zoom: 14,
    });

    mapInstance.on("load", () => setMap(mapInstance));

    return () => mapInstance.remove();
  }, []);

  return (
    <div style={{ width: "100%", height: "100vh" }}>
      <div ref={mapContainer} style={{ width: "100%", height: "100%" }} />
      {map && (
        <OvertureMapsControlReact
          map={map}
          collapsed={state.collapsed}
          onStateChange={(newState) => console.log(newState)}
        />
      )}
    </div>
  );
}

Overture Themes

Each theme is a separate PMTiles archive from the official distribution at https://overturemaps-extras-us-west-2.s3.us-west-2.amazonaws.com/tiles/<RELEASE>/<THEME>.pmtiles.

Theme Source layers Default color Notes
addresses address #e6194b Points appear at z14+
base land, land_cover, land_use, water, bathymetry, infrastructure #3cb44b
buildings building, building_part #f58231
divisions division_area, division_boundary, division #911eb4
places place #4363d8 Points appear at z14+
transportation segment, connector #f032e6

API

OvertureMapsControl

The main control class implementing MapLibre's IControl interface.

Constructor Options

Option Type Default Description
collapsed boolean true Whether the panel starts collapsed (showing only the 29x29 toggle button)
position string 'top-right' Control position on the map
title string 'Overture Maps' Title displayed in the header
panelWidth number 300 Width of the dropdown panel in pixels
className string '' Custom CSS class name
theme 'light' | 'dark' | 'auto' 'auto' UI color scheme; 'auto' follows prefers-color-scheme
release string latest Pin a specific Overture release (e.g. '2026-05-20.0')
releasesUrl string Overture labs releases.json Endpoint listing available releases
tilesBaseUrl string Official Overture S3 tiles URL Base URL of the PMTiles distribution
inspect boolean true Click a rendered feature to open a properties popup
visibleThemes OvertureTheme[] ['buildings', 'transportation', 'places'] Themes that start visible
themeColors Partial<Record<OvertureTheme, string>> x-ray palette Per-theme color overrides
themeOpacity Partial<Record<OvertureTheme, number>> 0.8 Per-theme initial opacity (0..1)

Methods

  • toggle() / expand() / collapse() - Control the panel
  • getState() / setState(state) - Read or update the state
  • setRelease(release) - Switch the active Overture release
  • setThemeVisible(theme, visible) - Show or hide a theme
  • setThemeOpacity(theme, opacity) - Set a theme's opacity (0..1)
  • refreshReleases() - Re-fetch the release list
  • on(event, handler) / off(event, handler) - Manage event handlers
  • getMap() / getContainer() - Access the map and container

Events

  • collapse / expand - Panel visibility changes
  • statechange - Any state change
  • releasechange - The active release changed
  • themechange - A theme's visibility or opacity changed
  • error - The release list could not be loaded (a fallback release is used)

OvertureMapsControlReact

React wrapper component for OvertureMapsControl.

Props

All OvertureMapsControl options plus:

Prop Type Description
map Map MapLibre GL map instance (required)
onStateChange function Callback fired when state changes

useOvertureMapsState

Custom React hook for managing control state.

const {
  state, // Current state
  setState, // Update entire state
  setCollapsed, // Set collapsed state
  setPanelWidth, // Set panel width
  setRelease, // Set the active release
  setThemeVisible, // Set a theme's visibility
  setThemeOpacity, // Set a theme's opacity
  reset, // Reset to initial state
  toggle, // Toggle collapsed state
} = useOvertureMapsState(initialState);

Exported Types

OvertureMapsControlOptions, OvertureMapsState, OvertureThemeState, OvertureMapsControlReactProps, OvertureMapsEvent, OvertureMapsEventHandler, OvertureTheme, OvertureGeometry, OvertureLayerDef, ThemeDefinition, ControlColorScheme, and ReleasesResponse are exported from both entry points (React-specific types from /react).

Helpers are also exported: THEMES, THEME_IDS, buildLayerSpecs, layerIdsForTheme, sourceIdForTheme, tileUrlForTheme, fetchReleases, ensurePmtilesProtocol, and more.

Dark and Light Mode

The control UI uses CSS custom properties and follows the browser's prefers-color-scheme by default. Set the theme option to 'light' or 'dark' to force a scheme:

const control = new OvertureMapsControl({ theme: "dark" });

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-overture-maps-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

Setup

# Clone the repository
git clone https://github.com/opengeos/maplibre-gl-overture-maps.git
cd maplibre-gl-overture-maps

# Install dependencies
npm install

# Start development server
npm run dev

Scripts

Script Description
npm run dev Start development server
npm run build Build the library and GeoLibre bundle
npm run build:lib Build the standalone MapLibre library
npm run build:geolibre Build the GeoLibre ESM and CSS bundle
npm run package:geolibre Build and zip the GeoLibre plugin bundle
npm run build:examples Build examples for deployment
npm run test Run tests
npm run test:ui Run tests with UI
npm run test:coverage Run tests with coverage
npm run lint Lint the code
npm run format Format the code

Project Structure

maplibre-gl-overture-maps/
├── geolibre-plugin/
│   └── plugin.json          # GeoLibre external plugin manifest
├── scripts/
│   └── package-geolibre-plugin.mjs
├── src/
│   ├── index.ts              # Main entry point
│   ├── geolibre.ts           # GeoLibre plugin wrapper entry point
│   ├── react.ts              # React entry point
│   ├── index.css             # Root styles
│   └── lib/
│       ├── core/             # Control, themes, releases, types
│       ├── hooks/            # React hooks
│       ├── utils/            # Utility functions
│       └── styles/           # Component styles
├── tests/                    # Test files
├── examples/                 # Example applications
│   ├── basic/               # Vanilla TypeScript example
│   └── react/               # React example
└── .github/workflows/        # CI/CD workflows

Docker

The examples can be run using Docker. The image is automatically built and published to GitHub Container Registry.

Pull and Run

# Pull the latest image
docker pull ghcr.io/opengeos/maplibre-gl-overture-maps:latest

# Run the container
docker run -p 8080:80 ghcr.io/opengeos/maplibre-gl-overture-maps:latest

Then open http://localhost:8080/maplibre-gl-overture-maps/ in your browser to view the examples.

Build Locally

# Build the image
docker build -t maplibre-gl-overture-maps .

# Run the container
docker run -p 8080:80 maplibre-gl-overture-maps

Available Tags

Tag Description
latest Latest release
x.y.z Specific version (e.g., 1.0.0)
x.y Minor version (e.g., 1.0)

Notes

  • Overture tiles are designed for x-ray inspection, not as a production basemap. See the Overture tiles docs.
  • The addresses and places themes only contain features at zoom 14 and above.
  • If the release list cannot be fetched (e.g. offline), the control falls back to a known release and emits an error event; pin a release with the release option to skip the fetch dependency.

License

MIT License - see LICENSE for details.

About

A MapLibre plugin for visualizating PMTiles from Overture Maps

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors