微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 d3 圆包装中拖动带有孩子的节点?

如何解决如何在 d3 圆包装中拖动带有孩子的节点?

我一直在尝试使用此代码作为基础 https://codepen.io/MrHen/pen/GZQOPW 拖入 d3 打包节点。不幸的是,我找不到一种方法可以使用,这样当带有子节点的节点被拖动时,它的(可见)子节点会随着父节点移动。我用这个函数来拖动圆圈:

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

例如,在上面的示例中,我希望能够拖动第 1 层(浅蓝色)上的节点,当我这样做时,他们的孩子会改变他们的位置,以便他们(在视觉上)留在父母的边界内。

>

谢谢!

解决方法

首先删除根节点和中间节点上的pointer-events: none。然后设置一个小递归来遍历一个节点的后代并更新它们的位置:

  function recurOnChildren(d) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    if (!d.children) return;
    d.children.forEach(c => {
      recurOnChildren(c);
    });
  }

并从您的拖动处理程序调用:

  var drag = d3.behavior.drag()
    .on("drag",function(d,i) {
      recurOnChildren(d);
      draw();
    })

运行代码:

var margin = 20,diameter = 960;

var color = d3.scale.linear()
  .domain([-1,5])
  .range(["hsl(152,80%,80%)","hsl(228,30%,40%)"])
  .interpolate(d3.interpolateHcl);

var pack = d3.layout.pack()
  .padding(2)
  .size([diameter - margin,diameter - margin])
  .value(function(d) {
    return d.size;
  })

var svg = d3.select("body").append("svg")
  .attr("width",diameter)
  .attr("height",diameter)
  .append("g")
  .attr("transform","translate(" + diameter / 2 + "," + diameter / 2 + ")");

d3.json("https://gist.githubusercontent.com/mbostock/7607535/raw/695f8ed6298c06a946406c707200a1f6b21875d8/flare.json",function(error,root) {
  if (error) throw error;

  var focus = root,nodes = pack.nodes(root),view;

  function recurOnChildren(d) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    if (!d.children) return;
    d.children.forEach(c => {
      recurOnChildren(c);
    });
  }

  var drag = d3.behavior.drag()
    .on("drag",i) {
      recurOnChildren(d);
      draw();
    })

  var circle = svg.selectAll("circle")
    .data(nodes)
    .enter().append("circle")
    .attr("class",function(d) {
      return d.parent ? d.children ? "node node--middle" : "node node--leaf" : "node node--root";
    })
    .style("fill",function(d) {
      return d.children ? color(d.depth) : null;
    });

  var text = svg.selectAll("text")
    .data(nodes)
    .enter().append("text")
    .attr("class","label")
    .style("fill-opacity",function(d) {
      return d.parent === root ? 1 : 0;
    })
    .style("display",function(d) {
      return d.parent === root ? "inline" : "none";
    })
    .text(function(d) {
      return d.name;
    });

  var node = svg.selectAll("circle,text");

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

  d3.select("body")
    .style("background",color(-1))

  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;
    });
  }
});
.node {
  cursor: pointer;
}

.node:hover {
  stroke: #000;
  stroke-width: 1.5px;
}

.node--leaf {
  fill: white;
}

.label {
  font: 11px "Helvetica Neue",Helvetica,Arial,sans-serif;
  text-anchor: middle;
  text-shadow: 0 1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 -1px 0 #fff;
}

.label {
  pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。