4

I am trying to allow the user a more visual representation of where they are in the tree by highlighting the "selected" node in the tree, as well as displaying an icon, similar to plus/minus, based on whether or not the children are shown.

I can't seem to find anywhere on how to do this, since it seems that once the tree is redrawn after the expand, the selected node information is gone, and cannot be acted upon. Currently my tree nodes highlight based on children being hidden/displayed or not having any, but I would like to track which node has been clicked with a fill color. my tree is based off of mbostock’s block #1093025. Any help would be greatly appreciated for the plus/minus icon toggle, as well as highlighting the selected node.

Current code to display expand/collapse icons:

nodeEnter.append("svg:image")
    .attr("xlink:href", function(d) {
        if (d._children) return "images/arrow_right.png";
        else if (d.children) return "images/arrow_left.png";
    })
    .attr("x", "-12px")
    .attr("y", "-10px")
    .attr("width", 15)
    .attr("width", 20);

Function to enlarge selected node with functions for resizing... can't get these to work at all or for it to recognize the selected node on redraw. Only the fill seems to recognize the selected node.

nodeEnter.append("rect")
    .attr("y", newy)
    .attr("height", newheight)
    .attr("width", barWidth)
    .style("fill", color)
    .on("click", click);

function newy(d) {
    if (d._isSelected)
        return -barHeight / 1.25;
    else
        return -barheight/2;
}
function newheight(d) {
    if (d._isSelected)
        return barHeight * 1.75;
    else
        return barheight;
}
YakovL
  • 7,557
  • 12
  • 62
  • 102
David Figura
  • 43
  • 1
  • 5

1 Answers1

2

Just because the sample code "forgets" the selected node, doesn't mean you can't add it yourself:

// Toggle children on click.
var lastClickD = null;
function click(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  if (lastClickD){
    lastClickD._isSelected = false;
  }
  d._isSelected = true;
  lastClickD = d;
  update(d);
}

// on the selected one change color to red
function color(d) {
  if (d._isSelected) return 'red';
  return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}

To add your expand/collapse indicators, just update the nodes on redraw depending on it's children state:

// we used to set the text on enter
nodeEnter.append("text")
  .attr("dy", 3.5)
  .attr("dx", 5.5); 

// but now we change it on update based on children
node.select('text') 
  .text(function(d) { 
    if (d.children) {
      return '+' + d.name;
    } else if (d._children) {
      return '-' + d.name;
    } else {
      return d.name;
    }
  });

Here's an example.

Mark
  • 106,305
  • 20
  • 172
  • 230
  • Hi Mark, Thanks for the help! The first part worked perfectly. For the 2nd part, I currently am using the following: – David Figura Dec 22 '14 at 19:16
  • Hi @Mark, Thanks for the help! The first part worked perfectly. For the 2nd part, I appended an image to the left of each node, but the logic of which one (plus/minus) to use is not working. Here is what I currently am using the following: `code` nodeEnter.append("svg:image") .attr("xlink:href", function (d) { if(d._children) return "images/arrow_right.png"; else if (d.children) return "images/arrow_left.png"; }) .attr("x", "-12px") .attr("y", "-10px") .attr("width", 15) .attr("width", 20); – David Figura Dec 22 '14 at 19:24
  • I also was not able to get to your example? It came up empty. – David Figura Dec 22 '14 at 19:24
  • Hi @Mark I have Root level, then 5 nodes, each having different levels of children. If I click the first parent under root to expand, and the collapse it, it stays red, as expected, but when I click the 2nd parent under root, and expand it's children, both parent 1 and 2 are now red....Is there a way to only have one and only one node as red, which would be the last one to be clicked? Thanks in advance. – David Figura Dec 22 '14 at 19:30
  • @DavidFigura, first, in the future, include relevant code in your question. I edited it to include the snippet you just posted. Second, not sure why my link came up empty, it works on my end. Third, your image code does not work because you are only doing it on the `enter` selection, not the `update` one. See in my answer, how I act on `node` and not `nodeEnter`. Fourth, my highlighting code works as you describe. I'm guessing you missed something merging it into your code. Update my plunker or create a new one of your own, **with your specific** code, otherwise I'm guessing. – Mark Dec 22 '14 at 19:35
  • Hi @Mark, I apologize for the delay, but just got back from vacation. I appreciate your help. If possible, I've been also on top of color coding the selected node, I would like to enlarge that node. I tried to use the d._IsSelected in a new funciton for my "y" attribute of the node.Append("rect"), but it doesn't recognize the selected node. Thanks in advance. I'm going to try and edit the question as well, to insert a snippet. Thx Dave – David Figura Jan 06 '15 at 18:57