How can I stop event propagation on layer click events?
mapBox.on('click', layerId, function (e) {
console.log(e);
// e.stopPropagation(); which is not working
// e.originalEvent.stopPropagation(); which is not working
var popupHtml = getPopupHtmlWrapper(e.features[0]);
new mapboxgl.Popup({closeButton:false})
.setLngLat(e.lngLat)
.setHTML(popupHtml)
.addTo(mapBox);
});
Mapbox provides access to the original event. Which means whenever we want to limit a click
to the topmost layer clicked only, all we need to do is call e.originalEvent.preventDefault()
on the first layer and check for e.originalEvent.defaultPrevented
in the layers beneath:
this.map
.on('click', 'layer_1', function(e) { // topmost layer
e.originalEvent.preventDefault();
// layer_1 functionality
})
.on('click', 'layer_2', function(e) { // second topmost layer
if(!e.originalEvent.defaultPrevented) {
// click was performed outside of layer_1
e.originalEvent.preventDefault();
// layer_2 exclusive functionality
}
})
.on('click', 'layer_3', function(e) {
if(!e.originalEvent.defaultPrevented) {
// click was performed outside of layer_1 and layer_2
e.originalEvent.preventDefault();
// layer_3 exclusive functionality here...
}
...
})
Maybe we don't need a global variable, I got the same problems as you, and I fixed it with the solution:
mapbox.on('click', 'layer1', function(e){ e.originalEvent.cancelBubble = true; /* //or you can add an attr e['bubble'] = 'no'; */ console.log('layer1'); } mapbox.on('click', 'layer2', function(e){ if(e.originalEvent.cancelBubble){ return; } /* if(e['bubble] && e['bubble'] == 'no'){ return; } */ console.log('layer2'); }
One approach is to save the event coordinates of the click on the layer and then compare these coordinates with the underlying layer and its event coordinates.
let clickCoords = {};
this.map.on('click', 'points', event => {
clickCoords = event.point;
console.log('Layer click')
});
Now, detect a click on the map, not on the points layer
this.map.on('click', () => {
// check if coords are different, if they are different, execute whatever you need
if (clickCoords.x !== event.point.x && clickCoords.y !== event.point.y) {
console.log('Basemap click');
clickCoords = {};
}
});
Or, even better, use queryRenderedFeatures() .
this.map.on('click', event => {
if (this.map.queryRenderedFeatures(event.point).filter(feature => feature.source === YOURLAYERNAME).length === 0) {
console.log('Basemap click');
}
});
Here is a Mapbox example .
Was looking to find the same solution, but sharing event between the map and layer, so if layer, for example, was not clicked, I would like map click listener to be invoked, and opposite, if layer was clicked, I would like map click listener to be skipped
So I've ended up with the folowing:
// Event handler for layer
function(e) {
e.preventDefault()
// handle layer event
}
// Event handler for map
function(e) {
if(e.defaultPrevented) return
// handle map event
}
So, prevent default is working but you should check for defaultPrevented
property in event and handle it.
I am not aware of any simple way of handling this. I am assuming you are trying to prevent the click event from propagating to an other layer. What you can do is using a global variable storing that a click just happened at those coordinates. Then in your other click handler you check this case.
var recentClicks = {layer1 : null} mapBox.on('click', "layer1", function (e) { console.log(e); recentClicks["layer1"] = e.lngLat // Proceed to creating pop-up }); mapBox.on('click', "layer2", function (e) { console.log(e); if(recentClicks["layer1"] && recentClicks["layer1"][0] == e.lngLat[0] && recentClicks["layer1"][1] == e.lngLat[1]){ recentClicks["layer1"] = null return } else { // Proceed to treating layer 2 click event } });
With a bit of work, you can apply this to an infinite number of layers.
Per the suggestion by @Stophface, I used
e => {
const features = map.queryRenderedFeatures(e.point)
if (features[0].layer.id === myLayerName ) {
doMyClickAction(e)
}
}
so as to only do something with the event when the layer I care about in this instance is the first one that is clicked.
Some of the above suggestions worked after I adjusted my layer ordering by setting the beforeLayer
parameter when adding a layer:
https://docs.mapbox.com/mapbox-gl-js/example/geojson-layer-in-stack/
If none of the above suggestions work for you, try playing with the layer order and going through them again.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.