0

I'm trying to combine two different force directed graphs.

One is dynamic force directed graph (code from here) where I can set the thickness of the lines between nodes (and the data is defined inline); the other is collapsible force directed graph (code from a SO answer here, that uses non-tree data) where I can click the nodes to hide the children (and the data is defined from a JSON file).

I thought this should be clear enough, but I keep having problems. The JS console said that the propertyforce is undefined even though I have set its variable.

Here is the Plunker: http://plnkr.co/edit/MtOB9PGnXlNwlNj6P5NY?p=preview

And here is the collapsible graph part (full code is in Plunker)

// Combined script //
var root,
    force = d3.layout.force()
    .size([width, height])
    .on("tick", tick);


var link = svg.selectAll(".link"),
    node = svg.selectAll(".node");

    d3.json("data.json", function(json) {
      root = json;
      //Give nodes ids and initialize variables
      for(var i=0; i<root.nodes.length; i++) {
        var node = root.nodes[i];
        node.id = i;
        node.collapsing = 0;
        node.collapsed = false;
      }
      //Give links ids and initialize variables
      for(var i=0; i<root.links.length; i++) {
        var link = root.links[i];
        link.source = root.nodes[link.source];
        link.target = root.nodes[link.target];
        link.id = i;
      }

      update();
    });

    function update() {
      //Keep only the visible nodes
      var nodes = root.nodes.filter(function(d) {
        return d.collapsing == 0;
      });
      var links = root.links;
      //Keep only the visible links
      links = root.links.filter(function(d) {
        return d.source.collapsing == 0 && d.target.collapsing == 0;
      });

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

      // Update the links…
      link = link.data(links, function(d) { return d.id; });

      // Exit any old links.
      link.exit().remove();

      // Enter any new links.
      link.enter().insert("line", ".node")
          .attr("class", "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; })
          .attr("marker-end", "url(#arrow)");

      // Update the nodes…
      node = node.data(nodes, function(d){ return d.id; }).style("fill", color);

      // Exit any old nodes.
      node.exit().remove();

      // Enter any new nodes.
      node.enter().append("circle")
          .attr("class", "node")
          .attr("cx", function(d) { return d.x; })
          .attr("cy", function(d) { return d.y; })
          .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
          .style("fill", color)
          .on("click", click)
          .call(force.drag);
    }

    function tick() {
      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("cx", function(d) { return d.x; })
          .attr("cy", function(d) { return d.y; });
    }

    // Toggle children on click.
    function click(d) {
      if (!d3.event.defaultPrevented) {
        //check if link is from this node, and if so, collapse
        root.links.forEach(function(l) {
          if(l.source.id == d.id) {
            if(d.collapsed){
              l.target.collapsing--;
            } else {
              l.target.collapsing++;
            }
          }
        });
        d.collapsed = !d.collapsed;
      }
      update();
    }
// Combined end //

Without combining the two codes, it's working fine, as shown in this fiddle: https://jsfiddle.net/Lrrepn0c/

Any ideas?

Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
deathlock
  • 2,756
  • 5
  • 27
  • 48
  • You're using D3 v4. There is no `d3.layout.force` in v4. Also, stack snippet is for **running code** only. I just edited your question. – Gerardo Furtado Nov 09 '17 at 11:46
  • Hmm. Downgrading to D3 v4 results in "`forceLink` is not a function", so I guess it's a v4 thing? Meanwhile trying to find a substitute for `d3.layout.force` (is it `d3.forceSimulation`?) results in "`d3.forceSimulation(...).size` is not a function". http://plnkr.co/edit/k9J5njiAgFqe0epc1GIP?p=preview I'm kind of confused. Is it disabled too in D3 v4? – deathlock Nov 09 '17 at 12:25
  • 1
    Please have a look at the changelog. The documentation is very clear: https://github.com/d3/d3/blob/master/CHANGES.md#forces-d3-force – Gerardo Furtado Nov 09 '17 at 12:28

0 Answers0