弯头连接器的M,V,H在d3js中意味着什么?

时间:2017-08-03 09:15:31

标签: d3.js svg

我目前正在使用d3js处理树形图。我的连接器目前是曲线,我正在努力将其转换为垂直线。我发现肘部功能如下:

 function elbow(d, i) {  return "M" + d.source.y + "," + d.source.x
   + "H" + d.target.x + "V" + d.target.y
   + (d.target.children ? "" : "h" + margin.right);}

我的输出很有趣,所以我需要了解弯头连接器中使用的M,H和V是如何工作的?

我的整个代码如下 - 您也可以查看输出。

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": "Development",
        "streamName": "ArgOS_2_0_IPC-Tracer",
        "Parent": "ArgOS_2_0",
        "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": "ArgOS_2_CSGDK",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_2x_Dev",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_ION_DEV_wp",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "ArgOS_IPC",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_2_0_ASP",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_2_0_G2S",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_2_0_MGAM",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_2_0_MGAM2",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_2_0_NSW_TEMP",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_2_0_QUARTZ",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_DMG",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "true",
            "ChangeFlowsToParent": "true",
            "StreamType": "Development",
            "streamName": "d_ArgOS_DMG_PS",
            "Parent": "d_ArgOS_DMG",
            "Compliance": "Released"
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_Lounge_Table",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_Prizm",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "true",
            "ChangeFlowsToParent": "true",
            "StreamType": "Development",
            "streamName": "Merge_mainline_into_prizm",
            "Parent": "d_ArgOS_Prizm",
            "Compliance": "Released"
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_Prizm_Merge",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "d_ArgOS_QCOM",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0200",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "true",
            "ChangeFlowsToParent": "true",
            "StreamType": "Release",
            "streamName": "r_ArgOS_0200D",
            "Parent": "r_ArgOS_0200",
            "Compliance": "Released"
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0200A",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0210",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0212",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "false",
            "ChangeFlowsToParent": "true",
            "StreamType": "Release",
            "streamName": "r_ArgOS_0211",
            "Parent": "r_ArgOS_0212",
            "Compliance": "Released"
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0214",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "false",
            "ChangeFlowsToParent": "true",
            "StreamType": "Release",
            "streamName": "r_ArgOS_0213",
            "Parent": "r_ArgOS_0214",
            "Compliance": "Released",
            "children": [
              {
                "ChangeFlowsFromParent": "true",
                "ChangeFlowsToParent": "true",
                "StreamType": "Development",
                "streamName": "ArgOS_WindowManager",
                "Parent": "r_ArgOS_0213",
                "Compliance": "Released"
              },
              {
                "ChangeFlowsFromParent": "true",
                "ChangeFlowsToParent": "true",
                "StreamType": "Release",
                "streamName": "r_ArgOS_0215",
                "Parent": "r_ArgOS_0213",
                "Compliance": "Released"
              }
            ]
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0216",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0218",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      },
      {
        "ChangeFlowsFromParent": "false",
        "ChangeFlowsToParent": "true",
        "StreamType": "Release",
        "streamName": "r_ArgOS_0225",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released",
        "children": [
          {
            "ChangeFlowsFromParent": "false",
            "ChangeFlowsToParent": "true",
            "StreamType": "Release",
            "streamName": "r_ArgOS_0220",
            "Parent": "r_ArgOS_0225",
            "Compliance": "Released"
          }
        ]
      },
      {
        "ChangeFlowsFromParent": "true",
        "ChangeFlowsToParent": "true",
        "StreamType": "Development",
        "streamName": "test_mergewp",
        "Parent": "ArgOS_2_0",
        "Compliance": "Released"
      }
    ]
  }
]

// ************** Generate the tree diagram	 *****************
var margin = {top: 20, right: 120, bottom: 20, left: 120},
	width = 1960 - margin.right - margin.left,
	height = 800 - margin.top - margin.bottom;
	
	   var viewerWidth = $(document).width();
    var viewerHeight = $(document).height();
	
var i = 0,
	duration = 750,
	root;

var tree = d3.layout.tree(); //draw tree with size of nodes specified
tree.nodeSize([150, 40]); 

tree.separation(function separation(a, b) {
  return (a.parent == b.parent ? 1 : 2) / a.depth;
});

	
var diagonal = d3.svg.diagonal().projection(function(d) { return [d.x-30, -d.y + 280]; });
	
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 + ")") 
			.attr("transform", "translate(800,450)") 
			.on("click", clicksvg);
						
				
root = sampleData[0];

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

update(root);

<!-- d3.select(self.frameElement).style("height", "500px"); -->

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() //all nodes should be inside g - only then text seems to appear
	  .append("g")
	  <!-- .attr("height", 40) -->
	  <!-- .attr("width", 100) -->
	  <!-- .style("fill","yellow") -->
	  .attr("class", "node")
	  .attr("transform", function(d) { return "translate(" +  source.y0 + "," + source.x0 + ")"; })
	  .on("click", click);

  nodeEnter.append("rect")
	  .attr("height", 40)
	  .attr("width", 100)
	  .style("fill", "lightsteelblue");

  nodeEnter.append("text")
	  .attr("x", "50" )
	  .attr("y", "50")
	  <!-- .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) -->
	  .text(function(d) { return d.streamName; })
	  .style("fill","black")
	 
	  <!-- .style("fill-opacity", 1e-6); -->

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

  nodeUpdate.select("rect")
	 .attr("height", 40)
	  .attr("width", 100)
	  .attr("x",-80)
	  .attr("y", 0)
	  .style("fill", function(d) {return d.Parent == "none" ? "yellow" : "skyblue"});
	 

  nodeUpdate.select("text")
	  .attr("x",-75)
	  .attr("dy", -25)
	   .style("font-weight",  "bold")
	  .style("fill-opacity", 1)
	  ;
  // 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")
	  .style("stroke", function(d){
	  <!-- console.log(d.target); -->
	  if(d.target.ChangeFlowsFromParent == "true") { return  "green" } else {return "red"}})
	  .attr("d", elbow);
	  <!-- .attr("d", function(d) { -->
	  <!-- var o = {x: source.y0, y: -source.x0}; -->
		<!-- return diagonal({source: o, target: o}); -->
	  <!-- }); -->
	  
  // Transition links to their new position.
  link.transition()
	  .duration(duration)
	  .attr("d", elbow);

	  // Stash the old positions for transition.
  nodes.forEach(function(d) {
	d.x0 = d.y;
	d.y0 = d.x;
  });
  
 }

// open children info as a pop-up on click.
function click(d) {

d3.event.stopPropagation();

d3.select("#foreign").remove();

var xcor = d.x0 - 30;
var ycor = d.y0;

var pop = d3.select(this)
			.append('g')
			//.attr("transform", function(d) { return "translate(" + (xcor - 300) + "," + 0 + ")"; })
			 .attr("id","foreign");

	pop.append("rect")
      .attr("height", 200)
	   .attr("width", 300)
	   .attr("x", -20)
	   .attr("y", -60)
	   .attr("fill","white")
	   .attr("stroke", "black");
	   
	 <!-- pop.append("text") -->
		<!-- .attr("x", 30) -->
	   <!-- .attr("dy", -40) -->
     <!-- .style("fill-opacity", 5) -->
     <!-- .attr("text-anchor", "middle") -->
  
  var foreign = pop.append("foreignObject").
                    attr("class","foreign");
  
  foreign.append("xhtml:div")
		.attr("height", 200)
	   .attr("width", 500)
         .html(function(d) {
                return "<span style='font-weight:bold'>StreamName: </span>" + d.streamName + "<br/>" +
              "<strong>ParentName: </strong> <span style='color:red'>" + d.Parent + "</span><br/>" +
              "<strong>Compliance: </strong> <span style='color:red'>" + d.Compliance + "</span><br/>";
              })
		}

function clicksvg() {
	var thisclick = this;
	thisclick.selectAll("#foreign").remove(); 
	 }  
	 
	 function elbow(d, i) {
  return "M" + d.source.y + "," + d.source.x
       + "H" + d.target.x + "V" + d.target.y
       + (d.target.children ? "" : "h" + margin.right);
}
	 
	.node {
		cursor: pointer;
		overflow:auto;
	}

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

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

	.linkFrom {
	  fill: none;
	  stroke: blue;
	  stroke-width: 2px;
	}
	
	.linkTo {
		fill: none;
	  stroke: red;
	  stroke-width: 2px;
	}
	
	.link{
	fill:none;
	stroke:  #CCC;
	stroke-width: 2px;
	}
	
	.popup rect{
		cursor: pointer;
		position: absolute;
        text-align: left;
        <!-- width: 100px; -->
        <!-- height: 80px; -->
        padding: 8px;
        font: 10px sans-serif;
        background-color: gray;
        border: solid 1px #aaa;
        border-radius: 8px;
	
	}
	
	.foreign{
	cursor: pointer;
	}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.9/d3.min.js"></script>

1 个答案:

答案 0 :(得分:4)

这与D3无关。那些是SVG path commands

M命令:

  

“Move To”或M,取两个参数,一个坐标'x'和坐标'y'移动到。如果光标已经在页面的某个位置,则不会绘制任何线来连接这两个位置。

然后,H和V命令:

  

H绘制一条水平线,V绘制一条垂直线。两个命令只接受一个参数,因为它们只在一个方向上移动。