0

I am using d3 tree with more than 500 nodes(one root and 500/1000 child nodes to it in 2nd level). Arrows looks perfect up-to 50 child nodes but more than that on left and right side nodes, arrows shown at top of node and path are intersects node edge diagonally. how to resolve this issue in such way that arrow should touch node where path intersect node?Nodes used are rectangular as given in this question Arrows are not touching to nodes in d3.js

Community
  • 1
  • 1

1 Answers1

2

All right, all right here's your solution. This is what I call the "back-off" approach. It's the same approach I used in this question. It works by fitting the path and then subtracting off of it the "radius" of your square plus marker head.

Couple things first, you only need to append the "marker" def once, it can be used on all the lines. Second, I switched the paths to draw top down, you had them drawing what I would all backwards - from child to parent. This requires additional rotation of the head.

Here's the code:

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>
Community
  • 1
  • 1
Mark
  • 106,305
  • 20
  • 172
  • 230