d3 单击并拖动事件嵌套 [英] d3 click and drag event nesting

查看:39
本文介绍了d3 单击并拖动事件嵌套的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 g 元素中嵌套了很多元素,如下所示:

I am nesting a lot of elements inside of a g element like so:

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

但是,有些矩形我希望能够拥有自己的拖动事件.问题是当你把东西放在 g 标签中时,它的大小会扩展以包含这些标签.因此,即使我可以分配事件,也无法触发它们,因为 g 标记的事件在某种程度上更重要,即使 rect 在它之上.

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 a g tag, its size expands to contain those tags. 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.

你们知道有什么解决方法吗?

Is there some sort of workaround that you guys know of?

这里是一个简单的完整案例.g 内的一个矩形和一个圆.g 是可拖动的,圆也应该是可拖动的,但不是.

Here's a simple complete case in its entirety. A rect and a circle inside a g. The g is draggable and the circle should be draggable too but is not.

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 )

这是一些代码

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'
  }

推荐答案

一个 SVG 元素没有大小或面积;它是其所有后代的透明容器,不能拦截其他元素的事件(除非您添加要在捕获阶段"期间触发的事件侦听器).

An SVG <g> element does not have a size or area; 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').

作为父元素,事件冒泡到它;可能您看到的是,您用来触发 <rect> 上的拖动开始(鼠标按下?)的任何事件也冒泡到 <g> 并开始并发拖动那个.

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.

要解决此问题,您需要阻止事件冒泡.在 上的 mousedown(或其他)事件处理程序中添加:

To fix this, you want to stop your event from bubbling. In your event handler for the mousedown (or whatever) on the <rect> add:

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

如果没有您的实际代码(或者更好的精简测试用例),就很难确定或进一步帮助您.

编辑 这是您的简单示例的工作版本:http://jsfiddle.net/ZrCQE/2/

Edit Here's a working version of your simple example: http://jsfiddle.net/ZrCQE/2/

具体来说,显然 d3.event 不是事件本身,而是具有引用实际事件的 sourceEvent 属性的对象.

Specifically, apparently d3.event is not the event itself, but an object with a sourceEvent property that references the actual event.

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);​

这篇关于d3 单击并拖动事件嵌套的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆