在d3 js树布局中将标签放置在链接的中间

时间:2016-02-01 05:48:20

标签: d3.js tree

我尝试使用d3js树布局创建标记的双树。到目前为止功能正常,但我面临的问题是,我无法将标签放在链接的中间。

现在它看起来像这样(一旦你添加了足够的节点) Tree layout

这是我在g元素中添加边和标签的代码的一部分。我尝试在链接的中点添加标签,但它不起作用。 (显示的代码是双树的右侧)

    var edge = d3.select("#right-edges")
        .append("g")
        .attr("class", "edge-container")
        .data(links);

         var link = edge.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", "edge-container")
        .attr("class", "link")
        .attr("id", function(d) {
            return ("rightlink" + d.source.id + "-" + d.target.id)
        })
        .attr("d", function(d) {
            var o = {
                x: source.x0,
                y: source.y0
            };

            return diagonal({
                source: o,
                target: o
            });
        }).on("click", removelink)
        .on("mouseover", showRemoveButton)
        .on("mouseout", hideRemoveButton);

    function showRemoveButton() {
        console.log("hover");
    }

    function hideRemoveButton() {
        console.log("hover-out");
    }




    var text = edge.selectAll("text.text-link")
        .data(links, function(d) {
            return d.target.id + d.source.id;
        });

    text.enter().insert("text", "edge-container")
        .attr("class", "text-link")

    .attr("x", function(d) {
            var x = (d.source.y + d.target.y) / 2
            return parseInt(x + 25);
        })
        .attr("y", function(d) {
            var y = (d.source.x + d.target.x) / 2
            return y;
        })
        .text("test-label")
        .attr("text-anchor", "start")
        .style("font-size", "12px");

到目前为止,这是工作代码 -



var treeData = [{
    "name": "Device",
    "parent": "null"
  }

];
var treeData2 = [{
    "name": "Device",
    "parent": "null"
  }

];

$(document).ready(function($) {

  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 2260 - margin.right - margin.left,
    height = 500 - margin.top - margin.bottom;

  var svg = d3.select('.doubletree-container').append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom);


  $.fn.makeDoubleTree = function() {

    this.makeRightTree();
    this.makeLeftTree();

  };


}(jQuery));


$.fn.makeRightTree = function() {
  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 1260 - 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()
    .projection(function(d) {
      return [d.y, d.x];
    });

  var svg = d3.select("svg").append("g")
    .attr("class", "right-tree-container")
    .attr("transform", "translate(600,0)");
  svg.append("g").attr("id", "right-edges")


  root = treeData[0];
  oldrx = root.x0 = height / 2;
  oldry = root.y0 = 0;

  update(root);

  function update(source) {


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


    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", function(d) {
        console.log(d);
        if (d.parent == "null") {

          if (d.children)

          {
            return "node rightparent collapsed" //since its root its parent is null
          } else {
            return "node rightparent"
          }

        } else {
          if (d.children) {
            return "node rightchild collapsed" //all nodes with parent will have this class
          } else {
            return "node rightchild" //all nodes with parent will have this class
          }
        }

      })
      .attr("transform", function(d) {
        return "translate(" + source.y0 + "," + source.x0 + ")";
      })
      .on("click", click);

    nodeEnter.append("rect")
      .attr("id", function(d) {
        return "rightnode" + d.id;
      })
      .attr("x", "-10")
      .attr("y", "-15")
      .attr("height", 30)
      .attr("width", 100)
      .attr("rx", 15)
      .attr("ry", 15)
      .style("fill", "#f1f1f1");

    nodeEnter.append("image")
      .attr("xlink:href", "img.png")
      .attr("x", "0")
      .attr("y", "-10")
      .attr("width", 16)
      .attr("height", 16);




    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.name;
      })
      .style("fill-opacity", 1e-6);




    var addRightChild = nodeEnter.append("g").attr("class", "addRightChild");
    addRightChild.append("rect")
      .attr("x", "90")
      .attr("y", "-10")
      .attr("height", 20)
      .attr("width", 20)
      .attr("rx", 10)
      .attr("ry", 10)
      .style("stroke", "#444")
      .style("stroke-width", "2")
      .style("fill", "#ccc");

    addRightChild.append("line")
      .attr("x1", 95)
      .attr("y1", 1)
      .attr("x2", 105)
      .attr("y2", 1)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    addRightChild.append("line")
      .attr("x1", 100)
      .attr("y1", -4)
      .attr("x2", 100)
      .attr("y2", 6)
      .attr("stroke", "#444")
      .style("stroke-width", "2");



    // adding the right chevron
    var rightChevron = nodeEnter.append("g").attr("class", "right-chevron");




    rightChevron.append("line")
      .attr("x1", 75)
      .attr("y1", -5)
      .attr("x2", 80)
      .attr("y2", 0)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    rightChevron.append("line")
      .attr("x1", 80)
      .attr("y1", 0)
      .attr("x2", 75)
      .attr("y2", 5)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    rightChevron.on("click", function(d) {


    });




    // Transition nodes to their new position.
    var nodeUpdate = node.transition()
      .duration(duration)
      .attr("transform", function(d) {
        if (d.parent == "null") {
          d.y = oldry;
          d.x = oldrx;
        }

        return "translate(" + d.y + "," + d.x + ")";
      });



    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) {
        return "translate(" + source.y + "," + source.x + ")";
      })
      .remove();


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




    // Update the links…
    var edge = d3.select("#right-edges")
      .append("g")
      .attr("class", "edge-container")
      .data(links);

    var link = edge.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", "edge-container")
      .attr("class", "link")
      .attr("id", function(d) {
        return ("rightlink" + d.source.id + "-" + d.target.id)
      })
      .attr("d", function(d) {
        var o = {
          x: source.x0,
          y: source.y0
        };

        return diagonal({
          source: o,
          target: o
        });
      }).on("click", removelink)
      .on("mouseover", showRemoveButton)
      .on("mouseout", hideRemoveButton);

    function showRemoveButton() {
      console.log("hover");
    }

    function hideRemoveButton() {
      console.log("hover-out");
    }




    var text = edge.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id + d.source.id;
      });

    text.enter().insert("text", "edge-container")
      .attr("class", "text-link")

    .attr("x", function(d) {
        var x = (d.source.y + d.target.y) / 2
        return parseInt(x + 25);
      })
      .attr("y", function(d) {
        var y = (d.source.x + d.target.x) / 2
        return y;
      })
      .text("test-label")
      .attr("text-anchor", "start")
      .style("font-size", "12px");

    /* transition labels to new positions */
    var label = svg.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id;
      });

    // Transition links to their new position.
    label.transition()
      .duration(0);

    // Transition exiting nodes to the parent's new position.
    label.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {
          x: source.x,
          y: source.y
        };
        return diagonal({
          source: o,
          target: o
        });
      })
      .remove();


    // d3.selectAll(".right-tree-container .remove-child").remove();  


    //    var removeButton = edge.selectAll(".remove-child")
    //    .data(links, function(d) {
    //        return d.target.id + d.source.id;
    //    });


    // removeButton.enter().insert("rect", "edge-container")
    //    .attr("class", "remove-child")
    //     .attr("x", function(d) {
    //        var x = (d.source.y + d.target.y) / 2
    //        return parseInt(x + 45);
    //    })
    //    .attr("y", function(d) {
    //        var y = (d.source.x + d.target.x) / 2
    //        return y;
    //    })
    //    .attr("width","20")
    //    .attr("height","20")
    //    .attr("rx","10")
    //    .attr("ry","10")
    //    .style("fill","white")
    //    .style("stroke","#444")
    //    .style("stroke-width","2");




    function removelink(d) {

      var confirmDelete = confirm("Are you sure you want to delete?");
      if (confirmDelete) {
        //this is the links target node which you want to remove
        var target = d.target;
        //make new set of children
        var children = [];
        //iterate through the children 
        target.parent.children.forEach(function(child) {
          if (child.id != target.id) {
            //add to the child list if target id is not same 
            //so that the node target is removed.
            children.push(child);
          }
        });
        //set the target parent with new set of children sans the one which is removed
        target.parent.children = children;
        //redraw the parent since one of its children is removed
        update(d.target.parent)
      }



    }

    var link = svg.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });

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




    addRightChild.on("click", function(d) {


      event.stopPropagation();
      $("#child-info").show();
      $("#child-text").val("");

      $("#btn-add-child").off('click');
      $("#btn-add-child").click(function() {
        var childname = $("#child-text").val();


        if (typeof d._children === 'undefined' || d._children === null) {
          if (typeof d.children === 'undefined') {


            var newChild = [{
              "name": childname,
              "parent": "Son Of A",
            }];


            var newnodes = tree.nodes(newChild);
            d.children = newnodes[0];
            // console.log(d.children);
            update(d);


          } else {
            var newChild = {
              "name": childname,
              "parent": "Son Of A",
            };
            // console.log(d.children);
            d.children.push(newChild);
            // console.log(d.children);
            update(d);
          }
        } else {
          var newChild = {
            "name": childname,
            "parent": "Son Of A",
          };

          d.children = d._children;
          d.children.push(newChild);
          // console.log(d.children);
          update(d);


        }


        $("#child-info").hide();
      });
    });;
  }

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

    $(".addLeftChild, .addRightChild").hide();
    if (d.id === 1) {
      $(".rightparent").children(".addRightChild").show();
      $(this).children(".addRightChild").show();
    } else {
      $(this).children(".addRightChild").show();

    }
    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links
    while (d.parent) {

      d3.select("#leftnode1").style("fill", "#F7CA18");
      d3.selectAll("#rightnode" + d.id).style("fill", "#F7CA18"); //color the node
      if (d.parent != "null")
        d3.selectAll("#rightlink" + d.parent.id + "-" + d.id).style("stroke", "#F7CA18"); //color the path
      d = d.parent;
    }
  }
}


$.fn.makeLeftTree = function() {
  // ************** Generate the tree diagram  *****************
  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 1260 - 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()
    .projection(function(d) {
      return [d.y, d.x];
    });

  var svg = d3.select("svg").append("g")
    .attr("class", "left-tree-container")
    .attr("transform", "translate(-421,0)");

  svg.append("g").attr("id", "left-edges")

  root = treeData2[0];
  oldlx = root.x0 = height / 2;
  oldly = root.y0 = width;

  update(root);

  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 = width - (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", function(d) {
        if (d.parent == "null") {
          return "node leftparent" //since its root its parent is null
        } else
          return "node leftchild" //all nodes with parent will have this class
      })
      .attr("transform", function(d) {
        return "translate(" + source.y0 + "," + source.x0 + ")";
      })
      .on("click", click);

    nodeEnter.append("rect")
      .attr("x", "-10")
      .attr("id", function(d) {
        return "leftnode" + d.id;
      })
      .attr("y", "-15")
      .attr("height", 30)
      .attr("width", 100)
      .attr("rx", 15)
      .attr("ry", 15)
      .style("fill", "#f1f1f1");

    nodeEnter.append("image")
      .attr("xlink:href", "img.png")
      .attr("x", "60")
      .attr("y", "-10")
      .attr("width", 16)
      .attr("height", 16);

    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.name;
      })
      .style("fill-opacity", 1e-6);

    var addLeftChild = nodeEnter.append("g").attr("class", "addLeftChild");
    addLeftChild.append("rect")
      .attr("x", "-30")
      .attr("y", "-10")
      .attr("height", 20)
      .attr("width", 20)
      .attr("rx", 10)
      .attr("ry", 10)
      .style("stroke", "#444")
      .style("stroke-width", "2")
      .style("fill", "#ccc");

    addLeftChild.append("line")
      .attr("x1", -25)
      .attr("y1", 1)
      .attr("x2", -15)
      .attr("y2", 1)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    addLeftChild.append("line")
      .attr("x1", -20)
      .attr("y1", -4)
      .attr("x2", -20)
      .attr("y2", 6)
      .attr("stroke", "#444")
      .style("stroke-width", "2");


    var leftChevron = nodeEnter.append("g").attr("class", "left-chevron");

    leftChevron.append("line")
      .attr("x1", 5)
      .attr("y1", -5)
      .attr("x2", 0)
      .attr("y2", 0)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    leftChevron.append("line")
      .attr("x1", 0)
      .attr("y1", 0)
      .attr("x2", 5)
      .attr("y2", 5)
      .attr("stroke", "#444")
      .style("stroke-width", "2");




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



    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) {
        return "translate(" + source.y + "," + source.x + ")";
      })
      .remove();

    // nodeExit.select("circle")
    //     .attr("r", 1e-6);

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

    var edge = d3.select("#left-edges")
      .append("g")
      .attr("class", "edge-container")
      .data(links);




    var text = edge.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id + d.source.id;
      });

    text.enter().append("text")
      .attr("class", "text-link")

    .attr("x", function(d) {
        var x = (d.source.y + d.target.y) / 2
        return parseInt(x + 45);
      })
      .attr("y", function(d) {
        var y = (d.source.x + d.target.x) / 2
        return y;
      })
      .text("test-label")
      .attr("text-anchor", "start")
      .style("font-size", "12px");


    /* transition labels to new positions */
    var label = svg.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id;
      });

    // Transition links to their new position.
    label.transition()
      .duration(0);

    // Transition exiting nodes to the parent's new position.
    label.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {
          x: source.x,
          y: source.y
        };
        return diagonal({
          source: o,
          target: o
        });
      })
      .remove();

    var link = edge.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });



    // Update the links…


    // Enter any new links at the parent's previous position.
    link.enter().insert("path", "edge-container")
      .attr("class", "link")
      .attr("id", function(d) {
        return ("leftlink" + d.source.id + "-" + d.target.id)
      })
      .attr("d", function(d) {
        var o = {
          x: source.x0,
          y: source.y0
        };
        return diagonal({
          source: o,
          target: o
        });
      }).on("click", removelink);

    function removelink(d) {

      var confirmDelete = confirm("Are you sure you want to delete?");


      if (confirmDelete) {

        //this is the links target node which you want to remove
        var target = d.target;
        //make new set of children
        var children = [];
        //iterate through the children 
        target.parent.children.forEach(function(child) {
          if (child.id != target.id) {
            //add to teh child list if target id is not same 
            //so that the node target is removed.
            children.push(child);
          }
        });
        //set the target parent with new set of children sans the one which is removed
        target.parent.children = children;
        //redraw the parent since one of its children is removed
        update(d.target.parent)
      }

    }

    var link = svg.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });

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


    addLeftChild.on("click", function(d) {

      event.stopPropagation();
      $("#child-info").show();
      $("#child-text").val("");

      $("#btn-add-child").off('click');
      $("#btn-add-child").click(function() {
        var childname = $("#child-text").val();

        if (typeof d._children === 'undefined' || d._children === null) {
          if (typeof d.children === 'undefined') {


            var newChild = [{
              "name": childname,
              "parent": "Son Of A",
            }];

            // console.log(tree.nodes(newChild[0]));
            var newnodes = tree.nodes(newChild);
            d.children = newnodes[0];
            // console.log(d.children);
            update(d);


          } else {
            var newChild = {
              "name": childname,
              "parent": "Son Of A",
            };
            // console.log(d.children);
            d.children.push(newChild);
            // console.log(d.children);
            update(d);
          }
        } else {
          var newChild = {
            "name": childname,
            "parent": "Son Of A",
          };
          console.log("collapsed case");
          d.children = d._children;
          d.children.push(newChild);
          // console.log(d.children);
          update(d);


        }


        $("#child-info").hide();
      });
    });
  }

  // Toggle children on click.
  function click(d) {

    if (d.id !== 1) {

      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else {
        d.children = d._children;
        d._children = null;
      }
      update(d);
    }


    $(".addLeftChild, .addRightChild").hide();
    if (d.id === 1) {
      $(".rightparent").children(".addRightChild").show();
      $(this).children(".addLeftChild").show();
    } else {
      $(this).children(".addLeftChild").show();

    }


    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links
    while (d.parent) {
      d3.selectAll("#leftnode" + d.id).style("fill", "#F7CA18"); //color the node
      if (d.parent != "null")
        d3.selectAll("#leftlink" + d.parent.id + "-" + d.id).style("stroke", "F7CA18"); //color the path
      d = d.parent;
    }

  }
}

body {
  margin: 0;
  padding: 0;
}
#child-info {
  width: 100px;
  height: 50px;
  height: auto;
  position: fixed;
  padding: 10px;
  display: none;
  left: 40%;
  z-index: 100;
}
.asset-title {
  padding: 15px;
  float: left;
}
.node {
  cursor: pointer;
}
.node text {
  font: 12px sans-serif;
}
.link {
  fill: none;
  stroke: #85e0e0;
  stroke-width: 2px;
}
.rightparent>rect {
  display: none;
}
.leftparent>rect {
  fill: #f1f1f1;
  stroke: #ccc;
  stroke-width: 2;
}
.leftparent .left-chevron {
  display: none;
}
.leftparent image {
  display: none;
}
.addLeftChild,
.addRightChild {
  display: none;
}
.left-chevron,
.right-chevron {
  display: none;
}
.collapsed .left-chevron,
.collapsed .right-chevron {
  display: block;
}

<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 id="child-info" style="display:none">
  <input type="text" id="child-text" placeholder="child name">
  <button id="btn-add-child">add</button>
</div>
<div class="doubletree-container">
</div>


<script type="text/javascript">
  $(document).ready(function() {
    $(".doubletree-container").makeDoubleTree();
  });
</script>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

我已添加到您的代码中。结果如下。主要部分是:

.attr("x", function(d) {
        var x = (d.source.y + d.target.y) / 2;
     d.thisText =  "test-label";
        return x - d.thisText.length/2 + 5; //added 5 to make up for node width. This needs to be worked out properly
      })

它并不完全是中心,因为我没有实现节点中心和标签之间的差异。但是改变上面的代码将获得你想要的结果:)希望这会有所帮助。

var treeData = [{
    "name": "Device",
    "parent": "null"
  }

];
var treeData2 = [{
    "name": "Device",
    "parent": "null"
  }

];

$(document).ready(function($) {

  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 2260 - margin.right - margin.left,
    height = 500 - margin.top - margin.bottom;

  var svg = d3.select('.doubletree-container').append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom);


  $.fn.makeDoubleTree = function() {

    this.makeRightTree();
    this.makeLeftTree();

  };


}(jQuery));


$.fn.makeRightTree = function() {
  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 1260 - 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()
    .projection(function(d) {
      return [d.y, d.x];
    });

  var svg = d3.select("svg").append("g")
    .attr("class", "right-tree-container")
    .attr("transform", "translate(600,0)");
  svg.append("g").attr("id", "right-edges")


  root = treeData[0];
  oldrx = root.x0 = height / 2;
  oldry = root.y0 = 0;

  update(root);

  function update(source) {


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


    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", function(d) {
        console.log(d);
        if (d.parent == "null") {

          if (d.children)

          {
            return "node rightparent collapsed" //since its root its parent is null
          } else {
            return "node rightparent"
          }

        } else {
          if (d.children) {
            return "node rightchild collapsed" //all nodes with parent will have this class
          } else {
            return "node rightchild" //all nodes with parent will have this class
          }
        }

      })
      .attr("transform", function(d) {
        return "translate(" + source.y0 + "," + source.x0 + ")";
      })
      .on("click", click);

    nodeEnter.append("rect")
      .attr("id", function(d) {
        return "rightnode" + d.id;
      })
      .attr("x", "-10")
      .attr("y", "-15")
      .attr("height", 30)
      .attr("width", 100)
      .attr("rx", 15)
      .attr("ry", 15)
      .style("fill", "#f1f1f1");

    nodeEnter.append("image")
      .attr("xlink:href", "img.png")
      .attr("x", "0")
      .attr("y", "-10")
      .attr("width", 16)
      .attr("height", 16);




    nodeEnter.append("text")
      .attr("x", function(d) {
        return d.children || d._children ? 0 : 0;
      })
      .attr("dy", ".35em")
      .attr("text-anchor", function(d) {
        return d.children || d._children ? "end" : "start";
      })
      .text(function(d) {
        return d.name;
      })
      .style("fill-opacity", 1e-6);




    var addRightChild = nodeEnter.append("g").attr("class", "addRightChild");
    addRightChild.append("rect")
      .attr("x", "90")
      .attr("y", "-10")
      .attr("height", 20)
      .attr("width", 20)
      .attr("rx", 10)
      .attr("ry", 10)
      .style("stroke", "#444")
      .style("stroke-width", "2")
      .style("fill", "#ccc");

    addRightChild.append("line")
      .attr("x1", 95)
      .attr("y1", 1)
      .attr("x2", 105)
      .attr("y2", 1)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    addRightChild.append("line")
      .attr("x1", 100)
      .attr("y1", -4)
      .attr("x2", 100)
      .attr("y2", 6)
      .attr("stroke", "#444")
      .style("stroke-width", "2");



    // adding the right chevron
    var rightChevron = nodeEnter.append("g").attr("class", "right-chevron");




    rightChevron.append("line")
      .attr("x1", 75)
      .attr("y1", -5)
      .attr("x2", 80)
      .attr("y2", 0)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    rightChevron.append("line")
      .attr("x1", 80)
      .attr("y1", 0)
      .attr("x2", 75)
      .attr("y2", 5)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    rightChevron.on("click", function(d) {


    });




    // Transition nodes to their new position.
    var nodeUpdate = node.transition()
      .duration(duration)
      .attr("transform", function(d) {
        if (d.parent == "null") {
          d.y = oldry;
          d.x = oldrx;
        }

        return "translate(" + d.y + "," + d.x + ")";
      });



    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) {
        return "translate(" + source.y + "," + source.x + ")";
      })
      .remove();


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




    // Update the links…
    var edge = d3.select("#right-edges")
      .append("g")
      .attr("class", "edge-container")
      .data(links);

    var link = edge.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", "edge-container")
      .attr("class", "link")
      .attr("id", function(d) {
        return ("rightlink" + d.source.id + "-" + d.target.id)
      })
      .attr("d", function(d) {
        var o = {
          x: source.x0,
          y: source.y0
        };

        return diagonal({
          source: o,
          target: o
        });
      }).on("click", removelink)
      .on("mouseover", showRemoveButton)
      .on("mouseout", hideRemoveButton);

    function showRemoveButton() {
      console.log("hover");
    }

    function hideRemoveButton() {
      console.log("hover-out");
    }




    var text = edge.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id + d.source.id;
      });

    text.enter().insert("text", "edge-container")
      .attr("class", "text-link")

    .attr("x", function(d) {
        var x = (d.target.y + d.source.y) / 2
        return x - 50;
      })
      .attr("y", function(d) {
        var y = (d.source.x + d.target.x) / 2
        return y;
      })
      .text("test-label")
      .attr("text-anchor", "start")
      .style("font-size", "12px");

    /* transition labels to new positions */
    var label = svg.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id;
      });

    // Transition links to their new position.
    label.transition()
      .duration(0);

    // Transition exiting nodes to the parent's new position.
    label.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {
          x: source.x,
          y: source.y
        };
        return diagonal({
          source: o,
          target: o
        });
      })
      .remove();


    // d3.selectAll(".right-tree-container .remove-child").remove();  


    //    var removeButton = edge.selectAll(".remove-child")
    //    .data(links, function(d) {
    //        return d.target.id + d.source.id;
    //    });


    // removeButton.enter().insert("rect", "edge-container")
    //    .attr("class", "remove-child")
    //     .attr("x", function(d) {
    //        var x = (d.source.y + d.target.y) / 2
    //        return parseInt(x + 45);
    //    })
    //    .attr("y", function(d) {
    //        var y = (d.source.x + d.target.x) / 2
    //        return y;
    //    })
    //    .attr("width","20")
    //    .attr("height","20")
    //    .attr("rx","10")
    //    .attr("ry","10")
    //    .style("fill","white")
    //    .style("stroke","#444")
    //    .style("stroke-width","2");




    function removelink(d) {

      var confirmDelete = confirm("Are you sure you want to delete?");
      if (confirmDelete) {
        //this is the links target node which you want to remove
        var target = d.target;
        //make new set of children
        var children = [];
        //iterate through the children 
        target.parent.children.forEach(function(child) {
          if (child.id != target.id) {
            //add to the child list if target id is not same 
            //so that the node target is removed.
            children.push(child);
          }
        });
        //set the target parent with new set of children sans the one which is removed
        target.parent.children = children;
        //redraw the parent since one of its children is removed
        update(d.target.parent)
      }



    }

    var link = svg.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });

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




    addRightChild.on("click", function(d) {


      event.stopPropagation();
      $("#child-info").show();
      $("#child-text").val("");

      $("#btn-add-child").off('click');
      $("#btn-add-child").click(function() {
        var childname = $("#child-text").val();


        if (typeof d._children === 'undefined' || d._children === null) {
          if (typeof d.children === 'undefined') {


            var newChild = [{
              "name": childname,
              "parent": "Son Of A",
            }];


            var newnodes = tree.nodes(newChild);
            d.children = newnodes[0];
            // console.log(d.children);
            update(d);


          } else {
            var newChild = {
              "name": childname,
              "parent": "Son Of A",
            };
            // console.log(d.children);
            d.children.push(newChild);
            // console.log(d.children);
            update(d);
          }
        } else {
          var newChild = {
            "name": childname,
            "parent": "Son Of A",
          };

          d.children = d._children;
          d.children.push(newChild);
          // console.log(d.children);
          update(d);


        }


        $("#child-info").hide();
      });
    });;
  }

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

    $(".addLeftChild, .addRightChild").hide();
    if (d.id === 1) {
      $(".rightparent").children(".addRightChild").show();
      $(this).children(".addRightChild").show();
    } else {
      $(this).children(".addRightChild").show();

    }
    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links
    while (d.parent) {

      d3.select("#leftnode1").style("fill", "#F7CA18");
      d3.selectAll("#rightnode" + d.id).style("fill", "#F7CA18"); //color the node
      if (d.parent != "null")
        d3.selectAll("#rightlink" + d.parent.id + "-" + d.id).style("stroke", "#F7CA18"); //color the path
      d = d.parent;
    }
  }
}


$.fn.makeLeftTree = function() {
  // ************** Generate the tree diagram  *****************
  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 1260 - 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()
    .projection(function(d) {
      return [d.y, d.x];
    });

  var svg = d3.select("svg").append("g")
    .attr("class", "left-tree-container")
    .attr("transform", "translate(-421,0)");

  svg.append("g").attr("id", "left-edges")

  root = treeData2[0];
  oldlx = root.x0 = height / 2;
  oldly = root.y0 = width;

  update(root);

  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 = width - (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", function(d) {
        if (d.parent == "null") {
          return "node leftparent" //since its root its parent is null
        } else
          return "node leftchild" //all nodes with parent will have this class
      })
      .attr("transform", function(d) {
        return "translate(" + source.y0 + "," + source.x0 + ")";
      })
      .on("click", click);

    nodeEnter.append("rect")
      .attr("x", "-10")
      .attr("id", function(d) {
        return "leftnode" + d.id;
      })
      .attr("y", "-15")
      .attr("height", 30)
      .attr("width", 100)
      .attr("rx", 15)
      .attr("ry", 15)
      .style("fill", "#f1f1f1");

    nodeEnter.append("image")
      .attr("xlink:href", "img.png")
      .attr("x", "60")
      .attr("y", "-10")
      .attr("width", 16)
      .attr("height", 16);

    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.name;
      })
      .style("fill-opacity", 1e-6);

    var addLeftChild = nodeEnter.append("g").attr("class", "addLeftChild");
    addLeftChild.append("rect")
      .attr("x", "-30")
      .attr("y", "-10")
      .attr("height", 20)
      .attr("width", 20)
      .attr("rx", 10)
      .attr("ry", 10)
      .style("stroke", "#444")
      .style("stroke-width", "2")
      .style("fill", "#ccc");

    addLeftChild.append("line")
      .attr("x1", -25)
      .attr("y1", 1)
      .attr("x2", -15)
      .attr("y2", 1)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    addLeftChild.append("line")
      .attr("x1", -20)
      .attr("y1", -4)
      .attr("x2", -20)
      .attr("y2", 6)
      .attr("stroke", "#444")
      .style("stroke-width", "2");


    var leftChevron = nodeEnter.append("g").attr("class", "left-chevron");

    leftChevron.append("line")
      .attr("x1", 5)
      .attr("y1", -5)
      .attr("x2", 0)
      .attr("y2", 0)
      .attr("stroke", "#444")
      .style("stroke-width", "2");

    leftChevron.append("line")
      .attr("x1", 0)
      .attr("y1", 0)
      .attr("x2", 5)
      .attr("y2", 5)
      .attr("stroke", "#444")
      .style("stroke-width", "2");




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



    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) {
        return "translate(" + source.y + "," + source.x + ")";
      })
      .remove();

    // nodeExit.select("circle")
    //     .attr("r", 1e-6);

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

    var edge = d3.select("#left-edges")
      .append("g")
      .attr("class", "edge-container")
      .data(links);




    var text = edge.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id + d.source.id;
      });

    text.enter().append("text")
      .attr("class", "text-link")

    .attr("x", function(d) {
        var x = (d.source.y + d.target.y) / 2;
     d.thisText =  "test-label";
        return x - d.thisText.length/2 + 5;
      })
      .attr("y", function(d) {
        var y = (d.source.x + d.target.x) / 2
        return y;
      })
      .text(function(d){return d.thisText})
      .attr("text-anchor", "start")
      .style("font-size", "12px");


    /* transition labels to new positions */
    var label = svg.selectAll("text.text-link")
      .data(links, function(d) {
        return d.target.id;
      });

    // Transition links to their new position.
    label.transition()
      .duration(0);

    // Transition exiting nodes to the parent's new position.
    label.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {
          x: source.x,
          y: source.y
        };
        return diagonal({
          source: o,
          target: o
        });
      })
      .remove();

    var link = edge.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });



    // Update the links…


    // Enter any new links at the parent's previous position.
    link.enter().insert("path", "edge-container")
      .attr("class", "link")
      .attr("id", function(d) {
        return ("leftlink" + d.source.id + "-" + d.target.id)
      })
      .attr("d", function(d) {
        var o = {
          x: source.x0,
          y: source.y0
        };
        return diagonal({
          source: o,
          target: o
        });
      }).on("click", removelink);

    function removelink(d) {

      var confirmDelete = confirm("Are you sure you want to delete?");


      if (confirmDelete) {

        //this is the links target node which you want to remove
        var target = d.target;
        //make new set of children
        var children = [];
        //iterate through the children 
        target.parent.children.forEach(function(child) {
          if (child.id != target.id) {
            //add to teh child list if target id is not same 
            //so that the node target is removed.
            children.push(child);
          }
        });
        //set the target parent with new set of children sans the one which is removed
        target.parent.children = children;
        //redraw the parent since one of its children is removed
        update(d.target.parent)
      }

    }

    var link = svg.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });

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


    addLeftChild.on("click", function(d) {

      event.stopPropagation();
      $("#child-info").show();
      $("#child-text").val("");

      $("#btn-add-child").off('click');
      $("#btn-add-child").click(function() {
        var childname = $("#child-text").val();

        if (typeof d._children === 'undefined' || d._children === null) {
          if (typeof d.children === 'undefined') {


            var newChild = [{
              "name": childname,
              "parent": "Son Of A",
            }];

            // console.log(tree.nodes(newChild[0]));
            var newnodes = tree.nodes(newChild);
            d.children = newnodes[0];
            // console.log(d.children);
            update(d);


          } else {
            var newChild = {
              "name": childname,
              "parent": "Son Of A",
            };
            // console.log(d.children);
            d.children.push(newChild);
            // console.log(d.children);
            update(d);
          }
        } else {
          var newChild = {
            "name": childname,
            "parent": "Son Of A",
          };
          console.log("collapsed case");
          d.children = d._children;
          d.children.push(newChild);
          // console.log(d.children);
          update(d);


        }


        $("#child-info").hide();
      });
    });
  }

  // Toggle children on click.
  function click(d) {

    if (d.id !== 1) {

      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else {
        d.children = d._children;
        d._children = null;
      }
      update(d);
    }


    $(".addLeftChild, .addRightChild").hide();
    if (d.id === 1) {
      $(".rightparent").children(".addRightChild").show();
      $(this).children(".addLeftChild").show();
    } else {
      $(this).children(".addLeftChild").show();

    }


    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links
    while (d.parent) {
      d3.selectAll("#leftnode" + d.id).style("fill", "#F7CA18"); //color the node
      if (d.parent != "null")
        d3.selectAll("#leftlink" + d.parent.id + "-" + d.id).style("stroke", "F7CA18"); //color the path
      d = d.parent;
    }

  }
}
body {
  margin: 0;
  padding: 0;
}
#child-info {
  width: 100px;
  height: 50px;
  height: auto;
  position: fixed;
  padding: 10px;
  display: none;
  left: 40%;
  z-index: 100;
}
.asset-title {
  padding: 15px;
  float: left;
}
.node {
  cursor: pointer;
}
.node text {
  font: 12px sans-serif;
}
.link {
  fill: none;
  stroke: #85e0e0;
  stroke-width: 2px;
}
.rightparent>rect {
  display: none;
}
.leftparent>rect {
  fill: #f1f1f1;
  stroke: #ccc;
  stroke-width: 2;
}
.leftparent .left-chevron {
  display: none;
}
.leftparent image {
  display: none;
}
.addLeftChild,
.addRightChild {
  display: none;
}
.left-chevron,
.right-chevron {
  display: none;
}
.collapsed .left-chevron,
.collapsed .right-chevron {
  display: block;
}
<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 id="child-info" style="display:none">
  <input type="text" id="child-text" placeholder="child name">
  <button id="btn-add-child">add</button>
</div>
<div class="doubletree-container">
</div>


<script type="text/javascript">
  $(document).ready(function() {
    $(".doubletree-container").makeDoubleTree();
  });
</script>

你需要对Y做同样的事情。但是如果你想让它完全处于中心位置,那么只需取走textHeight / 2

,而不是取走textLength / 2。