我遇到了d3拖动行为的问题。我遇到的问题的变化是answered before,但我无法找到我特定问题的答案。
Here's a fiddle说明了我要描述的问题。
我想要做的是在可拖动元素上设置一个点击处理程序,其中点击处理程序不应该在dragend
上执行。我知道在click处理程序中我可以使用d3.event.defaultPrevented
,如果拖动了元素,则应该将其设置为true。当mouseup
事件发生在除mousedown
事件之外的其他元素上时,会出现问题。当拖动元素的移动比鼠标光标慢时,会发生这种情况。如果释放鼠标并且拖动的元素不在鼠标下,则d3.event.defaultPrevented
设置为false并且单击处理程序不会被调用。这使得无法确定在拖动之后是否触发了click
事件。
在我的示例中,如果单击处理程序执行但是d3.event.defaultPrevented
设置为true,则圆圈会闪烁绿色。同样在点击处理程序中,阻止传播阻止事件冒泡到svg单击处理程序。如果圆圈的点击处理程序没有执行,并且事件冒泡到svg点击处理程序,则如果d3.event.defaultPrevented
设置为true,则圆圈闪烁蓝色,否则闪烁红色。
我想要达到的目的是让圆圈闪烁绿色或蓝色,无论圆圈在鼠标的哪个位置,以便能够知道在拖动之后是否发生了点击事件。这是否可能或者这是javascript /浏览器性质的限制?如果有的话有解决方法吗?或者我只是禁用“减速”'它被拖动时的圆圈?
我在SO上发现了一个非常相似的question,但它并没有真正有用的答案。
任何帮助表示赞赏!
修改 看起来在拖动过程中阻止元素减速的想法解决了问题。但如果可以使用现有的事件信息,我仍然会感兴趣。
这里是小提琴的代码:
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();
答案 0 :(得分:0)
问题似乎来自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
处理程序中的数据元素似乎总是被设置为开始时拖动的圆圈,鼠标按钮是否在指向圆圈时被释放。