在d3树路径中创建灵活链接

时间:2017-08-07 13:17:57

标签: d3.js

我是D3 js的新手。我想用d3绘制树形结构。但是,我希望我的节点之间的路径不像通常的对角线和投影方法那样灵活。我需要节点之间的连接是这样的:

enter image description here

我如何在d3中执行此操作?

这是我目前的对角线代码。



<html>
<head>
<title> Box office </title>
</head>
<body>
<style>
.node {
		cursor: pointer;
	}

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

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

	.link {
	  fill: none;
	  stroke: #ccc;
	  stroke-width: 2px;
	}

</style>
<!-- load the d3.js library -->	
<script src="https://d3js.org/d3.v3.min.js"></script>

<div id = "boxoffice"></div>

<script type="text/javascript">



var sampleData = [
  {
    "ChangeFlowsFromParent": "false",
    "ChangeFlowsToParent": "false",
    "StreamType": "Mainline",
    "streamName": "ArgOS_2_0",
    "Parent": "none",
    "Compliance": "Released",
    "children": [
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2_0_DHAL",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
	   {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2_0_Dev",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "true",
            "ChangeFlowsToParent": "true",
            "StreamType": "Release",
            "streamName": "r_ArgOS_0230",
            "Parent": "ArgOS_2_0_Dev",
            "Compliance": "Released"
          },
		   {
            "ChangeFlowsFromParent": "true",
            "ChangeFlowsToParent": "true",
            "StreamType": "Release",
            "streamName": "branch1",
            "Parent": "ArgOS_2_0_Dev",
            "Compliance": "Released",
			 "children": [
			  {
				"ChangeFlowsFromParent": "true",
				"ChangeFlowsToParent": "true",
				"StreamType": "Release",
				"streamName": "branch100",
				"Parent": "branch1",
				"Compliance": "Released"
			  },
			  {
				"ChangeFlowsFromParent": "true",
				"ChangeFlowsToParent": "true",
				"StreamType": "Release",
				"streamName": "branch200",
				"Parent": "branch1",
				"Compliance": "Released",
				 "children": [
				  {
					"ChangeFlowsFromParent": "true",
					"ChangeFlowsToParent": "true",
					"StreamType": "Release",
					"streamName": "honey",
					"Parent": "branch200",
					"Compliance": "Released"
				  }
				  ]
			  }
			  ]
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2_0_IPC-Tracer",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
			 "children": [
			  {
				"ChangeFlowsFromParent": "true",
				"ChangeFlowsToParent": "true",
				"StreamType": "Release",
				"streamName": "ArgOS_2_0_IPC_child 1",
				"Parent": "ArgOS_2_0_IPC",
				"Compliance": "Released"
			  },
			  {
				"ChangeFlowsFromParent": "true",
				"ChangeFlowsToParent": "true",
				"StreamType": "Release",
				"streamName": "ArgOS_2_0_IPC_child 2",
				"Parent": "ArgOS_2_0_IPC",
				"Compliance": "Released"
			  }
			  ]
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2_0_NSW_Temp",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2_0_Test",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2_CBD",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "test_mergewp",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      }
    ]
  }
]


var margin = {top:100, bottom: 100, left:100, right:100},
width = 1800 - margin.left-margin.right, //total width minus side margins
height = 1500 - margin.top - margin.bottom; //total height minus vertical margins

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

tree.nodeSize([40,100]);

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

	

var svgContainer = d3.select("#boxoffice").append("svg").attr("width", width).attr("height", height).append("g").attr("transform", "translate(" + (width/2) + "," + (height - 500) + ")");

var root = sampleData[0];
root.x0 = width/2;
root.y0 = 0;

update(root);

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

function update(sourceNode){

var nodes = tree.nodes(sourceNode).reverse(),
 links = tree.links(nodes);

  
nodes.forEach(function(d){d.y = d.depth * 180});
   

var node = svgContainer.selectAll("g.node").attr("class", "node").data(nodes, function(d, i){return d.id || (d.id = ++i); });

var nodeEnter = node.enter().append("g")
							 .attr("transform", function(d) { 
							 
							 <!-- if(d.StreamType == "Mainline") -->
								<!-- return "translate(-100,-100)"; -->
							 <!-- else -->
								return "translate(" + sourceNode.y0 + "," + sourceNode.x0 + ")"; 
							 							 
							 });
  
nodeEnter.append("circle")
		.attr("r", 15)
		.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
		
		nodeEnter.append("text")
	  .attr("x", function(d) { return d.children || d._children ? -13 : 13; })
	  .attr("dy", ".35em")
	  .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
	  .text(function(d) { return d.streamName; })
	  .style("fill-opacity", 1e-6);
	
			 
  var nodeUpdate = node.transition()
	  .duration(100)
	  .attr("transform", function(d) { 
	  
	   if(d.StreamType == "Mainline")
	    {
			var lastElement = nodes[0];
			
		return  "translate(" + (lastElement.y + 100) + "," + (lastElement.x -130) + ")"; //adding the root element 
		}
	    else
			return "translate(" + d.y + "," + (d.x-(margin.top + margin.bottom)) + ")"; 
            
	  });

  nodeUpdate.select("circle")
	  .attr("r", 10)
	  .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeUpdate.select("text")
	  .style("fill-opacity", 1);

  var link = svgContainer.selectAll("path.link")
	  .data(links, function(d) { return d.target.id; });
	
  link.enter().insert("path", "g")
  .attr("class", "link")
  .attr("d", function(d) {
	var o = {x: sourceNode.x0, y: sourceNode.y0};
	return diagonal({source: o, target: o});
  });

  // Transition links to their new position.
  link.transition()
	  .duration(10)
	  .attr("d", diagonal);
	 	  
	  
nodes.forEach(function(d) {
	d.x0 = d.x;
	d.y0 = d.y;
  });
	  

}

function positionLink(d) {
  return "M" + d[0].x + "," + d[0].y
       + "S" + d[1].x + "," + d[1].y
       + " " + d[2].x + "," + d[2].y;
}

</script>

</body>
</html>
&#13;
&#13;
&#13;

在此代码中,链接都是凌乱的。我可以为对角路径链接整理它,但我希望我的链接是动态和灵活的。我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:0)

目前还不清楚你的意思是什么?&#34;灵活的&#34;。可以从https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#Bezier_Curves收集更准确的术语。例如,您可能需要一个三次贝塞尔曲线。

要实现这一点,您需要更改此部分代码:

.attr("d", function(d) {
var o = {x: sourceNode.x0, y: sourceNode.y0};
return diagonal({source: o, target: o});

可以在此示例中找到更多信息,该示例似乎实现了您想要的内容: https://bl.ocks.org/mbostock/4339184

它使用:

.attr("d", d3.linkHorizontal()
      .x(function(d) { return d.y; })
      .y(function(d) { return d.x; }));

链接功能是相关的,但不等同于对角线功能。