简体   繁体   中英

Find co-ordinates of end point of links in d3 tree layout

I'm trying to create a double tree structure , and instead of svg nodes i would like to append div on those points. How can i find the end point co-ordinate of each to place a div on the particular point.

This is what i have so far -

  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 [dy, dx]; }); var connector = diagonal; var calcLeft = function(d) { var l = dy; if (!d.isRight) { l = dy - halfWidth; l = halfWidth - l; } return { x: dx, 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) { dy = d.depth * 180 + halfWidth; } else { dy = 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(" + py + "," + px + ")"; }); 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(" + py + "," + px + ")"; }) .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) oy -= halfWidth - (d.target.y - d.source.y); else oy += 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 = px; d.y0 = py; }); // 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> 

The last point of a link in this case would be:

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

EDIT

Since in the fiddle you posted the links have transition so you must run the code after the transition is complete.

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

working code here

Hope this helps!

You can try using rectObject = object.getBoundingClientRect();

This will also work. More documentation here - https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

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