leaflet-wms-crop
v1.0.2
Published
A Leaflet.js plugin that clips/crops WMS layers to GeoJSON boundaries on the client side
Maintainers
Readme
Leaflet WMS Crop Plugin
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).
Installation
Option 1: npm (Recommended for React/Node.js projects)
npm install leaflet-wms-cropUsage in React/Next.js:
import 'leaflet-wms-crop';
// or
import 'leaflet-wms-crop/leaflet-wms-crop.js';Option 2: CDN (Recommended for HTML/vanilla JS)
Via GitHub (jsDelivr):
<script src="https://cdn.jsdelivr.net/gh/amanchry/leaflet-wms-crop@latest/leaflet-wms-crop.js"></script>Via npm (unpkg.com):
<script src="https://unpkg.com/leaflet-wms-crop@latest/leaflet-wms-crop.js"></script>Quick Start
Basic HTML Example
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
</head>
<body>
<div id="map" style="height: 100vh;"></div>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/amanchry/leaflet-wms-crop@latest/leaflet-wms-crop.js"></script>
<script>
// Create map
var map = L.map('map').setView([20, 77], 5);
// Add base layer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// Define boundary polygon (array of [lat, lng] coordinates)
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
];
// Create clipped WMS layer
var 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);
</script>
</body>
</html>API Reference
Main Method
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
Methods
setBoundary(boundary)
Update the clipping boundary dynamically.
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.
var currentBoundary = wmsLayer.getBoundary();
console.log(currentBoundary); // Array of [lat, lng] pairsBoundary Formats
The plugin supports multiple boundary formats for clipping WMS layers. The boundary will be automatically normalized internally.
1. Array of Coordinates
The simplest format: an array of [lat, lng] coordinate pairs.
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);2. L.LatLngBounds
Use Leaflet's LatLngBounds for rectangular boundaries.
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);3. L.Polygon
Use an existing Leaflet Polygon layer.
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);4. GeoJSON Polygon
Standard GeoJSON Polygon format. Note: GeoJSON uses [lng, lat] coordinate order, which is automatically converted.
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);5. GeoJSON MultiPolygon
GeoJSON MultiPolygon format. Only the first polygon in the MultiPolygon will be used.
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);6. GeoJSON Feature
A GeoJSON Feature object containing a Polygon or MultiPolygon geometry.
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);7. GeoJSON FeatureCollection (with Turf.js)
For FeatureCollection with multiple features, use Turf.js to merge them first:
// 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);
});React/Next.js Usage
Basic React Example
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 (
<div style={{ height: "100vh", width: "100vw" }}>
<div ref={mapDivRef} style={{ height: "100%", width: "100%" }} />
</div>
);
}
Next.js Configuration
If using Next.js, you may need to configure webpack to handle the plugin:
// next.config.js
module.exports = {
webpack: (config) => {
config.resolve.alias.canvas = false;
return config;
}
};Requirements
- Leaflet.js v1.0.0 or higher
- Turf.js (required for merging multiple features in GeoJSON FeatureCollection)
Live Demo
Check out the live demo with a complete working example:
The demo:
- Loads a GeoJSON boundary from URL
- Merges multiple features using Turf.js
- Clips WMS layer to the boundary
- Displays boundary outline
Links
- 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
License
MIT License - see LICENSE file for details.
Contributing
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
Acknowledgments
- Built for Leaflet.js
- Uses Turf.js for GeoJSON operations
- Inspired by the need for client-side WMS clipping functionality
