d93.js v4. Переход в дурацкое соединение в примере с разборным деревом.

Если вы поиграете со сворачиваемым деревом ниже, вы увидите, что когда вы доберетесь до конца дерева, развернете и свернете узлы, строки будут делать какие-то дурацкие вещи, и я не совсем уверен, что движет поведением или переписывает извведите описание ссылки здесь полностью вне базы. Я отказался от плоской структуры данных и использовал стратификацию, чтобы преобразовать ее в древовидную структуру. Единственная проблема на данный момент - это переходы строк ... есть мысли?

var data = [{
    "name": "Hazer 5000",
    "parent": "CFO",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/stephen.jpg"
  }, {
    "name": "Employee 1",
    "parent": "Hazer 5000",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/cory.jpg"
  }, {
    "name": "Analytics Area",
    "parent": "Hazer 5000",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/matt.jpg"
  }, {
    "name": "Employee 2",
    "parent": "Hazer 5000",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/XinheZhang.jpg"
  }, {
    "name": "Employee 3",
    "parent": "Hazer 5000",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/craig.jpg"
  }, {
    "name": "Employee 4",
    "parent": "Hazer 5000",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/youri.jpg"
  }, {
    "name": "Intern 1",
    "parent": "Analytics Area",
    "img": ""
  }, {
    "name": "Inter 2",
    "parent": "Analytics Area",
    "img": ""
  }, {
    "name": "CFO",
    "parent": null,
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Brett.jpg"
  }, {
    "name": "CPA",
    "parent": "CFO",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Wes.jpg"
  }, {
    "name": "Matt's wife",
    "parent": "CPA",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Amy_R.jpg"
  }, {
    "name": "Employee 5",
    "parent": "CPA",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/DavidBriley.jpg"
  }, {
    "name": "Employee 6",
    "parent": "CPA",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/BrittanyAllred_.jpg"
  }, {
    "name": "Employee 7",
    "parent": "CPA",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Shea.jpg"
  }, {
    "name": "Employee 8",
    "parent": "Matt's wife",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Mindy.jpg"
  }, {
    "name": "Employee 9",
    "parent": "Matt's wife",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Jessica_Stacy.jpg"
  }, {
    "name": "Employee 10",
    "parent": "Matt's wife",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/FraleaneHudson.jpg"
  },{
    "name": "Employee 11",
    "parent": "Employee 9",
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/MeganPierce_.jpg"
  },{
    "name": "Intern 3",
    "parent": "Employee 8",
    "img": ""
  }, {
    "name": "Intern 4",
    "parent": "Employee 8",
    "img": ""
  }

];

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

var i = 0,
    duration = 750,
    root;

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

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


var stratify = d3.stratify()
  .id(function(d) {
    return d.name;//This position
  })
  .parentId(function(d) {
    return d.parent; //What position this position reports to
  });

var root = stratify(data);

root.each(function(d) {
  
    d.name = d.id; //transferring name to a name variable
    d.id = i; //Assigning numerical Ids
    i++;
  
  });

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

  function collapse(d) {
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
  }

  root.children.forEach(collapse);
  update(root);


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

function update(source) {

  // Compute the new tree layout.
  var nodes = tree(root).descendants(),
      links = nodes.slice(1);

  // 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("circle")
      .attr("r", 1e-6)
      .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeEnter.append("text")
      .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
      .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);

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

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

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


  // Update the links…
  var link = svg.selectAll("path.link")
      .data(links);
  
  // Transition links to their new position.
  link.transition()
      .duration(duration)
      .attr("d", connector);

  // Enter any new links at the parent's previous position.
  var linkEnter = link.enter().insert("path", "g")
                        .attr("class", "link")
                        .attr("d", function(d) {
        var o = {x: source.x0, y: source.y0, parent:{x: source.x0, y: source.y0}};
        return connector(o);
      });

  // Transition links to their new position.
  link.merge(linkEnter).transition()
      .duration(duration)
      .attr("d", connector);

  // 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, parent:{x: source.x, y: source.y}};
        return connector(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);
}

function connector(d) {
  return "M" + d.y + "," + d.x +
    "C" + (d.y + d.parent.y) / 2 + "," + d.x +
    " " + (d.y + d.parent.y) / 2 + "," + d.parent.x +
    " " + d.parent.y + "," + d.parent.x;
}
.node {
  cursor: pointer;
}

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

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

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
<script src="https://d3js.org/d3.v4.min.js"></script>

Ответы на вопрос(1)

Ваш ответ на вопрос