-
-
Save perliedman/84ce01954a1a43252d1b917ec925b3dd to your computer and use it in GitHub Desktop.
// Since overlays are VectorGrid layers with canvas rendering, | |
// they don't support clicking through them (the topmost canvas | |
// swallows the event, lower layers will not see it). | |
// We workaround this by this hack (inspired by | |
// http://www.vinylfox.com/forwarding-mouse-events-through-layers/): | |
// | |
// All overlays are in their own Leaflet pane. When a click hits a | |
// layer in the pane, we first handle the event like normal, and then | |
// hit the event handler below this comment. | |
// | |
// The event handler will hide the original target layer's DOM element, | |
// and then find out which DOM element is under it, and re-dispatch the same | |
// event on that element, and continuing this process until all layers | |
// have been dispatched, or abort if a layer's event handler stops the | |
// event. | |
// | |
// We currently only do this for clicks, since hiding and redisplaying | |
// elements is a performance hog if you do it in for example mousemove. | |
overlayPane = map.createPane('my-overlays'); | |
L.DomEvent.on(overlayPane, 'click', function(e) { | |
if (e._stopped) { return; } | |
var target = e.target; | |
var stopped; | |
var removed; | |
var ev = new MouseEvent(e.type, e) | |
removed = {node: target, display: target.style.display}; | |
target.style.display = 'none'; | |
target = document.elementFromPoint(e.clientX, e.clientY); | |
if (target && target !== overlayPane) { | |
stopped = !target.dispatchEvent(ev); | |
if (stopped || ev._stopped) { | |
L.DomEvent.stop(e); | |
} | |
} | |
removed.node.style.display = removed.display; | |
}); |
I found the cursor not functioning properly as having multiple layers should do: the cursor changes to <pointer>
(the "finger") only at the top vector tiles. Here's the workaround I did:
For the event dispatching, dispatch also the mousemove
(instead of mouseover
) event, additional to the click
event:
function enactDispatch(paneObj){
L.DomEvent.on(paneObj, 'mousemove click', function(e) {
if (e._stopped) { return; }
var target = e.target;
var stopped;
var removed;
var ev = new MouseEvent(e.type, e)
removed = {node: target, display: target.style.display};
target.style.display = 'none';
target = document.elementFromPoint(e.clientX, e.clientY);
target.dispatchEvent(ev)
L.DomEvent.stop(e);
removed.node.style.display = removed.display;
});
}
vecLayer1 = map.createPane('veclayer1');
enactDispatch(vecLayer1);
vecLayer2 = map.createPane('veclayer2');
enactDispatch(vecLayer2);
Then when adding the vector tile layers, rebuild the mouse cursor change by assigning$('.leaflet-tile-loaded')
properties on mouseover
and mouseout
events.
function vectorGrid(veclayerpath,paneName){
var vgrd = L.vectorGrid.protobuf(veclayerpath+"{z}/{x}/{y}.mvt", {
rendererFactory: L.canvas.tile,
vectorTileLayerStyles: {
<<the styles>>
},
interactive: true,
getFeatureId: function(f) {
return f.properties.id;
},
pane: paneName
})
.on('click', function(e) {
<<the click response>>
})
.on('mouseover', function(e) {
$('.leaflet-tile-loaded').addClass("leaflet-interactive");
})
.on('mouseout', function(e) {
$('.leaflet-tile-loaded').removeClass("leaflet-interactive");
})
return vgrd
}
vectorGrid(<<path_to_backend_of_veclayer1>>,'veclayer1').addTo(map);
vectorGrid(<<path_to_backend_of_veclayer2>>,'veclayer2').addTo(map);
Hope you find this helpful.
Also, in case the above I said is implemented, click
events are somehow disabled when adding GeoJSON layers to their panes.
I used mousedown
instead as a workaround.
Also, if the web map is also for use of mobile devices, you might have already used leaflet-touch-helper.js
to make line features easier to click. In that case, you'll also need to add mousedown
event to the listeners in leaflet-touch-helper.js
, otherwise the extraWeight-clickables will not work.
Unlike vector tile layers though, mouseover
and mouseout
don't need to be reconstructed.
The click works OK but I'd need to set the popup to stay by
L.map('map', { ... closePopupOnClick: false }
. Otherwise the popup shows up in a flash then gone.