d3将拖放添加到打包的圈

时间:2016-04-11 16:15:25

标签: d3.js

我正在尝试使用此作为起点添加将一个圆圈内的圆圈拖动到另一个圆圈的功能:https://bl.ocks.org/mbostock/7607535

我已添加此代码:

var drag = d3.behavior.drag()

        .on("drag", function(d,i) {
            d.x += d3.event.dx
            d.y += d3.event.dy
            d3.select(this).attr("transform", function(d,i){
                return "translate(" + [ d.x,d.y ] + ")"
            })
        });

然后尝试像这样附加它:

svg.selectAll("circle").call(drag);

node.call(drag);

我有两个问题,一个是在我拖动时正确定位圆圈(我认为是因为我需要保存原点)而另一个是如何选择要按照假设拖动的子圆圈我想要父圈。理想情况下,我希望能够选择任何圆圈,并能够将其放入任何其他圆圈。有没有办法附加拖动行为,所以这只是工作或我需要查看数据结构,以便计算出我可能试图拖动的最低级别的圆圈?

2 个答案:

答案 0 :(得分:2)

Zoomable示例中有很多内容,其中一些与您的意图发生冲突。快速修复:

  

一个是在我拖动时正确定位圆圈(我认为这是因为我需要保存原点)。

定位圆圈需要在ondrag事件期间进行更新。这是我使用的:

  var drag = d3.behavior.drag()
    .on("drag", function(d, i) {
      d.x += d3.event.dx;
      d.y += d3.event.dy;
      draw();
    });

  function draw() {
    var k = diameter / (root.r * 2 + margin);
    node.attr("transform", function(d) {
      return "translate(" + (d.x - root.x) * k + "," + (d.y - root.y) * k + ")";
    });
    circle.attr("r", function(d) {
      return d.r * k;
    });
  }

draw函数替换了Zoomable示例中的zoomTo函数。可以使用缩放功能进行缩放,但需要额外考虑。

  

另一个是如何选择要拖动的子圆圈,因为它假设我想要父圆圈。

Zoomable示例有这个CSS:

.label,
.node--root,
.node--leaf {
  pointer-events: none;
}

如果要定位叶节点,则必须删除CSS规则的.node--leaf部分。您还可以添加新规则以关闭非叶节点的事件:

.attr("class", function(d) {
  return d.parent ? d.children ? "node node--middle" : "node node--leaf" : "node node--root";
})

请注意添加node--middle

  

理想情况下,我希望能够选择任何圆圈并将其放入任何其他圆圈。有没有办法附加拖动行为,所以这只是工作或我需要查看数据结构,以便计算出我可能试图拖动的最低级别的圆圈?

您可以毫不费力地拖动它,但拖动行为不会自动将更改传播到数据结构中。如果您希望更改实际层次结构,则需要执行一些额外步骤:

  1. 检测叶节点结束的位置
  2. 相应地更改叶节点的父节点
  3. 重新计算整个包装
  4. 重绘/动画新包装
  5. 第1步将是棘手的。我没有一个帮助这个的例子。您可以使用dragstop事件快速检测拖动事件结束的位置 - 技巧将确定哪个节点位于该停靠点下方。

答案 1 :(得分:0)

它不允许您拖动最多的子节点,因为有pointer-events: none的css样式应用于这些节点,因此它们永远不会触发拖动。所以你需要取出部分或全部这些课程:

.label,
.node--root,
.node--leaf {
  pointer-events: none;
}

这样可以拖动孩子,但不会阻止拖动父母的能力。如果您不希望父母被拖走,您不得.call(drag)。这样做的方法是使用drag在所有圈子的集合上调用filter

因此,在创建圈子后,您可以这样做:

circle
  .filter( function(d) { return d.children ? false : true; } )
  .call(drag);

这只会将拖拽应用于没有孩子的东西。

由于不知道原点导致拖动过程中的错误定位,你是对的。我确定您需要在dragstart上保存原始圈子位置,然后在拖动过程中将d3.event.dx添加到该位置。