3

I am new to D3 and have been trying to make my arrowhead's color the same as my arrow's color in a D3 graph referring to code solution given here.

Its a directed graph and the json file is responsible in linking various nodes. I am trying to ensure that whatever color my link is, my arrowhead gets the same color but that doesn't seem to work. Here is my js code :

var width = 960,
height = 500;

// initialization
var svg = d3.select("div").append("svg")
    .attr("width", width)
    .attr("height", height);

var force = d3.layout.force()
    .gravity(0) // atom's cohesiveness / elasticity of imgs :)
    .distance(150) // how far the lines ---> arrows :)
    .charge(-50) // meta state transition excitement
    .linkDistance(140)
    //.friction(0.55) // similar to charge for quick reset :)
    .size([width, height]); // degree of freedom to the canvas

// exception handling
d3.json("/assets/javascripts/position.json", function(error, json) {
     if (error) throw error;
          // Restart the force layout
    force
      .nodes(json.nodes)
      .links(json.links)
      .start();

      var pipeline = document.getElementById("pipeline").innerHTML;

      // Build the link
      var link = svg.selectAll(".links")
      .data(json.links)
      .enter().append("line")
      .attr("class", "lol")
      .style("stroke-width", "2")
      .attr("stroke", function(d){
        return linkColor(d.colorCode);})
      .each(function(d) {
        var color = linkColor(d.colorCode);
        d3.select(this).attr("marker-end", marker(color));
      });

      function marker(color) {
        svg.append("svg:marker")
          .attr("id", color.replace("#", ""))
          .attr("viewBox", "0 -5 10 10")
          .attr("refX", 15)
          .attr("refY", 0)
          .attr("markerWidth", 9)
          .attr("markerHeight", 9)
          .attr("orient", "auto")
          .attr("markerUnits", "userSpaceOnUse")
          .append("svg:path")
          .attr("d", "M0,-5L10,0L0,5")
          .style("fill", linkColor(color));

        return "url(" + linkColor(color) + ")";
      };
      var node = svg.selectAll(".nodes")
      .data(json.nodes)
      .enter().append("g")
      .attr("class", "node")
      .call(force.drag);

      node.append("svg:image")
                  .attr("xlink:href", "") // update the node with the image
                  .attr("x", function(d) { return -5;}) // how far is the image from the link??
                  .attr("y", function(d) { return -25;}) // --- same ---
                  .attr("height", 55) // size
                  .attr("width", 55);

      // Define the div for the tooltip
      var div = d3.select("body").append("pre")
      .attr("class", "tooltip")
      .style("opacity", 0);

      node.append("text")
        .attr("class", "labelText")
        .attr("x", function(d) { return -5;})
        .attr("y", function(d) { return 48;})
        .text(function(d) { return d.label });

      force.on("tick", function() {
        link.attr("x1", function(d) { return d.source.x; })
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });

        node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        force.stop();
      });

      function linkColor(linkCode) {
        switch (linkCode)
        {
          case 'ctoc':
            return '#0000FF';//blue
            break;
          case 'ctof':
            return '#00afaa';//green
            break;
          case 'ftoc':
            return '#fab800';//yellow
            break;
          case 'ftof':
            return '#7F007F';//purple
            break;
          default:
            return '#0950D0';//generic blue
            break;
        }
      }
});

where position.json is:

    {
  "nodes": [
    {"x": 100, "y": 100},
    {"x": 250, "y": 100},
    {"x": 400, "y": 100},
    {"x": 550, "y": 200},
    {"x": 700, "y": 200},
    {"x": 100, "y": 300},
    {"x": 250, "y": 300},
    {"x": 400, "y": 300}
  ],
  "links": [
    {"source":  0, "target":  1, "colorCode" : "ctof"},
    {"source":  1, "target":  2, "colorCode" : "ftoc"},
    {"source":  2, "target":  3, "colorCode" : "ctof"},
    {"source":  3, "target":  4, "colorCode" : "ftoc"},
    {"source":  5, "target":  6, "colorCode" : "ctof"},
    {"source":  6, "target":  7, "colorCode" : "ftoc"},
    {"source":  7, "target":  3, "colorCode" : "ctof"}
  ]
}

But I dont see any output on my screen. Can someone please help me identify where I am going wrong?

Aakanksha Choudhary
  • 515
  • 2
  • 5
  • 19
  • 1
    Can you provide a functioning example, like on jsfiddle or codepen? It's difficult to determine what working and not working look like with just the d3 code alone. – Anthony Jul 11 '18 at 20:12
  • Yeah sure. Please give me some time to edit – Aakanksha Choudhary Jul 11 '18 at 20:16
  • Hey @Anthony, I couldn't add the json file as a variable in the jsFiddle. Because everything gets out of the json file import function and then nothing worked. So I have pasted almost my entire code again. Please let me know if there is a way to upload a json somehow, I would do it. – Aakanksha Choudhary Jul 11 '18 at 20:30

1 Answers1

6

Minor change:

In the marker function, the passed argument (color) is already the corresponding marker's ID which means you don't need to pass it to the linkColor function. Here's the changed marker function:

function marker(color) {
    svg.append("svg:marker")
      ...
      .attr("refX", 10)
      ...
      .style("fill", color);

    return "url(" + color + ")";
  };

Here's a snippet using the above code and to answer your comment on how to add a JSON, you could just add it as a variable (as I've done it here which makes it easier to debug as well).

var width = 960,
height = 500;

// initialization
var svg = d3.select("div").append("svg")
    .attr("width", width)
    .attr("height", height);

var force = d3.layout.force()
    .gravity(0) // atom's cohesiveness / elasticity of imgs :)
    .distance(150) // how far the lines ---> arrows :)
    .charge(-50) // meta state transition excitement
    .linkDistance(140)
    //.friction(0.55) // similar to charge for quick reset :)
    .size([width, height]); // degree of freedom to the canvas

// exception handling

var json =     {
  "nodes": [
    {"x": 100, "y": 100},
    {"x": 250, "y": 100},
    {"x": 400, "y": 100},
    {"x": 550, "y": 200},
    {"x": 700, "y": 200},
    {"x": 100, "y": 300},
    {"x": 250, "y": 300},
    {"x": 400, "y": 300}
  ],
  "links": [
    {"source":  0, "target":  1, "colorCode" : "ctof"},
    {"source":  1, "target":  2, "colorCode" : "ftoc"},
    {"source":  2, "target":  3, "colorCode" : "ctof"},
    {"source":  3, "target":  4, "colorCode" : "ftoc"},
    {"source":  5, "target":  6, "colorCode" : "ctof"},
    {"source":  6, "target":  7, "colorCode" : "ftoc"},
    {"source":  7, "target":  3, "colorCode" : "ctof"}
  ]
};

    force
      .nodes(json.nodes)
      .links(json.links)
      .start();

      // Build the link
      var link = svg.selectAll(".links")
      .data(json.links)
      .enter().append("line")
      .attr("class", "lol")
      .style("stroke-width", "2")
      .attr("stroke", function(d){
        return linkColor(d.colorCode);})
      .each(function(d) {
        var color = linkColor(d.colorCode);
        d3.select(this).attr("marker-end", marker(color));
      });

      function marker(color) {
        svg.append("svg:marker")
          .attr("id", color.replace("#", ""))
          .attr("viewBox", "0 -5 10 10")
          .attr("refX", 10)
          .attr("refY", 0)
          .attr("markerWidth", 9)
          .attr("markerHeight", 9)
          .attr("orient", "auto")
          .attr("markerUnits", "userSpaceOnUse")
          .append("svg:path")
          .attr("d", "M0,-5L10,0L0,5")
          .style("fill", color);

        return "url(" + color + ")";
      };
      var node = svg.selectAll(".nodes")
      .data(json.nodes)
      .enter().append("g")
      .attr("class", "node")
      .call(force.drag);

      node.append("svg:image")
                  .attr("xlink:href", "") // update the node with the image
                  .attr("x", function(d) { return -5;}) // how far is the image from the link??
                  .attr("y", function(d) { return -25;}) // --- same ---
                  .attr("height", 55) // size
                  .attr("width", 55);

      // Define the div for the tooltip
      var div = d3.select("body").append("pre")
      .attr("class", "tooltip")
      .style("opacity", 0);

      node.append("text")
        .attr("class", "labelText")
        .attr("x", function(d) { return -5;})
        .attr("y", function(d) { return 48;})
        .text(function(d) { return d.label });

      force.on("tick", function() {
        link.attr("x1", function(d) { return d.source.x; })
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });

        node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        force.stop();
      });

      function linkColor(linkCode) {
        switch (linkCode)
        {
          case 'ctoc':
            return '#0000FF';//blue
            break;
          case 'ctof':
            return '#00afaa';//green
            break;
          case 'ftoc':
            return '#fab800';//yellow
            break;
          case 'ftof':
            return '#7F007F';//purple
            break;
          default:
            return '#0950D0';//generic blue
            break;
        }
      }
  <head>
    <link rel="stylesheet" href="style.css">
    <script src="https://d3js.org/d3.v3.min.js"></script>
  </head>

  <body>
      <div></div>
      
          <script src="script.js"></script>

  </body>

I've made another change (changed refY to 10 based on the arrow head length). Play around with it to see the difference. Hope this helps.

Shashank
  • 5,570
  • 1
  • 11
  • 17
  • Hey @Shashank, I had a followup question. Would you mind checking this one too? https://stackoverflow.com/questions/51314901/ Thanks a lot again! – Aakanksha Choudhary Jul 12 '18 at 21:47
  • I just got online and saw your question and it seems like you've got answers to that. And yes, glad I could help. I'll keep a watch if you come up with any other questions. Will be happy to help. Happy coding! – Shashank Jul 13 '18 at 13:21