Javascript D3可折叠力布局混合儿童和父母

Javascript D3可折叠力布局混合儿童和父母,javascript,jquery,d3.js,force-layout,Javascript,Jquery,D3.js,Force Layout,我正在处理JSFIDLE上的示例 似乎我已经将所有内容正确地组织起来,因为孩子们与他们的父母有着正确的联系,并且显示了正确的文本 我遇到的问题如下 主节点(位于中心)不可折叠。与所定位的示例相比,该图的整体行为有些浮躁 折叠节点时颜色不变,折叠父节点时将显示父节点的子节点。在多个节点上单击几下后,孩子和家长似乎会发生切换 我的问题是代码的哪一部分可能导致这种情况,为什么 下面是我用来生成图表的代码。数据丢失,但由JSFIDLE提供。感谢您的帮助,提前谢谢 var width = 960,

我正在处理JSFIDLE上的示例

似乎我已经将所有内容正确地组织起来,因为孩子们与他们的父母有着正确的联系,并且显示了正确的文本

我遇到的问题如下

主节点(位于中心)不可折叠。与所定位的示例相比,该图的整体行为有些浮躁

折叠节点时颜色不变,折叠父节点时将显示父节点的子节点。在多个节点上单击几下后,孩子和家长似乎会发生切换

我的问题是代码的哪一部分可能导致这种情况,为什么

下面是我用来生成图表的代码。数据丢失,但由JSFIDLE提供。感谢您的帮助,提前谢谢

    var width = 960,
    height = 500,
    root;

var force = d3.layout.force()
    .charge(-220)
    .size([width, height])
    .on("tick", tick);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var link = svg.selectAll(".link");

function update() {
    var nodes = flatten(root);


    var links = d3.layout.tree().links(nodes);

    console.log(nodes);

    // Restart the force layout.
    force.nodes(nodes)
        .links(links)
        .linkDistance(55)
        .start();



    var link = svg.selectAll(".link")
        .data(links, function(d) { return d.target.id; });

    link.enter().append("line")
        .attr("class", "link");

    link.exit().remove();

    var node = svg.selectAll("g.node")
        .data(nodes)


    var groups = node.enter().append("g")
        .attr("class", "node")
        .attr("id", function (d) {
        return d.id
    })
        .on('click', click)
        .call(force.drag);


    groups.append("circle")
        .attr("class","node")
        .attr("x", -8)
      .attr("y",-8)
      .attr("r", function(d) { return d.children ? 4.5 : 10 })
      .style("fill", color)
      .on("click", click)
      .call(force.drag);


    groups.append("text")
        .attr("dx", 12)
        .attr("dy", "0.35em")
        .style("font-size", "10px")
        .style("color", "#000000")
        .style("font-family", "Arial")
        .text(function (d) {
        console.log(d);
        return d.name
    });


    node.exit().remove();


    force.on("tick", function () {
        link.attr("x1", function (d) {
            return d.source.x;
        })
            .attr("y1", function (d) {
            return d.source.y;
        })
            .attr("x2", function (d) {
            return d.target.x;
        })
            .attr("y2", function (d) {
            return d.target.y;
        });

        node.attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
        });
    });
}

function tick() {
  link.attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; });

  node.attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
        });
}

// Color leaf nodes orange, and packages white or blue.
function color(d) {
   return d._children ? "#3182bd" // collapsed package
      : d.children ? "#c6dbef" // expanded package
      : "#fd8d3c"; // leaf node
}

// Toggle children on click.
function click(d) {
  if (!d3.event.defaultPrevented) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else {
      d.children = d._children;
      d._children = null;
    }
    update();
  }
}

// Returns a list of all nodes under the root.
function flatten(root) {
  var nodes = [], i = 0;

  function recurse(node) {
    if (node.children) node.children.forEach(recurse);
    if (!node.id) node.id = ++i;
    nodes.push(node);
  }

  recurse(root);
  return nodes;
}

好的,这里有两件事

首先,默认情况下,d3使用每个数据的索引作为其ID(以确定项目何时进入/退出选择)。这是您的问题,当索引X处的元素被新元素替换时,d3认为它们是相同的。您需要提供一个函数来返回id:

var node = svg.selectAll("g.node")
    .data(nodes, function(d) { return d.id; });
其次,只有当项目进入选择时,才设置圆的填充颜色。您应该从enter()块中提取分配样式的位,这样每次调用
update()
时都会执行该位

我将你的小提琴复制并拼凑到plunker中,因为JSFIDLE对我来说运行得非常慢:

非常感谢redmallard。我是javascript新手,它有很多支持库。弄清楚基本脚本已经够难的了,更不用说通过一个新的库来弄清楚脚本是如何反应的了。谢谢你的澄清。我在控制台中调试一些东西,但不明白为什么名称会被切换和重写。这就成功了。
node.selectAll('circle').style('fill', color);