Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapbox gl js - overlapping layers and mouse event handling

Is there any clear and reliable (and described) mechanism to control mouse events for overlapping layers in Mapbox GL JS? For example, I have 3 overlapping layers, but want that click handler was called only for the layer that is on top, but not for all 3 layers - is that possible somehow? For now, as a workaround, I track MouseEnter and MouseLeave events and call an appropriate handler based on that. But I don't like this solution at all because it spoils my code with excess logic.

like image 556
Anton Pilyak Avatar asked May 11 '18 14:05

Anton Pilyak


People also ask

What is evented in Mapbox GL JS?

Map and other Mapbox GL JS classes emit events in response to user interactions or changes in state. Evented is the interface used to bind and unbind listeners for these events. This page describes the different types of events that Mapbox GL JS can raise.

What is Mapbox GL JS?

Mapbox GL JS is a JavaScript library for interactive, customizable vector maps on the Web. It renders map data from Mapbox Vector Tiles, using the Mapbox Style specification and hardware-accelerated graphics (WebGL). Mapbox GL JS is part of a cross-platform ecosystem, which also includes native SDKs for applications on Android and iOS.

How to avoid collision between layers in Mapbox?

Properties should be prefixed to avoid collisions, like 'mapbox:'. Optional number between 0 and 24 inclusive. The minimum zoom level for the layer. At zoom levels less than the minzoom, the layer will be hidden.

What is the use of mapboxzoomevent?

MapBoxZoomEvent is a class used to generate the events 'boxzoomstart', 'boxzoomend', and 'boxzoomcancel'. For a full list of available events, see Map events. originalEvent ( MouseEvent): The DOM event that triggered the boxzoom event. Can be a MouseEvent or KeyboardEvent . target ( Map): The Map instance that triggered the event.


1 Answers

It is not very clear what problem you're experiencing. If you have three layers (layer1, layer2, layer3) where the top layer is layer1 and you only want to respond to click events for it, you do:

map.on('click', 'layer1', function(e) {...})

If this is not what you mean, perhaps clarify what you mean by "overlapping layers" and "want that click handler was called only for the layer that is on top". Also, please provide your current code, with an example of what the problem is.

EDIT

A click event can apply to all layers beneath the clicked point, so if you want to capture several layers in a single click event, and identify the topmost item clicked:

map.on('click', function(e) {
  let f = map.queryRenderedFeatures(e.point, { layers: ['layer1','layer2','layer3'] });
  if (f.length) {
    console.log(f[0]);  //topmost feature
  }
});

But, if you want to capture the click event for just a single layer you can specify that layer in two ways:

map.on('click', function(e) {
  let f = map.queryRenderedFeatures(e.point, { layers: ['layer1'] });
  if (f.length) {
    console.log(f[0]);
    return;
  } 
  f = map.queryRenderedFeatures(e.point, { layers: ['layer2'] });
  if (f.length) {
    console.log(f[0]);
    return;
  }
  f = map.queryRenderedFeatures(e.point, { layers: ['layer3'] });
  if (f.length) {
    console.log(f[0]);
  }
});

Or as in the original answer above:

map.on('click', 'layer1', function(e) {
  let f = map.queryRenderedFeatures(e.point, { layers: ['layer1'] });
  if (f.length) {
    console.log(f[0]);
  } 
  return;
});
like image 101
Steve Bennett Avatar answered Oct 27 '22 09:10

Steve Bennett