如何通过固定矩形框在d3 js中的宽度动态增加高度 [英] How increase height dynamically by fixing width of the rect box in d3 js

查看:192
本文介绍了如何通过固定矩形框在d3 js中的宽度动态增加高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用d3 js折叠树。
我想修正矩形的宽度。
如果矩形框中的文本大小大于矩形框的固定宽度如何动态增加矩形框的高度?



如下图所示我想要的输出。



这里是我使用的代码



>

  .node {cursor:pointer; border-style:solid; border-width:2px 10px 4px 20px; } .node circle {fill:#fff;中风:钢蓝stroke-width:3px; } .node rect {fill:#fff;中风:钢蓝stroke-width:3px; } .node text {font:12px sans-serif; } .link {fill:none; stroke:#ccc; stroke-width:2px; }  

 <! - 载入d3.js库 - > < script src =https://d3js.org/d3.v3.min.js>< / script> < script> var treeData = [{name:Top,parent:null,children:[{name:Level 2:这里,parent:顶级,children:[{name:A的儿子,parent:Level 2:A},{name ,parent:Level 2:A}]},{name:Level 2:B,parent:Top Level}]}]; // ******** ******生成树图***************** var margin = {top:20,right:120,bottom:20,left:120},width = 960  -  margin.right  -  margin.left,height = 500  -  margin.top  -  margin.bottom; var i = 0,duration = 750,root; var tree = d3.layout.tree().size([height,width]); var diagonal = d3.svg.diagonal {x:d.source.x,y:d.source.y + 150};}).projection(function(d){return [dy + 0,dx + 0];}); 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 +)); root = treeData [0]; root.x0 = height / 2 ; root.y0 = 0;更新(root); d3.select(self.frameElement).style(height,500px); function update(source){//计算新的树布局。 var nodes = tree.nodes(root).reverse(),links = tree.links(nodes); //规范化固定深度。 nodes.forEach(function(d){d.y = d.depth * 180;}); //更新节点... var node = svg.selectAll(g.node).data(nodes,function(d){return d.id ||(d.id = ++ i);}); //在父级的上一个位置输入任何新的节点。 var nodeEnter = node.enter()。append(g).attr(class,node).attr(transform,function(d){returntranslate(+ source.y0 + + source.x0 +);}).on(click,click); nodeEnter.append(rect).attr(x,function(d){return d.children || d._children?0:0;}).attr(y,function(d){return d .attr(width,10).attr(height,10).attr(ry,10) .style(fill,function(d){return d._children?lightsteelblue:#fff;}); nodeEnter.append(text).attr(x,60).attr(dy,.35em).attr(text-anchor,middle).text返回d.name;}).style(fill-opacity,1e-6); //将节点转换到新的位置。 var nodeUpdate = node.transition().duration(duration).attr(transform,function(d){returntranslate(+ d.y +,+ d.x +); nodeUpdate.select(rect).attr(x,function(d){return d.children || d._children?0:0;}).attr(y,function(d){return d (ry,10).attr(width,150).attr(height,150) 30).style(fill,function(d){return d._children?lightsteelblue:#fff;}); nodeUpdate.select(text).style(fill-opacity,1).attr(text-anchor,middle); //转换退出节点到父的新位置。 var nodeExit = node.exit()。transition().duration(duration).attr(transform,function(d){returntranslate(+ source.y +,+ source.x +) ; })\t  。去掉(); nodeExit.select(rect).attr(x,function(d){return d.children || d._children?0:0;}).attr(y,function(d){return d .attr(width,10).attr(height,10).attr(ry,10) ; nodeExit.select(text).style(fill-opacity,1e-6).attr(text-anchor,middle); //更新链接... var link = svg.selectAll(path.link).data(links,function(d){return d.target.id;}); //在父级的上一个位置输入任何新的链接。 link.enter()。insert(path,g).attr(class,link)attr(fill,none)attr(stroke,black)。 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); //转换退出节点到父的新位置。 link.exit()。transition().duration(duration).attr(d,function(d){var o = {x:source.x,y:source.y}; return diagonal ,target:o});}).remove(); //存储转换的旧位置。 node.forEach(function(d){d.x0 = dx; d.y0 = dy;});} //在click.function上切换孩子click(d){if(d.children){d._children = d 。儿童d.children = null; } else {d.children = d._children; d._children = null; } update(d);}< / script>  

解决方案

只是一个表面的尝试。


  1. 首先添加所有文本元素

  2. 使用tspans将文本元素包裹在某个宽度内

  3. 获取文本元素的高度并将其作为属性存储在数据本身中

  4. 使用stored属性设置矩形的高度

参考包装文字这里



希望这有助于



 

  .node {cursor:指针; border-style:solid; border-width:2px 10px 4px 20px; } .node circle {fill:#fff;中风:钢蓝stroke-width:3px; } .node rect {fill:#fff;中风:钢蓝stroke-width:3px; } .node text {font:12px sans-serif; } .link {fill:none; stroke:#ccc; stroke-width:2px; }  

 < script src =https:// cdnjs .cloudflare.com / ajax / libs / d3 / 3.4.0 / d3.min.js>< / script>  


I'm using d3 js for collapsing tree. I want to fix the width of the rectangle. If text size in rectangle box is more than the fixed width of rect box how to increase height of rect box dynamically?

Like below image I want the output.

Here is the code what I'm using

.node {
		cursor: pointer;
		border-style: solid;
    border-width: 2px 10px 4px 20px;
	}

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

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

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

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

var treeData = [
  {
    "name": "Top Level",
    "parent": "null",
    "children": [
      {
        "name": "Level 2: A. Some text here Some text here Some text here",
        "parent": "Top Level",
        "children": [
          {
            "name": "Son of A",
            "parent": "Level 2: A"
          },
          {
            "name": "Daughter of A",
            "parent": "Level 2: A"
          }
        ]
      },
      {
        "name": "Level 2: B",
        "parent": "Top Level"
		
      }
    ]
  }
];


// ************** Generate the tree diagram	 *****************
var margin = {top: 20, right: 120, bottom: 20, left: 120},
	width = 960 - margin.right - margin.left,
	height = 500 - margin.top - margin.bottom;
	
var i = 0,
	duration = 750,
	root;

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


var diagonal = d3.svg.diagonal()
        .source(function (d) {
            return {
                "x": d.source.x,
                "y": d.source.y + 150
            };
        })
        .projection(function (d) { return [d.y + 0, d.x + 0];
      });

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

root = treeData[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().append("g")
	  .attr("class", "node")
	  .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
	  .on("click", click);

  nodeEnter.append("rect")
	 .attr("x", function(d) { return d.children || d._children ? 0 : 0; })
	 .attr("y", function(d) { return d.children || d._children ? 15 : 15; })
	 .attr("rx", 10)
	 .attr("ry", 10)
     .attr("width", 10)
     .attr("height", 10)
	 .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeEnter.append("text")
	  .attr("x", 60)
	  .attr("dy", ".35em")
	  .attr("text-anchor", "middle")
	  .text(function(d) { return d.name; })
	  .style("fill-opacity", 1e-6);

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

  nodeUpdate.select("rect")
	  .attr("x", function(d) { return d.children || d._children ? 0 : 0; })
	 .attr("y", function(d) { return d.children || d._children ? -15 : -15; })
	 .attr("rx", 10)
	 .attr("ry", 10)
     .attr("width", 150)
     .attr("height", 30)
	  .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

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

  // 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("rect")
	  .attr("x", function(d) { return d.children || d._children ? 0 : 0; })
	 .attr("y", function(d) { return d.children || d._children ? 15 : 15; })
	 .attr("rx", 10)
	 .attr("ry", 10)
     .attr("width", 10)
     .attr("height", 10);

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

  // 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("fill", "none")
.attr("stroke", "black")
	  .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);
}

</script>

解决方案

Just a superficial attempt.

  1. First add all the text elements
  2. Wrap the text element within certain width using tspans
  3. Get the height of the text element and store as an attribute it in the data itself
  4. Use the stored attribute for setting the height of the rectangle

Reference for wrapping text here. You can always write custom wrapping function.

Hope this helps

var treeData = [
  {
    "name": "Top Level",
    "parent": "null",
    "children": [
      {
        "name": "Level 2: A. Some text here Some text here Some text here Some text here",
        "parent": "Top Level",
        "children": [
          {
            "name": "Son of A Some text here Some text here",
            "parent": "Level 2: A"
          },
          {
            "name": "Daughter of A Some text here Some text here Some text here Some text here Some text here",
            "parent": "Level 2: A"
          }
        ]
      },
      {
        "name": "Level 2: B Some text here Some text here Some text here",
        "parent": "Top Level"
		
      }
    ]
  }
];


// ************** Generate the tree diagram	 *****************
var margin = {top: 20, right: 120, bottom: 20, left: 120},
	width = 960 - margin.right - margin.left,
	height = 500 - margin.top - margin.bottom;
	
var i = 0,
	duration = 750,
	root;

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


var diagonal = d3.svg.diagonal()
        .source(function (d) {
            return {
                "x": d.source.x,
                "y": d.source.y + 150
            };
        })
        .projection(function (d) { return [d.y + 0, d.x + 0];
      });

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

root = treeData[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().append("g")
	  .attr("class", "node")
	  .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
	  .on("click", click);

  nodeEnter.append("rect")
	 .attr("x", function(d) { return d.children || d._children ? 0 : 0; })
	 .attr("y", function(d) { return d.children || d._children ? 15 : 15; })
	 .attr("rx", 10)
	 .attr("ry", 10)
     .attr("width", 10)
     .attr("height", 10)
	 .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeEnter.append("text")
	  .attr("x", 60)
	  .attr("dy", ".35em")
	  .attr("text-anchor", "middle")
	  .text(function(d) { return d.name; })
	  .style("fill-opacity", 1e-6)
  	  .each(function(d) {
  	  	 calculateTextWrap(this,d);
  		});

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

  nodeUpdate.select("rect")
	  .attr("x", function(d) { return d.children || d._children ? 0 : 0; })
	 .attr("y", function(d) { return d.children || d._children ? -15 : -15; })
	 .attr("rx", 10)
	 .attr("ry", 10)
     .attr("width", 150)
     .attr("height", function(d) { return d.rectHeight})
	  .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

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

  // 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("rect")
	  .attr("x", function(d) { return d.children || d._children ? 0 : 0; })
	 .attr("y", function(d) { return d.children || d._children ? 15 : 15; })
	 .attr("rx", 10)
	 .attr("ry", 10)
     .attr("width", 10)
     .attr("height", 10);

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

	function calculateTextWrap(element, data) {
                    var text = d3.select(element);
                    if (text.node().getComputedTextLength() < 150) {
                        //console.log("No need to wrap");
                    } else {
                        var words = text.text().split("").reverse(),
                            word,
                            line = [],
                            lineNumber = 0,
                            lineHeight = 1.1, // ems
                            y = text.attr("y"),
                            dy = parseFloat(0.35),
                            tspan = text.text(null).append("tspan").attr("text-anchor", "start").attr("x", 5).attr("y", y).attr("dy", dy + "em");

                        while (word = words.pop()) {
                            line.push(word);
                            tspan.text(line.join(""));
                            if (tspan.node().getComputedTextLength() > 150) {
                                lineNumber++;
                                line.pop();
                                tspan.text(line.join(""));
                                line = [word];
                                tspan = text.append("tspan").attr("text-anchor", "start").attr("x", 5).attr("y", y).attr("dy", lineHeight + dy + "em").text(word);
                            }
                        }
                    }
				var rectHeight = text.node().getBBox().height;
					if(rectHeight < 30) rectHeight = 30;
				data.rectHeight = rectHeight + 10 ;
                }
	
	
  // 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("fill", "none")
.attr("stroke", "black")
	  .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);
}

.node {
		cursor: pointer;
		border-style: solid;
    border-width: 2px 10px 4px 20px;
	}

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

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

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.0/d3.min.js"></script>

这篇关于如何通过固定矩形框在d3 js中的宽度动态增加高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆