Leaflet GeometryUtil
Leaflet GeometryUtil is a utility library that extends Leaflet's core functionality with a wide array of geometric operations. It provides functions for calculating distances, bearings between points, interpolating points along polylines, locating points on lines, finding closest points or layers to a given geographic coordinate, rotating points around a center, and managing layers within a specified radius. The library seamlessly integrates with Leaflet's `L.LatLng` and layer objects, providing a cohesive API for complex geospatial computations directly within Leaflet applications. The current stable version is 0.10.3, released in December 2023, indicating active maintenance with several minor and patch releases per year to add features and address bugs. A key differentiator is its deep integration with the Leaflet ecosystem, offering a comprehensive set of geometric tools that feel native to Leaflet, rather than a standalone geometry library. It has included robust TypeScript definitions since version 0.10.0, significantly enhancing the developer experience for TypeScript projects by providing strong type checking and intellisense for all its utilities.
Common errors
-
ReferenceError: L is not defined
cause `leaflet.js` or `leaflet` module was not loaded or imported before `leaflet-geometryutil`.fixEnsure `leaflet` is loaded globally via a script tag or imported as a module before `leaflet-geometryutil`. E.g., `import 'leaflet'; import 'leaflet-geometryutil';` or `<script src="leaflet.js"></script><script src="leaflet.geometryutil.js"></script>`. -
TypeError: L.GeometryUtil.closest is not a function
cause `leaflet-geometryutil` script or module was not loaded/imported, or `L.GeometryUtil` was not properly assigned/augmented.fixVerify that `leaflet-geometryutil` is correctly included in your project. If using modules, ensure `import GeometryUtil from 'leaflet-geometryutil';` (or similar side-effect import) is present and executed. -
TypeError: Cannot read properties of undefined (reading 'distanceTo')
cause Often occurs when `map.latLngToLayerPoint` is called with an invalid map object or `latLngToLayerPoint` itself is undefined, usually because the map object is not initialized or passed correctly to `GeometryUtil` functions.fixEnsure that the `map` object passed as the first argument to `GeometryUtil` functions (e.g., `GeometryUtil.closest(map, ...)` or `GeometryUtil.distance(map, ...)`) is a valid and initialized `L.Map` instance.
Warnings
- breaking Version 0.8.1 removed a deprecated function from Leaflet 1.x. Users relying on this function will experience a breaking change upon upgrade.
- gotcha Leaflet must be loaded and available globally (as `L`) or properly imported before `leaflet-geometryutil` is used, especially in browser environments without a module bundler. The library extends the `L` object directly.
- gotcha The `closest` method previously used shallow copies for `latLngs` and had issues with the last segment on Polygons or nested Polygons in versions prior to 0.7.2. While fixed, be aware of potential subtle geometry calculation discrepancies if using older versions.
- gotcha Version 0.10.2 included changes to imports to accommodate `ngx-leaflet` organization. While this might primarily affect `ngx-leaflet` users, it highlights that specific module environments or custom bundling setups might need adjustment if relying on implicit import side-effects.
- breaking Leaflet 2.0 (currently in alpha, targeting stable November 2025) removes the global `L` object and replaces factory methods with constructors. `leaflet-geometryutil` heavily relies on augmenting `L`. This future change will likely break `leaflet-geometryutil` in its current form and require significant updates.
Install
-
npm install leaflet-geometryutil -
yarn add leaflet-geometryutil -
pnpm add leaflet-geometryutil
Imports
- GeometryUtil (ESM/TypeScript)
import { closest } from 'leaflet-geometryutil';import L from 'leaflet'; import GeometryUtil from 'leaflet-geometryutil';
- Global L.GeometryUtil (Side Effect Import)
import { GeometryUtil } from 'leaflet';import 'leaflet'; import 'leaflet-geometryutil'; // Then use L.GeometryUtil.functionName(map, ...)
- GeometryUtil (CommonJS)
const { closest } = require('leaflet-geometryutil');const L = require('leaflet'); const GeometryUtil = require('leaflet-geometryutil');
Quickstart
import L from 'leaflet';
import GeometryUtil from 'leaflet-geometryutil';
import 'leaflet/dist/leaflet.css';
// Ensure you have a div with id="map" in your HTML
// <div id="map" style="height: 400px; width: 600px;"></div>
const map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// Define a polyline
const polylinePoints = [
[51.505, -0.09],
[51.51, -0.08],
[51.50, -0.05],
[51.515, -0.07]
];
const polyline = L.polyline(polylinePoints, {color: 'blue'}).addTo(map);
// Example 1: Find the closest point on the polyline to a given point
const testPoint = L.latLng(51.51, -0.10);
L.marker(testPoint).addTo(map).bindPopup('Test Point').openPopup();
const closestPointResult = GeometryUtil.closest(map, polyline, testPoint);
if (closestPointResult) {
L.marker(closestPointResult.latlng, {
icon: L.divIcon({ className: 'my-div-icon', html: 'Closest' })
}).addTo(map);
console.log('Closest point on polyline:', closestPointResult.latlng.toString());
} else {
console.log('No closest point found (polyline might be empty).');
}
// Example 2: Interpolate a point on the line at 50% distance
const interpolatedPointResult = GeometryUtil.interpolateOnLine(map, polyline, 0.5);
if (interpolatedPointResult) {
L.circleMarker(interpolatedPointResult.latlng, {
radius: 5,
color: 'red'
}).addTo(map).bindPopup('Interpolated Point (50%)');
console.log('Interpolated point on polyline:', interpolatedPointResult.latlng.toString());
}