【问题标题】:How to drag nodes with children in d3 circle packing?如何在d3圆形包装中拖动带有子节点的节点?
【发布时间】:2021-01-19 16:51:23
【问题描述】:

我一直在尝试使用此代码作为基础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 层(浅蓝色)上的节点,当我这样做时,他们的孩子会改变他们的位置,以便他们(视觉上)保持在他们父母的边界内。

谢谢!

【问题讨论】:

  • 您只在叶子节点(没有子节点的节点)上设置拖动事件。那么,您的意思是要在孩子移动时拖动父母吗?您的问题描述相反。
  • 你好@Mark,非常感谢你的回答。我想要做的是在我移动父母时拖动孩子。我将拖动设置在父母移动的父母身上,但孩子没有。

标签: d3.js nested position drag


【解决方案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", function(d, 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>

【讨论】:

    猜你喜欢
    • 2013-01-20
    • 2013-01-27
    • 1970-01-01
    • 2014-02-09
    • 2021-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多