繁体   English   中英

当mousedown和mouseup发生在不同的元素上时,如何处理D3拖动事件?

[英]How to handle D3 drag events when mousedown and mouseup happen on different elements?

我在使用d3拖动行为时遇到问题。 之前已经回答过各种问题 ,但是我找不到针对自己特定问题的答案。

这是一个小提琴 ,它说明了我将要描述的问题。

我想要做的是在可拖动元素上具有单击处理程序,其中不应在dragend上执行单击处理程序。 我知道在点击处理程序中我可以使用d3.event.defaultPrevented ,如果拖动了元素,则应将其设置为true。 mouseup事件发生在mousedown事件以外的其他元素上时,就会出现问题。 当拖动的元素的移动速度比鼠标光标慢时,就会发生这种情况。 如果释放鼠标并且拖动的元素不在鼠标d3.event.defaultPreventedd3.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM