d3js阻止点击拖动事件

d3js preventing drag on click event

本文关键字:拖动 事件 d3js      更新时间:2023-09-26

我正在尝试在d3js中绘制一个UI,其中我有一个顶部面板,我应该能够将dragdrop元素复制到一个组中并将它们复制。我已经实现了这个目标,但我的代码中有一个错误。我实际想做的是拖动circle并复制它。但当我单击顶部面板中的circle时,它会自动触发拖动事件并自行复制。我该如何制止这种行为?

<svg height="600" width="600" style="background: black">
    <g>
        <rect x="0" y="0" , width="600" height="40" style="fill:gold;"></rect>
        <circle id='drag' cx="15" cy="20" init-cx="15" init-cy="20" r="10"
                style="stroke: white; stroke-width: 2px; fill:blue"/>
    </g>
    <g id="playground">
        <g>
            <circle id='top' cx="180" cy="120" r="30" style="stroke: white; stroke-width: 2px; fill:white"/>
        </g>
        <g>
            <circle id='top' cx="200" cy="220" r="30" style="stroke: white; stroke-width: 2px; fill:white"/>
        </g>
        <g>
            <circle id='top' cx="320" cy="150" r="50" style="stroke: white; stroke-width: 2px; fill:white"/>
        </g>
    </g>
</svg>
<script>
    $(document).ready(function () {

        var move = d3.behavior.drag()
            .on('drag', function () {
                console.log('dragging');
                var curr = d3.select(this)
                    .attr({
                        cx: d3.mouse(this)[0],
                        cy: d3.mouse(this)[1]
                    })

            })
            .on('dragend', function () {
                var curr = d3.select(this);
                d3.select('#playground')
                    .append('circle')
                    .attr({
                        cx : curr.attr('cx'),
                        cy : curr.attr('cy'),
                        r : curr.attr('r')
                    })
                    .style({
                        fill : 'white',
                        stroke : 'red',
                        'stroke-width' : '2px'
                    })
                ;
                curr.attr({
                    cx : curr.attr('init-cx'),
                    cy : curr.attr('init-cx')
                });
            })
            ;

        d3.select('#drag').call(move);

    });

</script>

这是我工作的小提琴。https://jsfiddle.net/fawzan/my2g724L/

希望这对您有用,看一看我在"dragend"中添加了一些代码,也就是说,在这里,我通过使用circle的属性(如init-cx和init-cy)来决定是否在操场上创建/附加一个圆圈。我添加的代码是

var initX = (curr.attr('init-cx')*1);
var currX = (curr.attr('cx')*1);
var initY = (curr.attr('init-cy')*1);
var currY = (curr.attr('cy')*1);                  
if(((currX) > (initX+20)) || ((currY) > (initY+20))){
//Here code to append a circle to playground
}

Fiddle

:D

您只需要检查拖动结束事件的目标是同一个圆,并且只有在它们不匹配的情况下才复制该圆。

.on('dragend', function() {
    if (d3.event.sourceEvent.target != this) {
      var curr = d3.select(this);
      d3.select('#playground')
        .append('circle')
        .attr({
          cx: curr.attr('cx'),
          cy: curr.attr('cy'),
          r: curr.attr('r')
        })
        .style({
          fill: 'white',
          stroke: 'red',
          'stroke-width': '2px'
        });
      curr.attr({
        cx: curr.attr('init-cx'),
        cy: curr.attr('init-cx')
      });
    }
});

var move = d3.behavior.drag()
  .on('drag', function() {
    console.log('dragging');
    console.log(this)
    console.log(this)
    var curr = d3.select(this)
      .attr({
        cx: d3.mouse(this)[0],
        cy: d3.mouse(this)[1]
      })
  })
  .on('dragend', function() {
    if (d3.event.sourceEvent.target != this) {
      var curr = d3.select(this);
      d3.select('#playground')
        .append('circle')
        .attr({
          cx: curr.attr('cx'),
          cy: curr.attr('cy'),
          r: curr.attr('r')
        })
        .style({
          fill: 'white',
          stroke: 'red',
          'stroke-width': '2px'
        });
      curr.attr({
        cx: curr.attr('init-cx'),
        cy: curr.attr('init-cx')
      });
    }
  });
d3.select('#drag').call(move);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg height="600" width="600" style="background: black">
  <g>
    <rect x="0" y="0" , width="600" height="40" style="fill:gold;"></rect>
    <circle id='drag' cx="15" cy="20" init-cx="15" init-cy="20" r="10" style="stroke: white; stroke-width: 2px; fill:blue" />
  </g>
  <g id="playground">
    <g>
      <circle id='top' cx="180" cy="120" r="30" style="stroke: white; stroke-width: 2px; fill:white" />
    </g>
    <g>
      <circle id='top' cx="200" cy="220" r="30" style="stroke: white; stroke-width: 2px; fill:white" />
    </g>
    <g>
      <circle id='top' cx="320" cy="150" r="50" style="stroke: white; stroke-width: 2px; fill:white" />
    </g>
  </g>
</svg>

单击时,您的curr.attr('cx')偏移量返回15。因此,您可以通过在dragend方法上添加条件来阻止默认操作:

if(curr.attr('cx')==15){
   return false;
}

更通用:

var isClicked = false;
var move = d3.behavior.drag()
    .on('dragstart', function() {
        isClicked = true;
    })
    .on('drag', function() {
        isClicked = false;
        var curr = d3.select(this)
            .attr({
                cx: d3.mouse(this)[0],
                cy: d3.mouse(this)[1]
            })
    })
    .on('dragend', function() {
        var curr = d3.select(this);
        if (!isClicked) {
            d3.select('#playground')
                .append('circle')
                .attr({
                    cx: curr.attr('cx'),
                    cy: curr.attr('cy'),
                    r: curr.attr('r')
                })
                .style({
                    fill: 'white',
                    stroke: 'red',
                    'stroke-width': '2px'
                });
        }
        curr.attr({
            cx: curr.attr('init-cx'),
            cy: curr.attr('init-cx')
        });
    });

d3.select('#drag').call(move);
d3.select('#drag').on('click', click);
function click(d) {
    isClicked = true;
}

结账Fiddle:

更多信息

使用布尔值监视是否启动拖动。通过这种方式,您可以停止拖动功能。

$(document).ready(function () {
    var isDragged = false;
    var move = d3.behavior.drag()
        .on('drag', function () {
            console.log('dragging');
            isDragged = true;
            var curr = d3.select(this)
                .attr({
                    cx: d3.mouse(this)[0],
                    cy: d3.mouse(this)[1]
                })

        })
        .on('dragend', function () {
            if (!isDragged) return;
            isDragged = false;
            var curr = d3.select(this);
            d3.select('#playground')
                .append('circle')
                .attr({
                    cx : curr.attr('cx'),
                    cy : curr.attr('cy'),
                    r : curr.attr('r')
                })
                .style({
                    fill : 'white',
                    stroke : 'red',
                    'stroke-width' : '2px'
                })
            ;
            curr.attr({
                cx : curr.attr('init-cx'),
                cy : curr.attr('init-cx')
            });
        })
        ;

    d3.select('#drag').call(move);

});

对于D3 v4(可能适用于v5和v6),您可以确定节点在dragged事件期间的位置,并查看它是否与其原始位置不同。假设没有,则永远不会调用alphaTarget

例如:

function dragstarted(d) {
    // if (!d3.event.active) simulation.alphaTarget(0.2).restart();
    d.fx = d.x;
    d.fy = d.y;
}
function dragged(d) {
    if (d3.event.active && (d.fy != d3.event.y || d.fx != d3.event.x)) {
        simulation.alphaTarget(0.5).restart();
    }
    d.fx = d3.event.x;
    d.fy = d3.event.y;
}

function dragended(d) {
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
}