Javascript 当mousedown和mouseup发生在不同的元素上时,如何处理D3拖动事件?
我遇到d3拖动行为的问题。我遇到的问题有很多种,但我找不到具体问题的答案 这说明了我要描述的问题 我想做的是在一个可拖动的元素上有一个click处理程序,其中click处理程序不应该在Javascript 当mousedown和mouseup发生在不同的元素上时,如何处理D3拖动事件?,javascript,d3.js,svg,dom-events,Javascript,D3.js,Svg,Dom Events,我遇到d3拖动行为的问题。我遇到的问题有很多种,但我找不到具体问题的答案 这说明了我要描述的问题 我想做的是在一个可拖动的元素上有一个click处理程序,其中click处理程序不应该在dragend上执行。我知道,在click处理程序中,我可以使用d3.event.defaultPrevented,如果拖动元素,则应将其设置为true。当mouseup事件发生在mousedown事件之外的另一个元素上时,就会出现问题。当拖动的元素的移动速度慢于鼠标光标时,会发生这种情况。如果释放鼠标并且拖动的元
dragend
上执行。我知道,在click处理程序中,我可以使用d3.event.defaultPrevented
,如果拖动元素,则应将其设置为true。当mouseup
事件发生在mousedown
事件之外的另一个元素上时,就会出现问题。当拖动的元素的移动速度慢于鼠标光标时,会发生这种情况。如果释放鼠标并且拖动的元素还未在鼠标下,则d3.event.defaultPrevented
设置为false,并且不会调用单击处理程序。这使得无法确定拖动后是否触发了单击
事件
在我的示例中,如果单击处理程序执行,但d3.event.defaultPrevented
设置为true,则圆圈闪烁绿色。此外,在单击处理程序中,阻止了传播,防止事件冒泡到svg单击处理程序。如果圆圈的click处理程序未执行,且事件在svg click处理程序中出现气泡,则圆圈将闪烁蓝色(如果d3.event.defaultPrevented
设置为true),否则将闪烁红色
我想要实现的是让圆圈闪烁绿色或蓝色,无论圆圈在鼠标上方的什么位置,以便能够知道拖动后是否发生单击事件。这是可能的,还是javascript/浏览器的特性限制了这一点?如果有,是否有解决办法?或者,我是否只需要在拖动圆时禁用它的“减速”
我发现了一个非常相似的答案,但是没有一个真正有用的答案
感谢您的帮助
编辑
看起来,在拖动过程中阻止元素减速的想法解决了问题。但我仍然很感兴趣,如果这是可能的使用事件信息可用
这是小提琴的代码:
var nodes = [{}];
var svg = d3.select('body')
.append('svg')
.attr({
width: 500,
height: 500
})
.on('click', function(){
var color = d3.event.defaultPrevented ? 'blue' : 'red';
flashNode(color);
});
var force = d3.layout.force()
.size([500, 500])
.nodes(nodes)
.friction(.2)
.on('tick', forceTickHandler);
var nodeElements = svg
.selectAll('circle');
nodeElements = nodeElements
.data(force.nodes())
.enter()
.append('circle')
.attr({
cx: 10,
cy: 10,
r: 10
})
.on('click', function(){
d3.event.stopPropagation();
var color = d3.event.defaultPrevented ? 'green' : 'orange';
flashNode(color);
})
.call(force.drag);
function forceTickHandler(e){
nodes.forEach(function(node) {
var k = e.alpha * 1.4;
node.x += (250 - node.x) * k;
node.y += (250 - node.y) * k;
});
nodeElements
.attr('cx', function(d, i){
return d.x;
})
.attr('cy', function(d, i){
return d.y;
});
};
function flashNode(color){
nodeElements
.attr('fill', color)
.transition()
.duration(1000)
.attr('fill', 'black');
}
force.start();
问题似乎来自更新节点位置的
forceTickHandler
中的代码:
nodes.forEach(function(node) {
var k = e.alpha * 1.4;
node.x += (250 - node.x) * k;
node.y += (250 - node.y) * k;
});
注释掉后,节点的位置不会滞后于鼠标指针。我真的不明白你想用上面的代码做什么。执行此操作的“典型”方式类似于
更新:这里有一种方法可以让你接近你想要的东西:
我从force.drag
创建了一个新的拖动处理程序,然后更新了dragend
上发生的事情,它似乎达到了预期的效果
代码更改是在创建拖动处理程序时进行的:
var drag = force.drag()
.on("dragend", function(d) {
flashNode('green');
});
然后更新节点的创建以使用新处理程序:
nodeElements = nodeElements
.data(force.nodes())
.enter()
.append('circle')
.attr({
cx: 10,
cy: 10,
r: 10
})
.on('click', function(){
d3.event.stopPropagation();
var color = d3.event.defaultPrevented ? 'green' : 'orange';
flashNode(color);
})
.call(drag);
拖动处理程序中的dragend
无论如何都会被调用,但它仍然会遇到您描述的类似问题,但您可以在处理程序中更好地处理它。要了解我在这里的意思,请尝试更改:
flashNode('green');
致:
你会看到,当鼠标指针直接指向圆圈时,如果你松开鼠标,它会闪烁绿色。如果圆落后于指针,并且在圆落在光标下之前释放鼠标,则它将闪烁橙色。话虽如此,dragend
处理程序中的数据元素似乎总是设置为开始拖动的圆圈,无论鼠标按钮是否在指向圆圈时松开。感谢您的回答!我知道问题源于勾选
处理程序和位置重新计算的滞后。我想要实现的是,当dragend
事件发生时,即使鼠标光标不再位于元素上,也要触发click处理程序。但现在我知道我是这样写的,这听起来有点不可能和愚蠢。我想在拖动元素时,我将不得不跳过位置的重新计算。我的想法是在画布和元素上进行一些类似但额外的交互。我用一种可能的方式更新了我的答案,以实现您所追求的结果。这是一个有点变通的方法,但它可能会让你保持你的节点移动的方式,你所追求的闪存行为。
flashNode(d3.event.defaultPrevented ? 'green' : 'orange');