箭头不会触及树形布局中d3.js中的节点

时间:2017-01-09 16:11:12

标签: d3.js

我正在使用超过500个节点的d3树(一个根和第二级500/1000个子节点)。箭头看起来最好50个子节点,但比左侧和右侧节点更多,节点和路径顶部显示的箭头对角线与节点边缘相交。 如何解决这个问题,箭头应该触及路径与节点相交的节点?使用的节点是矩形,如本问题Arrows are not touching to nodes in d3.js

中给出的

1 个答案:

答案 0 :(得分:1)

好的,好的,这是你的解决方案。这就是我称之为“退避”的方法。这与我在this question中使用的方法相同。它的工作原理是拟合路径,然后减去方形加上标记头的“半径”。

首先要做的事情,你只需要添加一次“标记”def,它就可以在所有的行上使用。其次,我改变了自上而下的路径,你让他们画出了我所有倒退的东西 - 从孩子到父母。这需要额外旋转头部。

以下是代码:

var width = 500;
var height = 500;
var nodeWidth = 40;
var nodeHeight = 40;
var circleRadius = 5;
var diagramLayout;
var graphData = {
  "nodes": [{
    "uid": "Term20",
    "name": "Term20",
    "image": "images/Term.png"
  }, {
    "uid": "glossforArrow",
    "name": "glossforArrow",
    "image": "images/Glossary.png"
  }, {
    "uid": "Term43",
    "name": "Term43",
    "image": "images/Term.png"
  }, {
    "uid": "Term1",
    "name": "Term43",
    "image": "images/Term.png"
  }, {
    "uid": "Term2",
    "name": "Term43",
    "image": "images/Term.png"
  }],
  "links": [{
    "source": "glossforArrow",
    "target": "Term20",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term43",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term1",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term3",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term4",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term5",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term6",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term7",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term8",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term9",
    "direction": "output",
    "label": "Owned Terms"
  }, {
    "source": "glossforArrow",
    "target": "Term2",
    "direction": "output",
    "label": "Owned Terms"
  }]
};

treeInitialize(graphData)


function treeInitialize(graphData) {

  diagramLayout = d3.select("#diagramLayout")
    .attr("id", "diagramLayout") //set id
    .attr("width", width) //set width
    .attr("height", height) //set height
    .append("g")
    .attr("transform", "translate(" + 20 + "," + 20 + ")")

  markerRefx = 40;

  var data2 = graphData.links.filter(function(l) {
    if (l.target == undefined && l.source == undefined) {
      return false;
    } else {
      return true;
    }
  });
  data2.push(JSON.parse('{"target":"glossforArrow","source":""}'))

  var treeData = d3.stratify().id(function(d) {
    return d.target;
  }).parentId(function(d) {
    return d.source;
  })(data2)

  nodes = d3.hierarchy(treeData, function(d) {
    return d.children;
  });

  var levelWidth = [1];
  var childCount = function(level, n) {

    if (n.children && n.children.length > 0) {
      if (levelWidth.length <= level + 1) levelWidth.push(0);

      levelWidth[level + 1] += n.children.length;
      n.children.forEach(function(d) {
        childCount(level + 1, d);
      });
    }
  };
  childCount(0, nodes);
  newHeight = d3.max(levelWidth) * 100;
  var tree = d3.tree().size([height, width])

  tree.size([newHeight, height / 2]);

  tree.separation(function(a, b) {
    return a.parent == b.parent ? 50 : 100;
  });
  nodes = tree(nodes);
  treeLayout(nodes);

  function treeLayout(nodes) {

    var node = diagramLayout.selectAll(".node");
    node = node.data(nodes.descendants());

    var link = diagramLayout.selectAll(".link")
      .data(nodes.descendants().slice(1))
      .enter().append("path")
      .attr("class", "link")
      .attr("fill", "none")
      .attr("stroke", "#000")
      .attr("stroke-width", "1px")
      .attr("stroke-opacity", "0.3")
      .attr("d", function(d) {
        return connector(d.parent, d);
      })

    //nodes.descendants().slice(1).forEach(function(d) { 

    var mark = diagramLayout.append("svg:defs").selectAll("marker") //
      .data(["start"]) // Different link/path types can be defined here
      .enter().append("svg:marker") // This section adds in the arrows
      .attr("id", String)
      .attr("viewBox", "0 -5 10 10")
      .attr("refX", 0)
      .attr("refY", 0)
      .attr("markerWidth", 5)
      .attr("markerHeight", 5)
      .attr("orient", "auto")
      .attr("stroke", "#000")
      .attr("fill", "#000")
      .append("svg:path")
      .attr("d", "M0,-5L10,0L0,5")
      .style("stroke-width", "0.3px")
      //.attr("transform","rotate(180,5, 0)");

    //	});	

    link.attr("marker-end", "url(#start)")
      .each(function(d, i, j) {

        var self = d3.select(this),
          t = this.getTotalLength(),
          p = this.getPointAtLength(t - 25);

        self.attr("d", connector(d.parent, p));
      })



    var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .attr("height", nodeHeight)
      .attr("width", nodeWidth)
    nodeEnter.attr("transform", function(d) {
      return "translate(" + project(d.x, d.y) + ")";
    })


    var nodeIcon = nodeEnter.append("rect")
      .attr("class", "rect")
      .attr("x", -20)
      .attr("y", -20)
      .attr("rx", 10)
      .attr("width", 40)
      .attr("height", 40)
      .attr("stroke-width", function(d) {
        return Math.sqrt(2);
      })
      .attr("stroke-opacity", "0.3")
      .attr("stroke", "#000")
      .attr("fill", "none")


    //wrap(nodeText, 8)	
  }

}

function connector(from, to) {
  return "M" + project(from.x, from.y) + "C" + project(from.x, (from.y + to.y) / 2) + " " + project(to.x, (from.y + to.y) / 2) + " " + project(to.x, to.y);
}

function project(x, y) {

  return [x, y];
}
.node {
  stroke: #fff;
  stroke-width: 1.5px;
}
.link {
  stroke: #000;
  stroke-opacity: .6;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="mainScreen" style="height:100%;width:100%;position:absolute;">
  <svg id="diagramLayout" style="height:100%;width:100%;position:absolute;">
  </svg>

</div>