简体   繁体   English

d3点击拖动事件嵌套

[英]d3 click and drag event nesting

I am nesting a lot of elements inside of ag element like so:我在 ag 元素中嵌套了很多元素,如下所示:

<g>
    <rect></rect>
    <text></text>
    ...
</g>

However, there are some rects that I want to be able to have drag events of their own.然而,有一些矩形我希望能够拥有它们自己的拖动事件。 The problem is that when you put stuff inside of ag tag, its size expands to contain those tags.问题是,当您将内容放入 ag 标签时,它的大小会扩展以包含这些标签。 So even though I can assign events there is no way they can be triggered because the g tag's event is somehow more important even though the rect is on top of it.因此,即使我可以分配事件,也无法触发它们,因为 g 标记的事件在某种程度上更重要,即使 rect 位于它之上。

Is there some sort of workaround that you guys know of?你们知道有某种解决方法吗?

EDIT: Here's a simple complete case in its entirety.编辑:这是一个完整的简单案例 A rect and a circle inside a g. g 内的一个矩形和一个圆。 The g is draggable and the circle should be draggable too but is not. g 是可拖动的,圆圈也应该是可拖动的,但不是。

var gDragBehav = d3.behavior.drag()
    .on('drag', gDragDrag)

function gDragDrag(d,i) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    d3.select(this)
        .attr('x', d.x)
        .attr('y', d.y)
        .attr("transform", "translate(" + d.x + "," + d.y + ")");
}

var circleDragBehav = d3.behavior.drag()
    .on('drag', circleDragDrag);

function circleDragDrag(d,i) {
    console.log('dragging a circle')
    d.cx += d3.event.dx;
    d.cy += d3.event.dy;
    d3.select(this)
        .attr('cx', d.cx)
        .attr('cy', d.cy)
}

var svg = d3.select('body').append('svg')

var g = svg.selectAll('g').data([{x: 10, y:10}])
    .enter().append('g').call( gDragBehav )

g.append( 'rect' ).attr('width', 100 ).attr('height', 100 )

g.selectAll( 'circle' ).data([{cx: 0, cy:0}])
    .enter().append( 'circle' )
    .attr('cx', function(d) { return d.cx } ).attr('cy', function(d) { return d.cy } )
    .attr('r', 40 )
    .call( circleDragBehav )

EDIT: Here's some of the code编辑:这是一些代码

var group = this.d3svg.selectAll('g' + '.' + this.className)
  .attr('x', this.drawFuncs['x'] )
  .attr('y', this.drawFuncs['y'] )
  .attr("transform", this.drawFuncs['translate'] )
  .attr('class', this.className )
  .call(gDragBehav)
  .on( 'click', blockClickMenu )

ports = ['AtomicPort']
for ( port in ports ) {  
  drawPort.call( this, group, ports[port] )
}

function drawPort( d3svg, portName, redraw ) {
  d3svg.selectAll('rect.' + portName)
    .data( function(d) { return d.ports[ portName ] } )
    .enter().append('rect')
    .attr('x', this.drawFuncs['x'] )
    .attr('y', this.drawFuncs['y'] )
    .attr('width', this.drawFuncs['width'] )
    .attr('height', this.drawFuncs['height'] )
    .attr('class', portName )
    .call(portDragBehav)

  var portDragBehav = d3.behavior.drag()
    .on('drag', portDragDrag);

  function portDragDrag(d,i) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    d3.select(this)
      .attr('x', d.x)
      .attr('y', d.y)
    d3.event.stopPropagation();
  }

  var gDragBehav = d3.behavior.drag()
    .on('dragstart', gDragStart)

  function gDragDrag(d,i) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    d3.select(this)
      .attr('x', d.x)
      .attr('y', d.y)
      .attr("transform", "translate(" + d.x + "," + d.y + ")");
    d3.event.stopPropagation(); //Uncaught TypeError: Object #<Object> has no method 'stopPropagation'
  }

An SVG <g> element does not have a size or area; SVG <g>元素没有大小或面积; it is a transparent container for all its descendants, and cannot intercept events for other elements (unless you are adding an event listener to be triggered during the 'capture phase').它是其所有后代的透明容器,并且不能拦截其他元素的事件(除非您要添加一个要在“捕获阶段”期间触发的事件侦听器)。

As a parent element, events bubble up to it;作为父元素,事件会向上冒泡; likely what you are seeing is that whatever event you're using to trigger the drag start (mousedown?) on the <rect> is also bubbling up to the <g> and starting a concurrent drag of that .您可能看到的是,无论您使用什么事件来触发<rect>上的拖动开始(鼠标按下?),也会冒泡到<g>并开始并发拖动

To fix this, you want to stop your event from bubbling.要解决此问题,您需要阻止事件冒泡。 In your event handler for the mousedown (or whatever) on the <rect> add:<rect>上的鼠标按下(或其他)的事件处理程序中添加:

function startDrag(evt){
  // whatever your code is here
  evt.stopPropagation();
}

Without your actual code (or better, a pared-down test case) it's hard to know for sure, or help you further.如果没有您的实际代码(或者更好的是,精简的测试用例),则很难确定或进一步帮助您。


Edit Here's a working version of your simple example: http://jsfiddle.net/ZrCQE/2/编辑这是您的简单示例的工作版本: http://jsfiddle.net/ZrCQE/2/

Specifically, apparently d3.event is not the event itself, but an object with a sourceEvent property that references the actual event.具体来说,显然d3.event不是事件本身,而是带有引用实际事件的sourceEvent属性的 object。

var dragGroup = d3.behavior.drag()
  .on('dragstart', function() {
    console.log('Start Dragging Group');
  }).on('drag', function(d, i) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    d3.select(this).attr("transform", "translate("+d.x+","+d.y+")");
  });

var dragCircle = d3.behavior.drag()
  .on('dragstart', function(){
    d3.event.sourceEvent.stopPropagation();
    console.log('Start Dragging Circle');
  })
  .on('drag', function(d,i){
    d.cx += d3.event.dx;
    d.cy += d3.event.dy;
    d3.select(this).attr('cx', d.cx).attr('cy', d.cy)
  });

var svg = d3.select('body').append('svg').attr('viewBox','-50 -50 300 300');

var g = svg.selectAll('g').data([{x:10,y:10}])
  .enter().append('g').call(dragGroup);

g.append('rect').attr('width', 100).attr('height', 100);

g.selectAll('circle').data([{cx: 90,cy:80}])
  .enter().append('circle')
    .attr('cx', function(d){ return d.cx })
    .attr('cy', function(d){ return d.cy })
    .attr('r', 30)
    .call(dragCircle);​

I have a similar sort of issue ( http://jsfiddle.net/j8RZN/1/ ), except the suggested workaround does not seem to be helping.我有类似的问题 ( http://jsfiddle.net/j8RZN/1/ ),除了建议的解决方法似乎没有帮助。

userBox.data([userBox]).call(d3.behavior.drag() //makes the box to move
//titleBox.data([userBox]).call(d3.behavior.drag()  //does not make the box move
.on("dragstart", function() {})
.on("drag", function(d, i) {
console.log('box being dragged');
d.attr("transform", "translate(" + (d3.event.x) +  "," + (d3.event.y) + ")");
})
.on("dragend", function() {}));

circleDrag.call(d3.behavior.drag()
.on("dragstart", function() {})
.on("drag", function(d, i) {
 d3.event.sourceEvent.stopPropagation();
 console.log('small rectangle being dragged');
})
.on("dragend", function() {}));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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