如何解决d3js树图被剪裁

时间:2016-08-16 12:35:36

标签: css d3.js svg

我正在尝试在d3中创建可折叠的树图。虽然网络上有很多例子,但我不是JS的专家或d3来自java背景,并且找不到任何完全符合我需求的东西,因此我在许多博客和要点中找到了不同的模板。

问题是我的图表的下半部分被剪裁了。如果我增加svg大小,那只会拉长图形并且它仍会被剪裁。我发布了我已放置代码的plunkr链接。请滚动到plunkr中的右侧以查看图表。

以下是要呈现树的javascript

var CollapsibleTree = function(elt) {

  var m = [20, 120, 20, 120],
  w = 1280 - m[1] - m[3],
  h = 780 - m[0] - m[2],
  i = 0,
  root;

  var tree = d3.layout.tree()
  .size([w, h]);

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

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

  var vis = d3.select(elt).append("svg:svg")
  .attr("width", w + m[1] + m[3])
  .attr("height", h + m[0] + m[2])
  .append("svg:g")
  .attr("transform", "translate("+w/6+","+h/2+")"); // bidirectional-tree


  var that = {
    init: function(url) {
      var that = this;
      var json = {
         "name":"A",
         "elementType":"ACTION",
         "elementSubType":"ACTION-A",
         "isparent":false,
         "parents":[
            {
               "name":"B",
               "elementType":"RESOURCE",
               "elementSubType":"RESOURCE-A",
               "isparent":true
            }
         ],
         "children":[
            {
               "name":"C",
               "elementType":"RESOURCE",
               "elementSubType":"RESOURCE-C",
               "isparent":false,
               "children":[
                  {
                     "name":"D",
                     "elementType":"ACTION",
                     "elementSubType":"ACTION-A",
                     "isparent":false,
                     "children":[
                        {
                           "name":"E",
                           "elementType":"RESOURCE",
                           "elementSubType":"RESOURCE-A",
                           "isparent":false,
                           "children":[
                              {
                                 "name":"F",
                                 "elementType":"ACTION",
                                 "elementSubType":"ACTION-C",
                                 "isparent":false,
                                 "children":[
                                    {
                                       "name":"G",
                                       "elementType":"RESOURCE",
                                       "elementSubType":"RESOURCE-C",
                                       "isparent":false
                                    }
                                 ]
                              }
                           ]
                        }
                     ]
                  }
               ]
            }
         ]
      };
      root = json;
      root.x = w / 2;
      root.y = h / 2;

      that.updateBoth(root);
    },

    updateBoth: function(source) {
      var duration = d3.event && d3.event.altKey ? 5000 : 300;

      // Compute the new tree layout.
      var nodes = tree.nodes(root).reverse();

      // Normalize for fixed-depth.
      nodes.forEach(function(d) { d.y = d.depth * 0.5*h/4; });

      // 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("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) {
        if( that.isParent(d) ) {
          return "translate(" + source.x + "," + -source.y + ")";
        } else {
          return "translate(" + source.x + "," + source.y + ")";
        }
      })
      .on("click", function(d) { that.toggle(d); that.updateBoth(d); });

      // Add images to node
      nodeEnter.append("svg:image")
      .attr("xlink:href", "img/file.png")
      .attr("width", 35)
      .attr("height", 35)
      .attr("x",function(d) { return -20; }) // position the images
      .attr("y",function(d) { return -20; });

      nodeEnter.append("text")
      // .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
      .attr("x", function(d) {
        return -10;
      })
      .attr("y", 20)
      .attr("dy", ".35em")
      .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
      .attr("text-anchor", function(d) {
        return "middle";
      })
      .text(function(d) {
        if (d.name.length > 10){
          return d.name.substring(0,10)+d.name.substring(10,d.name.length);
        }
        else {
          return d.name;
        }
      })
      .style("fill", "black")
      .style("fill-opacity", 1e-6);

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

      nodeUpdate.select("text")
      .style("fill-opacity", 1)
      .attr("class", function(d){
        if (d.status==="incomplete" || d.status === "failed"){
          return "blink";
        } else {
          return "non-blink"
        }
      });

      // 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 + ")"; })
      .attr("transform", function(d) { // custom code to fix error in node exit
        if (that.isParent(d)){
          return "translate(" + source.x + "," + -source.y + ")"; // controls exit of parents
        }
        else{
          return "translate(" + source.x + "," + source.y + ")"; // controls exit of children
        }
      })
      .remove();

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

      // Update the links…
      var link = vis.selectAll("path.link")
      .data(tree.links_parents(nodes).concat(tree.links(nodes)), function(d) { return d.target.id; });

      // Enter any new links at the parent's previous position.
      link.enter().insert("svg:path", "g")
      .attr("class", "link")
      .style("stroke", function(d) {
        return "black";
      })
      .attr("d", function(d) {
        var o = {x: source.x, y: source.y};
        if( that.isParent(d.target) ) {
          return parentdiagonal({source: o, target: o});
        } else {
          return childdiagonal({source: o, target: o});
        }
      })
      .transition()
      .duration(duration)
      .attr("d", function(d) {
        if( that.isParent(d.target) ) {
          return parentdiagonal(d);
        } else {
          // return parentdiagonal(d);
          return childdiagonal(d);
        }
      })

      // Transition links to their new position.
      link.transition()
      .duration(duration)
      .attr("d", function(d) {
        if( that.isParent(d.target) ) {
          return parentdiagonal(d);
        } else {
          return childdiagonal(d);
        }
      })

      // 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 parentdiagonal({source: o, target: o});
        if( that.isParent(d.target) ) {
          return parentdiagonal({source: o, target: o});
        } else {
          return childdiagonal({source: o, target: o});
        }
      })
      .remove();

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

    isParent: function(node) {
      if( node.parent && node.parent != root ) {
        return this.isParent(node.parent);
      } else
      if( node.isparent ) {
        return true;
      } else {
        return false;
      }
    },

    // Toggle children or parents (one level).
    toggle: function(d) {
      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else {
        d.children = d._children;
        d._children = null;
      }
      if (d.parents) {
        d._parents = d.parents;
        d.parents = null;
      } else {
        d.parents = d._parents;
        d._parents = null;
      }
    },

    // Toggle successors or aancestors (multiple level)
    toggleAll: function(d) {
      if (d.children) {
        d.children.forEach(that.toggleAll);
        that.toggle(d);
      }
      if (d.parents) {
        d.parents.forEach(that.toggleAll);
        that.toggle(d);
      }
    }

  }

  return that;
}

以下是css

body {
  overflow: hidden;
  margin: 0;
  font-size: 14px;
  font-family: "Helvetica Neue", Helvetica;
}

#chart, #header, #footer {
  position: absolute;
  top: 0;
}

#header, #footer {
  z-index: 1;
  display: block;
  font-size: 36px;
  font-weight: 300;
  text-shadow: 0 1px 0 #fff;
}

#header.inverted, #footer.inverted {
  color: #fff;
  text-shadow: 0 1px 4px #000;
}

#header {
  top: 80px;
  left: 140px;
  width: 1000px;
}

#footer {
  top: 680px;
  right: 140px;
  text-align: right;
}

rect {
  fill: none;
  pointer-events: all;
}

pre {
  font-size: 18px;
}

line {
  stroke: #000;
  stroke-width: 1.5px;
}

.string, .regexp {
  color: #f39;
}

.keyword {
  color: #00c;
}

.comment {
  color: #777;
  font-style: oblique;
}

.number {
  color: #369;
}

.class, .special {
  color: #1181B8;
}

a:link, a:visited {
  color: #000;
  text-decoration: none;
}

a:hover {
  color: #666;
}

.hint {
  position: absolute;
  right: 0;
  width: 1280px;
  font-size: 12px;
  color: #999;
}

.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;
}

/*svg {
  border: 1px;
  border-style: solid;
  border-color: black;
}*/

#foo {
  border: 5px;
  border-style: dashed;
  border-color: black;
  background-color: pink;
}

#categoryHierarchy{
  margin: 5px;
  height: 700px;
  width: auto;
  border: 2px;
  border-style: solid;
  border-color: #000;
  overflow: scroll;

  /*padding: 10px;*/
}

html个文件

<body>
    <div id="categoryHierarchy"></div>
    <script type="text/javascript">
          $(document).ready(function(event) {
            var tree = CollapsibleTree("#categoryHierarchy");
            tree.init('sample.json');
          });
  </script>
  </body>

1 个答案:

答案 0 :(得分:0)

您可以尝试缩短每个“节点”之间的距离。

E.g。第98行尝试使用h - 'x',我尝试使用300。

nodes.forEach(function(d) { d.y = d.depth * 0.5*(h-300)/4; });