简体   繁体   中英

D3 collapsible tree with React: not updating nodes

I am using d3 collapsible tree, the code for which I copied from:

https://bl.ocks.org/mbostock/4339083

I am trying to accomodate it for my React web app and change it, so that I could append nodes to any tree nodes myself. It is appending nodes, creating links correctly, except that text at the nodes positions are not changed and the nodes are not collapsing/expanding when clicking on them. So, these are two my main issues that I believe are very related to each other. Here is what I am doing:

Inside of componentDidUpdate I am calling the function that is creating and updating the tree chart:

componentDidUpdate() {
   this.updateGeneTreeChart(this.getRoot());
} 

Update happens when I am selecting (using basic html select ) node value to append next node to, and entering in a text field the value and then hit a button. So, I set the node to append to and text of the new node.

updateGeneTreeChart is:

updateGeneTreeChart = (source) => {
const svg = d3.select(this.node);
//svg.selectAll("*").remove();
const margin = {top: 20, right: 120, bottom: 20, left: 120};
const width = 960 - margin.right - margin.left;
const height = 800 - margin.top - margin.bottom;
let i = 0;
const duration = 750;

let root = this.getRoot();

let tree = d3.layout.tree()
    .size([height, width]);

let diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

let nodes = tree.nodes(root).reverse(),
    links = tree.links(nodes);
console.log("root.children");
console.log(root);
console.log(root.children);
/*if (this.state.selectedGeneArr.length) {
  root.children.forEach(this.collapse, this);
}*/
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });

// Update the nodes…
let node = svg.selectAll("g.node")
    .data(nodes, function(d) { return d.id || (d.id = ++i); });

// Enter any new nodes at the parent's previous position.
let nodeEnter = node.enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
    .on("click", this.clickNode);

node.attr("text", function(d) {
  return d.name;
});


nodeEnter.append("circle")
    .attr("r", 1e-6)
    .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

nodeEnter.append("text")
    .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
    .attr("dy", ".35em")
    .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
    .text(function(d) { return d.name; })
    .style("fill-opacity", 1e-6);

// Transition nodes to their new position.
let nodeUpdate = node.transition()
    .duration(duration)
    .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

nodeUpdate.select("circle")
    .attr("r", 4.5)
    .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

nodeUpdate.select("text")
    .style("fill-opacity", 1);

// Transition exiting nodes to the parent's new position.
let nodeExit = node.exit().transition()
    .duration(duration)
    .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
    .remove();

nodeExit.select("circle")
    .attr("r", 1e-6);

nodeExit.select("text")
    .style("fill-opacity", 1e-6);

// Update the links…
let link = svg.selectAll("path.link")
    .data(links, function(d) { return d.target.id; });

// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
    .attr("class", "link")
    .attr("d", function(d) {
      var o = {x: source.x0, y: source.y0};
      return diagonal({source: o, target: o});
    });

// Transition links to their new position.
link.transition()
    .duration(duration)
    .attr("d", diagonal);

// Transition exiting nodes to the parent's new position.
link.exit().transition()
    .duration(duration)
    .attr("d", function(d) {
      var o = {x: source.x, y: source.y};
      return diagonal({source: o, target: o});
    })
    .remove();

// Stash the old positions for transition.
nodes.forEach(function(d) {
  d.x0 = d.x;
  d.y0 = d.y;
});
}

getRoot() function is just getting a deep copy of the updated object that I am using to build the tree:

getRoot = () => {
  const margin = {top: 20, right: 120, bottom: 20, left: 120},
  width = 960 - margin.right - margin.left,
  height = 800 - margin.top - margin.bottom;
  let root = JSON.parse(JSON.stringify(this.state.geneTreeJSON));
  root.x0 = height / 2;
  root.y0 = 0;
  return root;
}

geneTreeJSON is the actual object that I am updating. I am sure that it is updated correctly, that its structure is right, that the nodes object in the updateGeneTreeChart is correct:

在此处输入图片说明

However, all the newly attached nodes either have no text or have the text of the root node (in this particular case - Il4ra ). If I delete everything inside of svg at the beginning of each update it actually draws the right text at the nodes. So, somehow the text is not updating. I tried to do the following:

node.attr("text", function(d) {
      return d.name;
    });

OR

nodeEnter.attr("text", function(d) {
      return d.name;
    });

Not working. I tried then to print out what is passed to the nodes:

nodeEnter.append("text")
    .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
    .attr("dy", ".35em")
    .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
    .text(function(d) {
      console.log("nodeEnter");
      console.log(d); 
      return d.name; })
    .style("fill-opacity", 1e-6);

And d is the root node, children are not printed out. So, I guess this is where the issue of text at least should be fixed but I do not know how. Any suggestions would be greatly appreciated.

I was able to fix the text of the nodes by adding the code:

// Update the nodes…
let node = svg.selectAll("g.node")
            .data(nodes, function(d) { return d.id || (d.id = ++i); });

---->    node.select("text")
           .data(nodes)
           .text(function(d) {
                return d.name; });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM