我有一个 D3 (v4) 可视化,其中包含许多形状,在某些情况下,它们会在大约三秒的时间内动画到新位置。这些形状具有单击和鼠标悬停事件侦听器,我希望仅当可视化项不移动时才将其激活。
执行此操作的简单方法很简单。我有一个名为
is_animating
的布尔变量,在动画开始时设置为 true
,在回调时设置为 false
,所以我只是将其添加到事件侦听器中:
shapes.on("click", function(d) {
if (is_animating) {
return;
}
// otherwise, business as usual
})
那很好,但我计划向形状添加大量事件侦听器,并且如果有一种更优雅的方式来拦截冒泡中较高的事件并且只执行一次而不是向每个事件添加此检查,我会喜欢它。但我不完全理解
d3.event
以及它如何处理冒泡。是否有一个简单的“主事件侦听器”(如果愿意的话),每当用户尝试执行某些操作时都会触发,如果 is_animating
为 true,这可能会导致事件短路?
D3 转换 API 中有一种方法可以控制是否存在与给定节点关联的任何活动转换 (d3.active)。
您可以使用它来检测节点上的活动转换,而无需引入额外的变量。
shapes.on("click", function(d) {
if (d3.active(this)) {
return;
}
// otherwise, business as usual
})
如果它适用于您设置的方式,您可以等到转换结束后再注册事件侦听器:
shapes
.transition()
.attr(...) // apply new positions, styles, etc
.on('end', function() {
// called per element once its transition has completed
d3.select(this)
.on('click', function() { /* business as usual */ })
})
另一个可能对您有用的有用之处是,您不必在
shapes
选择上注册事件侦听器,这会产生多个侦听器。相反,您可以订阅他们父母的活动。如果该父级是 d3 选择中的 svg,它看起来像这样
svg // assumes svg is a d3 selection containing every shape
.on('click', function() {
// to get the clicked element
d3.select(d3.event.target)
.attr(...)
// or, if you just want d, the datum of the shape
// that was clicked:
var d = select(d3.event.target).datum()
})
我认为没有办法防止你所描述的冒泡。我不知道为什么;我希望它能起作用,但我的测试没有成功。但应该注意的是,即使您能够停止传播,这也是从子级到父级的传播,而不是父级到子级的传播。