A Leaflet.js plugin that clips/crops WMS layers to GeoJSON boundaries on the client side
npm install leaflet-wms-crop


A lightweight Leaflet.js plugin that clips/crops WMS TileLayers on the client-side, so the WMS layer is only visible inside a specified boundary (Polygon, GeoJSON, or extent).
``bash`
npm install leaflet-wms-crop
Usage in React/Next.js:
`javascript`
import 'leaflet-wms-crop';
// or
import 'leaflet-wms-crop/leaflet-wms-crop.js';
Via GitHub (jsDelivr):
`html`
Via npm (unpkg.com):
`html`
`html`
`javascript`
L.tileLayer.wms.clipped(baseUrl, options, boundary)
#### Parameters
- baseUrl (String): WMS server URL
- options (Object): WMS layer options
- layers (String): Comma-separated layer names (required)format
- (String): Image format, default: 'image/png'transparent
- (Boolean): Enable transparency, default: trueopacity
- (Number): Layer opacity 0-1, default: 1attribution
- (String): Attribution texttileSize
- (Number): Tile size in pixels, default: 256
- boundary: Boundary to clip to (see Boundary Formats below)
#### Returns
L.TileLayer.WMS.Clipped - A Leaflet tile layer clipped to the boundary
#### setBoundary(boundary)
Update the clipping boundary dynamically.
`javascript
var newBoundary = [
[28.0, 68.0],
[38.0, 68.0],
[38.0, 98.0],
[28.0, 98.0],
[28.0, 68.0]
];
wmsLayer.setBoundary(newBoundary);
`
#### getBoundary()
Get the current clipping boundary.
`javascript`
var currentBoundary = wmsLayer.getBoundary();
console.log(currentBoundary); // Array of [lat, lng] pairs
The plugin supports multiple boundary formats for clipping WMS layers. The boundary will be automatically normalized internally.
The simplest format: an array of [lat, lng] coordinate pairs.
`javascript
var boundary = [
[35.6, 68.0], // NW
[35.6, 97.5], // NE
[6.5, 97.5], // SE
[6.5, 68.0], // SW
[35.6, 68.0] // Close polygon
];
var wmsLayer = L.tileLayer.wms.clipped(url, options, boundary);
`
Use Leaflet's LatLngBounds for rectangular boundaries.
`javascript`
var bounds = L.latLngBounds([6.5, 68.0], [35.6, 97.5]); // [south, west], [north, east]
var wmsLayer = L.tileLayer.wms.clipped(url, options, bounds);
Use an existing Leaflet Polygon layer.
`javascript
var polygon = L.polygon([
[35.6, 68.0],
[35.6, 97.5],
[6.5, 97.5],
[6.5, 68.0]
]);
var wmsLayer = L.tileLayer.wms.clipped(url, options, polygon);
`
Standard GeoJSON Polygon format. Note: GeoJSON uses [lng, lat] coordinate order, which is automatically converted.
`javascript
var geoJsonPolygon = {
"type": "Polygon",
"coordinates": [[
[68.0, 35.6], // [lng, lat]
[97.5, 35.6],
[97.5, 6.5],
[68.0, 6.5],
[68.0, 35.6] // Close polygon
]]
};
var wmsLayer = L.tileLayer.wms.clipped(url, options, geoJsonPolygon);
`
GeoJSON MultiPolygon format. Only the first polygon in the MultiPolygon will be used.
`javascript
var geoJsonMultiPolygon = {
"type": "MultiPolygon",
"coordinates": [[[
[68.0, 35.6],
[97.5, 35.6],
[97.5, 6.5],
[68.0, 6.5],
[68.0, 35.6]
]]]
};
var wmsLayer = L.tileLayer.wms.clipped(url, options, geoJsonMultiPolygon);
`
A GeoJSON Feature object containing a Polygon or MultiPolygon geometry.
`javascript
var geoJsonFeature = {
"type": "Feature",
"properties": {
"name": "India Boundary"
},
"geometry": {
"type": "Polygon",
"coordinates": [[
[68.0, 35.6],
[97.5, 35.6],
[97.5, 6.5],
[68.0, 6.5],
[68.0, 35.6]
]]
}
};
var wmsLayer = L.tileLayer.wms.clipped(url, options, geoJsonFeature);
`
For FeatureCollection with multiple features, use Turf.js to merge them first:
`javascript`
// Load GeoJSON from URL
fetch('https://example.com/boundary.geojson')
.then(response => response.json())
.then(geoJson => {
let mergedPolygon = geoJson.features[0];
// Merge all features using Turf.js
for (let i = 1; i < geoJson.features.length; i++) {
mergedPolygon = turf.union(mergedPolygon, geoJson.features[i]);
}
// Extract coordinates and convert [lng, lat] to [lat, lng]
const geometry = mergedPolygon.geometry;
const coordinates = geometry.coordinates[0].map(coord => [coord[1], coord[0]]);
// Create clipped WMS layer
var wmsLayer = L.tileLayer.wms.clipped(url, options, coordinates);
wmsLayer.addTo(map);
});
`jsx
import { useEffect, useRef } from "react";
import L from "leaflet";
import "leaflet-wms-crop";
export default function MapComponent() {
const mapDivRef = useRef(null);
const mapRef = useRef(null);
useEffect(() => {
if (!mapDivRef.current || mapRef.current) return;
// Create map
const map = L.map(mapDivRef.current).setView([20, 77], 5);
mapRef.current = map;
// Base layer
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "Ā© OpenStreetMap contributors",
}).addTo(map);
// India boundary (simple bbox polygon)
const boundary = [
[35.6, 68.0], // NW
[35.6, 97.5], // NE
[6.5, 97.5], // SE
[6.5, 68.0], // SW
[35.6, 68.0], // close
];
// Create clipped WMS layer
const wmsLayer = L.tileLayer.wms.clipped(
"https://services.terrascope.be/wms/v2",
{
layers: "WORLDCOVER_2021_MAP",
format: "image/png",
transparent: true,
opacity: 1,
},
boundary
);
wmsLayer.addTo(map);
return () => {
map.remove();
mapRef.current = null;
};
}, []);
return (
`
If using Next.js, you may need to configure webpack to handle the plugin:
`javascript``
// next.config.js
module.exports = {
webpack: (config) => {
config.resolve.alias.canvas = false;
return config;
}
};
- Leaflet.js v1.0.0 or higher
- Turf.js (required for merging multiple features in GeoJSON FeatureCollection)
Check out the live demo with a complete working example:
š View Demo
The demo:
- Loads a GeoJSON boundary from URL
- Merges multiple features using Turf.js
- Clips WMS layer to the boundary
- Displays boundary outline
- npm Package: https://www.npmjs.com/package/leaflet-wms-crop
- GitHub Repository: https://github.com/amanchry/leaflet-wms-crop
- Live Demo: https://amanchry.github.io/leaflet-wms-crop/
- Issues: https://github.com/amanchry/leaflet-wms-crop/issues
MIT License - see LICENSE file for details.
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
- Built for Leaflet.js
- Uses Turf.js for GeoJSON operations
- Inspired by the need for client-side WMS clipping functionality