Mark C.
Mark C.

Reputation: 6450

Modify lines/tooltip on hover

I am playing around with D3.js and I am trying to do two things:

  1. On hovering of the lines, I want to apply a style to the lines (color to light blue or something). It can go to the parent node, or the highest level parent, either one would greatly help me out. If you know how to do both, please share!
  2. On hovering of the text per each node, I would like to display a tooltip of the "test" attribute in the JSON data.

I have messed around with the tooltips before, but in this scenario I am not sure where to put the ,on("mouseover" event handler. This is also my first time testing out the d3.treeoption.

var margin = {top: 20, right: 120, bottom: 20, left: 120},
    width = 960 - margin.right - margin.left,
    height = 800 - margin.top - margin.bottom;
    
var i = 0,
    duration = 750,
    root;

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

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

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


  var root={                      //json var root
        "name": "flare",
          "test": "blue",
            "children": [{
            "name": "analytics",
                "test": "red",
                "children": [{
                "name": "cluster",
                    "test": "green",
                    "children": [{
                    "name": "AgglomerativeCluster",
                        "test": "blue",
                    "size": 3938
                }, {
                    "name": "CommunityStructure",
                    "test": "yellow",
                    "size": 3812
                }, {
                    "name": "HierarchicalCluster",
                    "test": "orange",
                    "size": 6714
                }, {
                    "name": "MergeEdge",
                    "test": "someColor",
                    "size": 743
                }]
            }, {
                "name": "graph",
                "test": "someColor",
                    "children": [{
                    "name": "BetweennessCentrality",
                        "test": "someColor",
                    "size": 3534
                }, {
                    "name": "LinkDistance",
                    "test": "someColor",
                    "size": 5731
                }, {
                    "name": "MaxFlowMinCut",
                    "size": 7840
                }, {
                    "name": "ShortestPaths",
                    "test": "someColor",
                    "size": 5914
                }, {
                    "name": "SpanningTree",
                    "test": "someColor",
                    "size": 3416
                }]
            }, {
                "name": "optimization",
                "test": "someColor",
                    "children": [{
                    "name": "AspectRatioBanker",
                        "test": "someColor",
                    "size": 7074
                }]
            }]
        }, {
            "name": "animate",
            "test": "someColor",
                "children": [{
                "name": "interpolate",
                    "test": "someColor",
                    "children": [{
                    "name": "ArrayInterpolator",
                        "test": "someColor",
                    "size": 1983
                }, {
                    "name": "ColorInterpolator",
                    "test": "someColor",
                    "size": 2047
                }, {
                    "name": "DateInterpolator",
                    "test": "someColor",
                    "size": 1375
                }, {
                    "name": "Interpolator",
                    "test": "someColor",
                    "size": 8746
                }, {
                    "name": "MatrixInterpolator",
                    "test": "someColor",
                    "size": 2202
                }, {
                    "name": "NumberInterpolator",
                    "test": "someColor",
                    "size": 1382
                }, {
                    "name": "ObjectInterpolator",
                    "test": "someColor",
                    "size": 1629
                }, {
                    "name": "PointInterpolator",
                    "test": "someColor",
                    "size": 1675
                }, {
                    "name": "RectangleInterpolator",
                    "test": "someColor",
                    "size": 2042
                }]
            }, {
                "name": "ISchedulable",
                "test": "someColor",
                "size": 1041
            }, {
                "name": "Parallel",
                "test": "someColor",
                "size": 5176
            }, {
                "name": "Pause",
                "test": "someColor",
                "size": 449
            }, {
                "name": "Scheduler",
                "test": "someColor",
                "size": 5593
            }, {
                "name": "Sequence",
                "test": "someColor",
                "size": 5534
            }, {
                "name": "Transition",
                "test": "someColor",
                "size": 9201
            }, {
                "name": "Transitioner",
                "test": "someColor",
                "size": 19975
            }, {
                "name": "TransitionEvent",
                "test": "someColor",
                "size": 1116
            }, {
                "name": "Tween",
                "test": "someColor",
                "size": 6006
            }]
        }, {
            "name": "data",
             "test": "someColor",
            "size": 4322
        }]
    } ;

  root.x0 = height / 2;
  root.y0 = 0;

  function collapse(d) {
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
  }

  root.children.forEach(collapse);
  update(root);


d3.select(self.frameElement).style("height", "800px");

function update(source) {

  // Compute the new tree layout.
  var nodes = tree.nodes(root).reverse(),
      links = tree.links(nodes);

  // Normalize for fixed-depth.
  nodes.forEach(function(d) { d.y = d.depth * 180; });

  // Update the nodes…
  var 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.
  var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
      .on("click", click);

  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.
  var 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.
  var 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…
  var 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;
  });
}

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


      
.node {
  cursor: pointer;
}

.node circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 1.5px;
}

.node text {
  font: 10px sans-serif;
}

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Upvotes: 1

Views: 1526

Answers (1)

mdml
mdml

Reputation: 22882

First, you can change the color of the lines (links) just using a simple CSS hover, like so:

.link:hover {
    stroke:blue;
}

This will turn the links blue on mouse over or hover.


Second, adding tooltips is slightly more complicated. One way is to have a hidden <div> on your page that becomes visible and moves to the <text> you are mousing over. It will then be hidden when you mouse out. To do so, add the following:

nodeEnter.on("mouseover", function (d) {
    var r = d3.select(this).node().getBoundingClientRect();
    d3.select("div#tooltip")
        .style("display", "inline")
        .style("top", (r.top-25) + "px")
        .style("left", r.left + "px")
        .style("position", "absolute")
        .text(d.test);
})
.on("mouseout", function(){
    d3.select("div#tooltip").style("display", "none")
});

This requires you to add the <div id="tooltip" style="display:none"></div> to your HTML page. To make the tooltip look slightly more tooltip-y, use the following CSS (I'm sure you can Google around and get an even better style):

div#tooltip{
    color:#ffffff;
    background:#000000;
    opacity:1;
    padding:5px;
}

I compiled this example in this fiddle.

Upvotes: 3

Related Questions