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

@geoleaf-plugins/measure

v1.0.13

Published

GeoLeaf Measure Plugin — Distance, surface, GPS & annotation tools with GeoJSON export

Readme

@geoleaf-plugins/measure

GeoLeaf plugin for measuring distances, surfaces (rectangle / circle / polygon), recording a GPS track and adding georeferenced annotations on an interactive map, with GeoJSON export.

  • MIT License — public registry (npmjs.org)
  • Requires @geoleaf/core loaded before this plugin
  • ESM only — no CommonJS/UMD
  • Integrates with @geoleaf-plugins/print for annotation export

Installation

npm install @geoleaf-plugins/measure

Load in your HTML after @geoleaf/core:

<script
    type="module"
    src="node_modules/@geoleaf-plugins/measure/dist/geoleaf-measure.plugin.js"
></script>

In a standard GeoLeaf deployment the plugin is registered lazily and its bundle is fetched on first use of the measure toolbar button — no manual <script> tag is required.


Quick start

Once the plugin is loaded it mounts the GeoLeaf.Measure namespace and registers a toolbar button (shown when ui.showMeasure / showButton is enabled). Clicking the button opens a floating sub-menu containing:

  1. Distance tool — click two or more points; re-click the last vertex, double-click (or Space) to finish — the re-click is what makes a touch double-tap work. Segment lengths and total distance are shown.
  2. Rectangle tool — drag from one corner to the opposite one; the area and side lengths are shown.
  3. Circle tool — drag from the center outward to set the radius; area, radius and circumference are shown.
  4. Polygon tool — click successive vertices; close by snapping onto the first vertex, double-clicking, or pressing C. Area, side lengths and perimeter are shown.
  5. GPS track — records the device position in real time and can be closed as a polygon.
  6. Tooltip annotation — click to place a resizable, editable tooltip box anchored to a map coordinate; drag to reposition.
  7. Unit cyclers — toggle distance units (m / km) and area units (m² / ha / km²).
  8. Clear all — removes every measure and annotation.
  9. GeoJSON export — downloads all active features as GeoJSON.

All features are mirrored to localStorage and restored on the next page load.


Public API (GeoLeaf.Measure)

startMeasure(type)

Arms the given tool programmatically (initialises the engine on first call).

type MeasureType = "distance" | "rect" | "circle" | "polygon" | "gps" | "annotation-tooltip";

function startMeasure(type: MeasureType): void;

stopMeasure()

Deactivates the currently active tool and returns to idle state.

function stopMeasure(): void;

clearAll()

Removes all measure features, annotation overlays, drawing layers and the localStorage entry.

function clearAll(): void;

getCollection()

Returns a deep copy of the current GeoJSON FeatureCollection (measures + annotations).

function getCollection(): GeoJSON.FeatureCollection;

exportGeoJSON(opts?)

Builds an RFC 7946 GeoJSON Blob (enriched properties) and, by default, triggers a file download. Pass { download: false } to obtain the Blob without downloading. The download uses the priority pattern navigator.share (iOS) → <a download> (desktop/Android) → window.open fallback.

function exportGeoJSON(opts?: {
    download?: boolean; // default true
    fileName?: string; // overrides cfg.exportFileName
}): Promise<Blob>;

setUnits(u) / getUnits()

Changes the active distance and/or area units (re-renders visible labels), or reads the current selection.

interface Units {
    distance: "m" | "km" | "auto";
    area: "m2" | "ha" | "km2" | "auto";
}

function setUnits(u: Partial<Units>): void;
function getUnits(): Units;

getPrintableAnnotations()

Returns annotation descriptors consumed by @geoleaf-plugins/print when composing the print output. Only annotations within the current map viewport are included.

interface PrintableAnnotation {
    kind: "label" | "tooltip";
    lngLat: [number, number];
    text: string;
    widthPx?: number;
    heightPx?: number;
    anchor: "bottom" | "center";
}

function getPrintableAnnotations(): PrintableAnnotation[];

registerMeasureType(type, def)

Registers a custom measure tool, armable afterwards through startMeasure(type).

interface MeasureTypeDef {
    cursor?: string; // defaults to "crosshair"
    onActivate?: (map: unknown) => void;
    onDeactivate?: () => void;
}

function registerMeasureType(type: string, def: MeasureTypeDef): void;

The plugin wraps your callbacks in the same envelope the built-in tools carry — exclusive interaction mode, cursor, and a guard that puts the cursor back if another handler overwrites it. Map listeners, drawing state and feature production stay yours.

No button appears in the floating menu. Its buttons come from a static table carrying an icon and i18n keys, which MeasureTypeDef does not provide, and enabledTools only filters that table. Trigger your tool from your own UI:

GeoLeaf.Measure.registerMeasureType("elevation", {
    cursor: "cell",
    onActivate: (map) => {
        /* wire your own listeners */
    },
    onDeactivate: () => {
        /* clean them up */
    },
});

myButton.addEventListener("click", () => GeoLeaf.Measure.startMeasure("elevation"));

Calling stopMeasure(), clearAll(), closing the measure menu, or arming another tool all disarm it and call onDeactivate. An identifier that was never registered arms nothing.


Configuration (modules.measure)

Add a modules.measure object to your GeoLeaf profile configuration. All fields are optional — the defaults below are applied otherwise.

{
    "modules": {
        "measure": {
            "enabled": true,
            "showButton": true,
            "defaultDistanceUnit": "km",
            "defaultAreaUnit": "ha",
            "enabledTools": ["distance", "rect", "circle", "polygon", "gps", "annotation-tooltip"],
            "snapPx": 12,
            "circleSteps": 64,
            "maxFeatures": 500
        }
    }
}

| Field | Type | Default | Description | | --------------------- | --------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enabled | boolean | true | Enables / disables the plugin entirely (skips toolbar + listener wiring when false). | | showButton | boolean | true | Shows the toolbar button. Aliased by the core-level ui.showMeasure. | | position | string | "left" | Toolbar slot position. | | menuPosition | string | { top, left } | "top-left" | Initial position of the floating sub-menu. | | defaultDistanceUnit | "m" | "km" | "auto" | "m" | Default distance unit. | | defaultAreaUnit | "m2" | "ha" | "km2" | "auto" | "m2" | Default area unit. | | snapPx | number | 12 | Snap tolerance (px) for polygon closure (min 1). | | circleSteps | number | 64 | Segments approximating a circle (clamped to 8–256). | | enabledTools | MeasureType[] | ["distance", "rect", "circle", "polygon", "gps", "annotation-tooltip"] | Tools shown in the sub-menu (unknown ids are filtered out). | | tooltipDefaultSize | { width, height } | { "width": 160, "height": 80 } | Default size of a new tooltip annotation box (px). | | labelMaxChars | number | 120 | Maximum characters in an annotation label. | | persist | boolean | true | Mirrors the FeatureCollection to localStorage. Writes are debounced (~300 ms) and a pending one is flushed when the page is hidden or unloaded, so a measure finished just before a reload is kept. | | storageKey | string | "geoleaf.measure.fc" | localStorage key used for persistence. | | maxFeatures | number | 500 | Maximum stored features (min 1). | | gpsCloseThresholdM | number | 15 | Proximity (m) to the start that prompts closing the GPS track as a polygon. | | gpsMaxJumpMps | number | 25 | Maximum speed (m/s) used to reject GPS outliers. | | decimals | { distance, area } | { "distance": 0, "area": 0 } | Decimal places for displayed values. | | exportFileName | string | "mesures.geojson" | Default filename for GeoJSON export. |

Note — plugin settings live under modules.measure (Plugin Contract v1, INV-CONFIG). The legacy root key measureConfig is no longer read.


Print integration

When both @geoleaf-plugins/measure and @geoleaf-plugins/print are loaded, the print modal shows an Annotations checkbox. When ticked, annotations are composited onto the exported map image at their geographic positions, using getPrintableAnnotations(). No extra configuration is required.


GPS track

The GPS tool records the device position using the GeoLeaf geolocation control.

  • Requires browser geolocation permission and HTTPS.
  • Outlier fixes are rejected using gpsMaxJumpMps (default 25 m/s).
  • When the live position returns within gpsCloseThresholdM metres of the start, a prompt offers to close the track as a polygon (area is then computed).
  • The track is exported as a LineString (or Polygon when closed) feature in GeoJSON export.

Annotations

Tooltip annotations are DOM overlays anchored to geographic coordinates.

  • Create: activate the annotation tool and click on the map; a resizable text box appears in edit mode.
  • Edit: click the annotation box to re-enter edit mode; type, then click outside to commit.
  • Drag: pointer-drag the annotation to move it; the anchor coordinate updates accordingly.
  • Delete: hover the annotation box; click the × button that appears.
  • Persist: annotations are included in getCollection() / exportGeoJSON() and are restored from localStorage on the next page load.

Limitations

  • GPS on mobile: requires HTTPS and granted geolocation permission. Accuracy depends on device hardware.
  • Annotation drag on touch: pointer events are used; pinch-zoom on an annotation may conflict with map panning.
  • Print annotation positioning: annotations are positioned using the print canvas pixel coordinates; very large or very small scales may shift anchor positions slightly.
  • No undo: clearAll() is irreversible.

Bundle budget

| Part | Size (gzip) | | ------------- | --------------------- | | Plugin bundle | ~32 KB (budget 60 KB) |

Turf.js geodesic helpers (@turf/distance, @turf/area, @turf/circle, @turf/centroid, @turf/helpers) are bundled inline. maplibre-gl is a peer dependency provided by the host page.


MIT License

Copyright © 2026 Mattieu Pottier. See LICENSE for details.