An overlay class for Leaflet, a JS library for interactive maps. Allows drawing overlay using Pixi.js, a JavaScript library for drawing using WebGL that seamlessly falls back to HTML5's canvas if needed. Thanks to Leaflet.D3SvgOverlay for inspiration.
- No limitations to polylines, circles or geoJSON. Draw whatever you want with Pixi.js
- No need to reproject your geometries on zoom, this is done using scaling
- Zoom animation where Leaflet supports it
Compatible with Leaflet 0.7.x and 1.x
A very basic demo.
Largest US cities (1000 animated markers).
French cities (36700 animated markers).
Rotating markers with constant size during zoom
French presidential 2017 election results: first round and second round (36000 polygons).
French legislative 2017 election results: first round and second round (36000 polygons).
(graph-draw is used to display boundaries in the election demos when rendered in WebGL)
Leaflet.PixiOverlay is available as a npm package:
npm install leaflet-pixi-overlay
or can be included in a page with jsDelivr CDN.
Include Pixi.js and the PixiOverlay libraries:
<script src="pixi.min.js"></script>
<script src="L.PixiOverlay.min.js"></script>
Create a map:
var map = L.map(...);
Create an overlay:
var pixiOverlay = L.pixiOverlay(function(utils) {
// your drawing code here
}, new PIXI.Container());
Add it to the map:
pixiOverlay.addTo(map);
var loader = new PIXI.loaders.Loader();
loader.add('marker', 'img/marker-icon.png');
loader.load(function(loader, resources) {
var markerTexture = resources.marker.texture;
var markerLatLng = [51.5, -0.09];
var marker = new PIXI.Sprite(markerTexture);
marker.anchor.set(0.5, 1);
var pixiContainer = new PIXI.Container();
pixiContainer.addChild(marker);
var firstDraw = true;
var prevZoom;
var pixiOverlay = L.pixiOverlay(function(utils) {
var zoom = utils.getMap().getZoom();
var container = utils.getContainer();
var renderer = utils.getRenderer();
var project = utils.latLngToLayerPoint;
var scale = utils.getScale();
if (firstDraw) {
var markerCoords = project(markerLatLng);
marker.x = markerCoords.x;
marker.y = markerCoords.y;
}
if (firstDraw || prevZoom !== zoom) {
marker.scale.set(1 / scale);
}
firstDraw = false;
prevZoom = zoom;
renderer.render(container);
}, pixiContainer);
pixiOverlay.addTo(map);
});
var polygonLatLngs = [
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047],
[51.509, -0.08]
];
var projectedPolygon;
var triangle = new PIXI.Graphics();
var pixiContainer = new PIXI.Container();
pixiContainer.addChild(triangle);
var firstDraw = true;
var prevZoom;
var pixiOverlay = L.pixiOverlay(function(utils) {
var zoom = utils.getMap().getZoom();
var container = utils.getContainer();
var renderer = utils.getRenderer();
var project = utils.latLngToLayerPoint;
var scale = utils.getScale();
if (firstDraw) {
projectedPolygon = polygonLatLngs.map(function(coords) {return project(coords);});
}
if (firstDraw || prevZoom !== zoom) {
triangle.clear();
triangle.lineStyle(3 / scale, 0x3388ff, 1);
triangle.beginFill(0x3388ff, 0.2);
projectedPolygon.forEach(function(coords, index) {
if (index == 0) triangle.moveTo(coords.x, coords.y);
else triangle.lineTo(coords.x, coords.y);
});
triangle.endFill();
}
firstDraw = false;
prevZoom = zoom;
renderer.render(container);
}, pixiContainer);
pixiOverlay.addTo(map);
L.pixiOverlay(<function> drawCallback, <PIXI.Container> container, <options> options?)
drawCallback
- callback to draw/update overlay contents.container
- a Pixi container (a subclass ofPIXI.Container
).options
- overlay options object.
Drawing callback function
drawCallback(utils, eventOrCustomData)
utils
- helper object. Contains methods to work with layers coordinate system and scaling.eventOrCustomData
- Contains either the Leaflet event that causes the redraw (moveend
event) or a plain object{type: 'add'}
when the pixi layer is added to the map or the argument of aredraw
call.
Overlay options object
available fields:
padding
- (number; defaults to0.1
) How much to extend the drawing area around the map view (relative to its size).forceCanvas
- (bool; defaults tofalse
) Force use of a 2d-canvas for rendering.doubleBuffering
- (bool; default tofalse
) Activate double buffering to prevent flickering when refreshing display on some devices (especially iOS devices). This field is ignored if rendering is done with 2d-canvas.resolution
- (number; defaults to2
on retina devices and1
elsewhere) Resolution of the renderer.projectionZoom
- (function(map): Number; defaults to function that returns the average ofmap.getMinZoom()
andmap.getMaxZoom()
if the latter is finite else it returnsmap.getMinZoom() + 8
) returns the projection zoom level. Customizing this option can help if you experience visual artifacts.pane
- (string; defaults to'overlayPane'
) The Leaflet pane where the overlay container is inserted.destroyInteractionManager
- (bool; defaults tofalse
) Destroy PIXI Interaction Manager. This is useful when you do not need to use PIXI interaction.autoPreventDefault
- (bool; defaults totrue
) Customize PIXI Interaction ManagerautoPreventDefault
property. This option is ignored ifdestroyInteractionManager
istrue
. This should be set tofalse
in most situations to let all dom events flow from PIXI to leaflet but it is set by default for compatibility reason.preserveDrawingBuffer
- (bool; defaults tofalse
) Enables drawing buffer preservation, enable this if you need to call toDataUrl on the webgl context.clearBeforeRender
- (bool; defaults totrue
) This sets if the renderer will clear the canvas or not before the new render pass.shouldRedrawOnMove
- (function(e: moveEvent): Boolean; defaults tofunction () {return false;}
) Move events trigger a redraw when this function returnstrue
. For example usingfunction (e) {return e.flyTo || e.pinch;}
will trigger redraws duringflyTo
animation and pinch zooms.
Utils object
available methods:
latLngToLayerPoint(latLng, zoom?)
- (function) returnsL.Point
projected fromL.LatLng
in the coordinate system of the overlay.layerPointToLatLng(point, zoom?)
- (function) returnsL.LatLng
projected back fromL.Point
into the original CRS.getScale(zoom?)
- (function) return the current scale factor of the overlay or the scale factor associated to zoom value.getRenderer()
- (function) return the current PIXI renderer.getContainer()
- (function) return the PIXI container used in the overlay.getMap()
- (function) return the current map.
redraw(data)
- (function) trigger a refresh of the layer.data
is passed as second argument ofdrawCallback
function. This is useful for example when you modify something in thecontainer
or if you want to animate usingPIXI.ticker.Ticker
.
- Improve default
projectionZoom
function
- Fix a pinch zoom regression introduced in 1.8.0
- Add support for redrawing the layer during flyTo animations and pinch zooms. (This is disabled by default. See
shouldRedrawOnMove
option to enable it,) - Both pixi.js@5 and pixi.js-legacy@5 should be supported now.
- Add basic support for pixi.js-legacy@5
- Add
preserveDrawingBuffer
andclearBeforeRender
options
- Bug fixes
- Add options for PIXI Interaction Manager
- Improved documentation
- Improved behavior when
doubleBuffering
is enabled - Remove event listeners on layer remove wih Leaflet 0.7.x
- Add second argument to
drawCallback
, improving control over redraw logic - No need to recompute container transform on
redraw
calls (performance improvement)
- Add
redraw
method
- Add
doubleBuffering
option to get rid of flickering on iOS devices
- Minor improvements
- Add support for leaflet@0.7.x (thanks to dzwiedzmin)
- Initial release.
This code is provided under the MIT License (MIT).