[英]How to handle D3 drag events when mousedown and mouseup happen on different elements?
我在使用d3拖动行为时遇到问题。 我之前已经回答过各种问题 ,但是我找不到针对自己特定问题的答案。
这是一个小提琴 ,它说明了我将要描述的问题。
我想要做的是在可拖动元素上具有单击处理程序,其中不应在dragend
上执行单击处理程序。 我知道在点击处理程序中我可以使用d3.event.defaultPrevented
,如果拖动了元素,则应将其设置为true。 当mouseup
事件发生在mousedown
事件以外的其他元素上时,就会出现问题。 当拖动的元素的移动速度比鼠标光标慢时,就会发生这种情况。 如果释放鼠标并且拖动的元素不在鼠标d3.event.defaultPrevented
则d3.event.defaultPrevented
设置为false,并且不会调用单击处理程序。 这使得无法确定在拖动后是否触发了click
事件。
在我的示例中,如果单击处理程序执行但d3.event.defaultPrevented
设置为true,则圆圈闪烁绿色。 同样,在单击处理程序中,可以防止传播,从而防止事件冒泡到svg单击处理程序。 如果未执行圆圈的单击处理程序,并且事件冒泡到svg单击处理程序,则如果d3.event.defaultPrevented
设置为true,则圆圈将闪烁蓝色,否则将闪烁红色。
我想要实现的是使圆圈在鼠标上方的任何位置都闪烁绿色或蓝色,以便能够知道单击事件是否在拖动之后发生。 这是否有可能,或者这是JavaScript /浏览器的本质限制吗? 如果是这样,是否有解决方法? 还是只需要在拖动圆时禁用圆的“减速”?
我在SO上发现了一个非常类似的问题 ,但实际上并没有一个有用的答案。
任何帮助表示赞赏!
编辑看起来像是在拖动过程中阻止元素减速的想法解决了这个问题。 但是我仍然会对使用事件信息可以实现这一点感兴趣。
这是小提琴的代码:
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;
});
当注释掉它时, node
的位置不会滞后于鼠标指针。 我不太明白上面的代码会发生什么。 “典型”方法类似于http://bl.ocks.org/mbostock/3750558上的粘力布局示例
更新:这是一种使您接近所追求的方式: https : //jsfiddle.net/ktbe7yh4/3/
我从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');
至:
flashNode(d3.event.defaultPrevented ? 'green' : 'orange');
并且您会看到,如果在指针直接指向圆圈时释放鼠标,它将闪烁绿色。 如果圆圈滞后于指针,并且您在圆圈停留在光标下方之前释放了鼠标,则它将闪烁橙色。 话虽如此,无论是否在指向圆圈的同时释放了鼠标按钮, dragend
处理程序中的数据元素似乎总是设置为开始拖动的圆圈。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.