在mapbox gl js中的图层上注册点击事件时如何操作事件冒泡

Posted

技术标签:

【中文标题】在mapbox gl js中的图层上注册点击事件时如何操作事件冒泡【英文标题】:How to manipulate event bubbling when registering click event upon a layer in mapbox gl js 【发布时间】:2018-05-14 13:31:36 【问题描述】:

如何停止层点击事件的事件传播?

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);
);

【问题讨论】:

你想阻止事件冒泡到什么程度? @mollymerp 我已经尝试将 cancelBubble 属性设置为 true,也是 stopPropagation 方法但没有成功(在我从回调中获得的 e.originalEvent 对象上) 【参考方案1】:

Mapbox 提供对原始事件的访问。这意味着每当我们想将click 限制为仅单击的最顶层时,我们需要做的就是在第一层调用e.originalEvent.preventDefault() 并在下面的层中检查e.originalEvent.defaultPrevented

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...
    
...
  )

【讨论】:

【参考方案2】:

也许我们不需要全局变量,我遇到了和你一样的问题,我用解决方案解决了它:

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');

【讨论】:

为什么if(e.originalEvent.cancelBubble)... true,当你在你的函数体中用mapbox.on('click', 'layer2', function(e)覆盖e 仅供参考,根据 MDN “Event 接口的 cancelBubble 属性是 Event.stopPropagation() 的历史别名”。 (developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)【参考方案3】:

一种方法是保存点击图层的事件坐标,然后将这些坐标与底层图层及其事件坐标进行比较。

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 = ;
  
);

或者,更好的是,使用queryRenderedFeatures()。

this.map.on('click', event => 
   if (this.map.queryRenderedFeatures(event.point).filter(feature => feature.source === YOURLAYERNAME).length === 0) 
    console.log('Basemap click');
  
);

这是Mapbox example。

【讨论】:

【参考方案4】:

根据@Stophface 的建议,我使用了

e => 
  const features = map.queryRenderedFeatures(e.point)
  if (features[0].layer.id === myLayerName ) 
    doMyClickAction(e)
  

以便仅当我在此实例中关心的图层是第一个被单击的图层时才对事件执行某些操作。

【讨论】:

【参考方案5】:

正在寻找相同的解决方案,但在地图和图层之间共享事件,因此,例如,如果未单击图层,我希望调用地图单击侦听器,相反,如果单击图层,我希望跳过地图点击监听器

所以我得到了以下结果:

// Event handler for layer
function(e) 
  e.preventDefault()
  // handle layer event


// Event handler for map
function(e) 
  if(e.defaultPrevented) return
  // handle map event

因此,防止默认设置起作用,但您应该检查事件中的 defaultPrevented 属性并进行处理。

【讨论】:

【参考方案6】:

我不知道有任何简单的方法来处理这个问题。我假设您正试图阻止单击事件传播到其他层。您可以做的是使用一个全局变量来存储在这些坐标上刚刚发生的点击。然后在您的其他点击处理程序中检查这种情况。

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
    
);

通过一些工作,您可以将其应用于无限数量的层。

【讨论】:

【参考方案7】:

在添加层时通过设置beforeLayer 参数调整层顺序后,上述一些建议有效:

https://docs.mapbox.com/mapbox-gl-js/example/geojson-layer-in-stack/

如果以上建议都不适合您,请尝试使用层顺序并再次检查它们。

【讨论】:

以上是关于在mapbox gl js中的图层上注册点击事件时如何操作事件冒泡的主要内容,如果未能解决你的问题,请参考以下文章

Mapbox GL JS:样式未完成加载

如何在 mapbox-gl 中为图层文本字段添加背景颜色

在 Mapbox-GL-JS 中 minzoom 和 maxzoom 到底做了啥?

Mapbox GL JS:如果单击标记,则忽略地图单击事件

在 mapbox gl js 中删除源不会删除其图层

在“填充”类型的 mapbox gl js 层中:我们可以控制笔画粗细吗?