Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to append the arrow marker dynamically in force layout d3.js

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");
like image 271
ferozcoder Avatar asked Mar 16 '23 15:03

ferozcoder


1 Answers

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(" ");
  });
like image 157
cyon Avatar answered Apr 20 '23 00:04

cyon