4

How to append the arrow marker dynamically in force layout of d3.js as in below image enter image description here

  d3.select('svg.svgparentTag').selectAll("marker").data(["BLACK", "BLUE"]).enter().append("svg:marker")
        .attr("id", String)
        .attr("viewBox", "0 -5 10 10")
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("class", function(d) { return "marker_only " + d.type; })
        .attr("d", "M0,-5L10,0L0,5"); //marker 

 var path = d3.select('.pitch').selectAll("path")
            .data(force.links())
            .enter().append('g').classed('g_path', true).append("svg:path").attr("class", "link");


 path.filter(function(d) {
            return d.arrow == true;
        }).attr("marker-mid", function(d) { return "url(#BLUE)"}).attr("stroke-linecap", "round");
ferozcoder
  • 454
  • 5
  • 18

1 Answers1

7

There's an example of this at http://bl.ocks.org/mbostock/1153292

What you need to do is create svg:defs and place svg:marker elements in the defs. Then attach the markers using one of the attributes marker-end, marker-mid or marker-start

// Per-type markers, as they don't inherit styles.
svg.append("defs").append("marker")
    .attr("id", "marker")
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 15)
    .attr("refY", -1.5)
    .attr("markerWidth", 6)
    .attr("markerHeight", 6)
    .attr("orient", "auto")
  .append("path")
    .attr("d", "M0,-5L10,0L0,5");

var path = svg.append("g").selectAll("path")
    .data(force.links())
  .enter().append("path")
    .attr("marker-end", "url(#marker)"; });

In case you need a marker-mid for straight lines, you may run into issues with the marker not drawing in the middle if the path doesn't have a node in the middle. Have a look at the answer from talkol for how to solve this https://stackoverflow.com/a/15758791/1617269

So adapted from the accepted answer in that question, you could have a generator function like this which generates lines with a node in the middle or arcs based on d.type. Check it out on jsfiddle

function tick() {
  path.attr("d", function(d) {
    var dx = d.target.x - d.source.x,
        dy = d.target.y - d.source.y,
        dr = Math.sqrt(dx * dx + dy * dy)/4,
        mLx = d.source.x + dx/2,
        mLy = d.source.y + dy/2,
        mAx = d.source.x + dx,
        mAy = d.source.y + dy;
      if (d.type === "line") {
       return [
          "M",d.source.x,d.source.y,
           "L",mLx,mLy,
           "L",d.target.x,d.target.y,
           "Z"
          ].join(" ");
      }
    return [
      "M",d.source.x,d.source.y,
      "A",dr,dr,0,0,1,mAx,mAy,
      "A",dr,dr,0,0,1,d.target.x,d.target.y
    ].join(" ");
  });
Community
  • 1
  • 1
cyon
  • 9,340
  • 4
  • 22
  • 26
  • @fekkyDEV Can you update your question with your code? – cyon Mar 24 '15 at 10:08
  • As in Image I'll get both curve as well as line links. In curve links its working fine but not in straight line. – ferozcoder Mar 24 '15 at 10:10
  • @fekkyDEV Yeah I think marker-mid can be quite buggy in that I think it may need the path to have a node in the middle or else it won't draw. I think you need to change the straight line generator to produce a node in the middle. I'll update my answer with a link to another stackoverflow post that solves this. – cyon Mar 24 '15 at 10:26
  • In this post http://stackoverflow.com/a/15758791/1617269 they mentioned to use ploy lines but how can i bend it as curve ? – ferozcoder Mar 25 '15 at 04:22
  • @fekkyDEV see my edits for how you could do the generation of line paths which have a node in the middle. That seems to work on chrome v41 – cyon Mar 25 '15 at 10:12