Skip to content

EricDalnas/leaflet.worldwrap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Leaflet.WorldWrap

A Leaflet plugin that makes vector layers render correctly and continuously across the antimeridian (the ±180° longitude line).

The Problem

Leaflet's tile layer already repeats the world seamlessly when you pan left or right. Vector layers do not. A route crossing the Pacific disappears at ±180°, or draws a line straight across the entire map in the wrong direction.

Other approaches split the feature into two pieces at the antimeridian. This breaks the geometry, the popup, any downstream GIS processing, and looks wrong at the seam.

The Approach

Leaflet.WorldWrap never splits anything.

  1. Coordinates are normalised so consecutive vertices never jump more than 180° of longitude, eliminating the "wrong-way" line across the map.
  2. A shadow clone is maintained for every tracked layer in each world copy that is currently visible on screen (plus a one-world buffer on each side so clones exist before they scroll into view).
  3. As you pan, stale shadows are removed and new ones are created in real time on Leaflet's move event — not just after panning stops — so there is no visible pop-in during fast panning.

Demo

Open demo.html in a browser. Pan east or west, zoom in and out, and watch the features appear seamlessly in every world copy.

Installation

Script tag:

<script src="leaflet.worldwrap.js"></script>

Usage

Pass worldWrap: true when creating your map. Every layer you add after that is handled automatically — no changes to your layer code required.

var map = L.map('map', {
    worldWrap: true,
    center: [10, 180],
    zoom: 3
});

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);

// These all just work — no special handling needed:
L.polyline([[35, 139], [40, -150], [37, -122]]).addTo(map);
L.polygon([[-12, 176], [-12, -179], [-22, -179], [-22, 176]]).addTo(map);
L.circle([0, 180], { radius: 800000 }).addTo(map);
L.marker([21, -157]).addTo(map);
L.geoJSON(myGeoJsonData).addTo(map);

Options

Option Type Default Description
worldWrap boolean false Enable world-wrapping for this map.

Supported Layer Types

Type Notes
L.Marker Shadow markers update in real time during drag.
L.Circle Shadow placed at shifted centre; radius unchanged.
L.CircleMarker Pixel-radius circle; only centre is shifted.
L.Polyline Coordinates normalised to prevent wrong-way lines.
L.Polygon Includes L.Rectangle. Rings are each normalised.
L.GeoJSON Each child feature is tracked individually.
L.FeatureGroup Each child layer is tracked individually.
L.LayerGroup Recurses into children; watches for future adds/removes.

How It Works — World Index Arithmetic

The map viewport spans some range of longitude, e.g. 90°W to 270°E when looking at the Pacific. Leaflet divides the longitude line into 360°-wide strips called world copies. World 0 is −180° to +180°. World −1 is −540° to −180°. World +1 is +180° to +540°, and so on.

// World index from a longitude:
Math.floor((lng + 180) / 360)

On every move event the plugin computes which world indices are visible, adds a shadow shifted by k × 360° for each visible world k ≠ 0, and removes any shadow for a world that is no longer visible.

Known Limitations

  • Editing shadows: Shadow copies are independent Leaflet layers. Editing one with Leaflet.draw or Leaflet.transform will not propagate back to the original or to other shadows.

  • Custom layer types: Only the built-in Leaflet vector types listed above are cloned. Custom layer subclasses that do not extend one of those types will be ignored.

  • Performance with large layer counts: Each tracked layer gets one full Leaflet clone per visible world copy (typically 2–4 at normal zoom levels). For small to medium datasets this is negligible. At large scales — thousands of features, or a dense GeoJSON layer — the overhead of maintaining and rendering that many extra SVG/Canvas elements can become noticeable. If you hit performance problems, consider clustering small features with Leaflet.markercluster, simplifying geometry before adding it to the map, or only adding the plugin to maps where the antimeridian region is actually relevant.

Browser / Leaflet Compatibility

Tested against Leaflet 1.9.x. Should work with any Leaflet 1.x build. No external dependencies beyond Leaflet itself.

ES5-compatible; no transpilation required.

Contributing

Bug reports and pull requests are welcome on GitHub.

License

MIT © Eric Dalnas

About

A Leaflet plugin that makes vector layers render correctly and continuously across the antimeridian (the ±180° longitude line).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors