Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@acalcutt/maplibre-contour-pmtiles

Package Overview
Dependencies
Maintainers
0
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@acalcutt/maplibre-contour-pmtiles

Render contour lines from raster elevation tiles in maplibre-gl-js from pmtiles terrain sources

  • 0.1.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
23
decreased by-87.29%
Maintainers
0
Weekly downloads
 
Created
Source

maplibre-contour-pmtiles

maplibre-contour-pmtiles is a plugin to render contour lines in MapLibre GL JS from raster-dem pmtiles sources. It was forked to support pmtiles with http support on the web and http and local supoort in node.js.

Topographic map of Mount Washington

Live example #1 (Just Terrain) | Code
Live example #2 (w/ OpenMapTiles Style) | Code | Style

To use it, import the @acalcutt/maplibre-contour-pmtiles package with a script tag:

<script src="https://unpkg.com/@acalcutt/maplibre-contour-pmtiles@latest/dist/maplibre-contour-pmtiles.min.js"></script>

Or as an ES6 module: npm add @acalcutt/maplibre-contour-pmtiles

import mlcontour from "@acalcutt/maplibre-contour-pmtiles";

Then to use, first create a DemSource and register it with maplibre:

var demSource = new mlcontour.DemSource({
  url: "pmtiles://https://url/of/dem/source.pmtiles",
  encoding: "mapbox", // "mapbox" or "terrarium" default="terrarium"
  maxzoom: 12,
  worker: true, // offload isoline computation to a web worker to reduce jank
  cacheSize: 100, // number of most-recent tiles to cache
  timeoutMs: 10_000, // timeout on fetch requests
});
demSource.setupMaplibre(maplibregl);

When using scripts locally with node, url can also use the format

  url: "pmtiles:///local/path/to/pmtiles/source.pmtiles",
  url: "pmtiles://C://local//path//to//pmtiles//source.pmtiles",

You should also be able to use a regular non-pmtiles source with

  url: "https://url/of/dem/source/{z}/{x}/{y}.png",

Then configure a new contour source and add it to your map:

map.addSource("contour-source", {
  type: "vector",
  tiles: [
    demSource.contourProtocolUrl({
      // convert meters to feet, default=1 for meters
      multiplier: 3.28084,
      thresholds: {
        // zoom: [minor, major]
        11: [200, 1000],
        12: [100, 500],
        14: [50, 200],
        15: [20, 100],
      },
      // optional, override vector tile parameters:
      contourLayer: "contours",
      elevationKey: "ele",
      levelKey: "level",
      extent: 4096,
      buffer: 1,
    }),
  ],
  maxzoom: 15,
});

Then add contour line and label layers:

map.addLayer({
  id: "contour-lines",
  type: "line",
  source: "contour-source",
  "source-layer": "contours",
  paint: {
    "line-color": "rgba(0,0,0, 50%)",
    // level = highest index in thresholds array the elevation is a multiple of
    "line-width": ["match", ["get", "level"], 1, 1, 0.5],
  },
});
map.addLayer({
  id: "contour-labels",
  type: "symbol",
  source: "contour-source",
  "source-layer": "contours",
  filter: [">", ["get", "level"], 0],
  layout: {
    "symbol-placement": "line",
    "text-size": 10,
    "text-field": ["concat", ["number-format", ["get", "ele"], {}], "'"],
    "text-font": ["Noto Sans Bold"],
  },
  paint: {
    "text-halo-color": "white",
    "text-halo-width": 1,
  },
});

You can also share the cached tiles with other maplibre sources that need elevation data:

map.addSource("dem", {
  type: "raster-dem",
  encoding: "terrarium",
  tiles: [demSource.sharedDemProtocolUrl],
  maxzoom: 13,
  tileSize: 256,
});

How it works

DemSource.setupMaplibre uses MapLibre's addProtocol utility to register a callback to provide vector tile for the contours source. Each time maplibre requests a vector tile:

  • DemManager fetches (and caches) the raster-dem image tile and its neighbors so that contours are continuous across tile boundaries.
    • When DemSource is configured with worker: true, it uses RemoteDemManager to spawn worker.ts in a web worker. The web worker runs LocalDemManager locally and uses the Actor utility to send cancelable requests and responses between the main and worker thread.
  • decode-image.ts decodes the raster-dem image RGB values to meters above sea level for each pixel in the tile.
  • HeightTile stitches those raw DEM tiles into a "virtual tile" that contains the border of neighboring tiles, aligns elevation measurements to the tile grid, and smooths the elevation measurements.
  • isoline.ts generates contour isolines from a HeightTile using a marching-squares implementation derived from d3-contour.
  • vtpbf.ts encodes the contour isolines as mapbox vector tile bytes.

MapLibre sends that vector tile to its own worker, decodes it, and renders as if it had been generated by a server.

Why?

There are a lot of parameters you can tweak when generating contour lines from elevation data like units, thresholds, and smoothing parameters. Pre-generated contour vector tiles require 100+gb of storage for each variation you want to generate and host. Generating them on-the-fly in the browser gives infinite control over the variations you can use on a map from the same source of raw elevation data that maplibre uses to render hillshade.

License

maplibre-contour-pmtiles is licensed under the BSD 3-Clause License. It includes code adapted from:

FAQs

Package last updated on 02 Jan 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc