jeudi 19 avril 2018

d3.layout.tree [collapsable] adding checkbox to nodes

I am creating a collapsible tree diagram on the basis of the source code in here http://mbostock.github.io/d3/talk/20111018/tree.html

It is working perfect, but I would like to add checkbox into the tree next to each node text. Please see below image for the desired outlook. I was searching forums, and I have seen that I should append the "foreignObjects" (source). Since I am very new to d3.js and coding, i can not figure out how to modify my existing script.

I would really appreciate any help!

Here is my current code with no checkbox:

<!DOCTYPE html>
<meta charset="utf-8">
<style>


body {
  background-color: #f9f9f9;
}

.node {
  cursor: pointer
  ;
}

.node circle {
  fill:   #1a5276;
  stroke:   #444444;
  stroke-width: 3px;
}

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

.link {
  fill: none;
  stroke:  #805e4b ;
  stroke-width: 1px;
  stroke-dasharray: 2;
}

.link:hover {
    stroke:red;
}

div#tooltip{        
 color:#505050;
    width: 300px;                   
    height: relative;                   
    opacity:1;
    padding: 5px;           
    font: 10px sans-serif;      
    background: #f0ecec;    
    border: 0px;        
    border-radius: 10px;                
}

div#hint {
  position: absolute;
  left: 30px;
  top: 30px;
  width: 1280px;
  font: 14px sans-serif;
  color: #999;
}
</style>
<div id="hint">ACTIVITY TYPES AND THEIR DEFINITIONS<br>click to expand or collapse a class of activity / mouse over to see the definitions and examples.</div>

<body>

<script src="d3.v3.min.js"></script>

<div id="tooltip" style="display:none"></div>

<script>


//create tree diagram on the basis of http://mbostock.github.io/d3/talk/20111018/tree.html

var margin = {top: 20, right: 120, bottom: 20, left: 120},
    width = 1500 - 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 + ")");

d3.json("activity.json", function(error, flare) {
  if (error) throw error;

  root = flare;
  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");

d3.selectAll("text")
     .style("fill", "black");

d3.select(this).select("text")
    .style("fill", "red");

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)







//modification-1 according to color requirements 
//see source: https://stackoverflow.com/questions/33524668/d3-collapsible-tree-different-node-colors
nodeEnter.append("circle")
        .attr("r", 1e-6)
        .style("stroke", function(d) {
            if(d.type == "activity_DataCollection") return "#aa1008";
            if(d.type == "main_DataCollection") return "#aa1008";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "#e0a90e";         
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "#336600";    
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "#805e4b";       
            if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "#8996b9";                 
        })
        .style("fill", function(d) {
          if(d.type == "activity") return "#805e4b";
          if(d.type == "activity_DataCollection") return "#aa1008";       
          if(d.type == "main_DataCollection") return "white";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "white";   
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "white";
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "white"; 
                        if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "white";       
            });
//modification-1 end according to color requirements


//adding tooltips is slightly more complicated. 
//see source: https://stackoverflow.com/questions/26790124/modify-lines-tooltip-on-hover
//One way is to have a hidden <div> on your page that becomes visible and moves to the <text> you are mousing over. 
//<div id="tooltip" style="display:none"></div> It will then be hidden when you mouse out. 

  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)
        .on("mouseover", function (d) {
            var r = d3.select(this).node().getBoundingClientRect();
            d3.select("div#tooltip")
                .style("display", "inline")
                .style("top", (r.top+15) + "px")
                .style("left", r.left + "px")
                .style("position", "absolute")
                .text(d.definition+" "+d.example);
        })
    .on("mouseout", function(){
        d3.select("div#tooltip").style("display", "none")
    });


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

//modification-2 according to color requirements
 nodeUpdate.select("circle")
        .attr("r", 5)
        .style("stroke", function(d) {
            if(d.type == "activity_DataCollection") return "#aa1008";
            if(d.type == "main_DataCollection") return "#aa1008";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "#e0a90e"; 
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "#336600";            
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "#805e4b";   
            if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "#8996b9";             




        })

        .style("fill", function(d) {
          if(d.type == "activity") return "#805e4b";
          if(d.type == "main") return "white";
            if(d.type == "activity_DataCollection") return "#aa1008";
            if(d.type == "main_DataCollection") return "white";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "white";   
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "white";          
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "white"; 
                        if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "white";       
        });
//modification-2 end according to color requirements        

  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);
}

// Toggle children on click.

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




</script>

enter image description here




Aucun commentaire:

Enregistrer un commentaire