在d3树布局中查找链接终点的坐标

时间:2016-02-03 14:16:06

标签: javascript jquery d3.js svg

我正在尝试创建一个双树结构,而不是svg节点,我想在这些点上附加div。如何找到每个的终点坐标以在特定点上放置div。

这就是我到目前为止 -

 var nodePosition = [];

 $(document).ready(function() {

   $(".static-doubletree-container").makeStaticDoubleTree();


 });



 jQuery.fn.makeStaticDoubleTree = function() {


   var margin = {
       top: 30,
       right: 10,
       bottom: 10,
       left: 10
     },
     width = 960 - margin.left - margin.right,
     halfWidth = width / 2,
     height = 500 - margin.top - margin.bottom,
     i = 0,
     duration = 500,
     root;

   var getChildren = function(d) {
     var a = [];
     if (d.winners)
       for (var i = 0; i < d.winners.length; i++) {
         d.winners[i].isRight = false;
         d.winners[i].parent = d;
         a.push(d.winners[i]);
       }
     if (d.challengers)
       for (var i = 0; i < d.challengers.length; i++) {
         d.challengers[i].isRight = true;
         d.challengers[i].parent = d;
         a.push(d.challengers[i]);
       }
     return a.length ? a : null;
   };

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

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

   var connector = diagonal;

   var calcLeft = function(d) {
     var l = d.y;
     if (!d.isRight) {
       l = d.y - halfWidth;
       l = halfWidth - l;
     }
     return {
       x: d.x,
       y: l
     };
   };

   var vis = d3.select(".static-doubletree-container").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 + ")");

   setTimeout(function() {
     var json = {
       "name": "Overall Winner",
       "winners": [{
         "name": "Winner Left 1",
         "winners": [{
           "name": "Winner Left 3"
         }, {
           "name": "Winner Left 4"
         }]
       }, {
         "name": "Winner Left 2"
       }],
       "challengers": [{
         "name": "Challenger Right 1",
         "challengers": [{
           "name": "Challenger Right 3"
         }, {
           "name": "Challenger Right 4"
         }]
       }, {
         "name": "Challenger Right 2",
         "challengers": [{
           "name": "Challenger Right 5"
         }, {
           "name": "Challenger Right 6"
         }]
       }]
     };

     root = json;
     root.x0 = height / 2;
     root.y0 = width / 2;

     var t1 = d3.layout.tree().size([height, halfWidth]).children(function(d) {
         return d.winners;
       }),
       t2 = d3.layout.tree().size([height, halfWidth]).children(function(d) {
         return d.challengers;
       });
     t1.nodes(root);
     t2.nodes(root);

     var rebuildChildren = function(node) {
       node.children = getChildren(node);
       if (node.children) node.children.forEach(rebuildChildren);
     }
     rebuildChildren(root);
     root.isRight = false;
     update(root);
   });

   var toArray = function(item, arr, d) {
     arr = arr || [];
     var dr = d || 1;
     var i = 0,
       l = item.children ? item.children.length : 0;
     arr.push(item);
     if (item.position && item.position === 'left') {
       dr = -1;
     }
     item.y = dr * item.y;
     for (; i < l; i++) {
       toArray(item.children[i], arr, dr);
     }
     return arr;
   };

   function update(source) {
     // Compute the new tree layout.
     var nodes = toArray(source);

     // Normalize for fixed-depth.

    

     nodes.forEach(function(d) {
       if (d.isRight) {
         d.y = d.depth * 180 + halfWidth;
       } else {
         d.y = width - (d.depth * 180 + halfWidth);
       }

     });





     // Update the nodes…
     var node = vis.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"; });

     // Transition nodes to their new position.
     var nodeUpdate = node.transition()
       .duration(duration)
       .attr("transform", function(d) {
         p = calcLeft(d);
         return "translate(" + p.y + "," + p.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) {
         p = calcLeft(d.parent || source);
         return "translate(" + p.y + "," + p.x + ")";
       })
       .remove();

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

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

     // Update the links...
     var link = vis.selectAll("path.link")
       .data(tree.links(nodes), 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 connector({
           source: o,
           target: o
         });
       });

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

     // Transition exiting nodes to the parent's new position.
     link.exit().transition()
       .duration(duration)
       .attr("d", function(d) {
         var o = calcLeft(d.source || source);
         if (d.source.isRight) o.y -= halfWidth - (d.target.y - d.source.y);
         else o.y += halfWidth - (d.target.y - d.source.y);
         return connector({
           source: o,
           target: o
         });
       })
       .remove();

     // Stash the old positions for transition.
     nodes.forEach(function(d) {
       var p = calcLeft(d);
       d.x0 = p.x;
       d.y0 = p.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(source);
     }
   }


 };

 
  .node circle {
    cursor: pointer;
    fill: #fff;
    stroke: steelblue;
    stroke-width: 1.5px;
  }
  .node text {
    font-size: 11px;
  }
  path.link {
    fill: none;
    stroke: #ccc;
    stroke-width: 1.5px;
  }
  .node.selected circle {
    fill: green;
  }
  .static-doubletree-container {
    position: relative;
  }
  .node-container-div {
    width: 120px;
    height: 50px;
    border-radius: 25px;
    background: #ccc;
    position: absolute;
  }
  .root {
    top: 230px;
    left: 400px;
  }
  .overlay-divs {
    position: absolute;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="static-doubletree-container">
  <div class="overlay-divs">

    <div class="node-container-div root">

    </div>
  </div>
</div>

2 个答案:

答案 0 :(得分:2)

在这种情况下,链接的最后一点是:

d3.selectAll(".link")[0].forEach(function(path){
  var j = path.getBBox();
 console.log(j)//returns the tightest bounding rectange from which co-ordinates can be found
})

修改

因为在你发布的小提琴中,链接有转换,所以你必须在转换完成后运行代码。

 window.setTimeout(function(){
  d3.selectAll(".link")[0].forEach(function(path){
    var j = path.pathSegList
    x = j[j.length-1].x
    y = j[j.length-1].y
   console.log(x,y)//last position of link
  })     
 }, duration);

工作代码here

希望这有帮助!

答案 1 :(得分:1)

您可以尝试使用rectObject = object.getBoundingClientRect();

这也有效。这里有更多文档 - https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect