score:6

Accepted answer

There are two errors in the code you posted in your question:

  1. When modifying the link force in your code you are no longer providing the links to the force since you are not providing links as an argument. It has to be d3.forceLink(links).

  2. The function provided to .id() is the accessor function to the nodes' ids. In your case the id of a node is defined by its property name. Thus, you need to change the accessor to .id(function(d) { return d.name; }).

Change the definition of the link force to the following to make it work:

.force("link", d3.forceLink(links).id(function(d) {
  return d.name;
}))

Have a look at the following snippet for a working demo:

nodes = [{
  name: "test",
  type: "test"
}, {
  name: "test2",
  type: "test2"
}];
links = [{
  source: "test",
  target: "test2"
}];

var width = 500,
  height = 500;

var svg = d3.select("svg"),
  color = "blue";

var simulation = d3.forceSimulation(nodes)
  .force("charge", d3.forceManyBody().strength(-1000))
  .force("link", d3.forceLink(links).id(function(d) {
    return d.name;
  }))
  .force("x", d3.forceX())
  .force("y", d3.forceY());

var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"),
  link = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".link"),
  node = g.append("g").attr("stroke", "#fff").attr("stroke-width", 1.5).selectAll(".node");

forceGraphUpdate = function() {

  node = node.data(nodes);
  node.exit().transition().attr("r", 0)
    .remove();

  node = node.enter().append("circle")
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .attr("fill", function(d) {
      return color;
    })
    .call(function(node) {
      node.transition().attr("r", 8)
    })
    .merge(node);

  link = link.data(links);

  link.exit().transition()
    .attr("stroke-opacity", 0)
    .attrTween("x1", function(d) {
      return function() {
        return d.source.x;
      };
    })
    .attrTween("x2", function(d) {
      return function() {
        return d.target.x;
      };
    })
    .attrTween("y1", function(d) {
      return function() {
        return d.source.y;
      };
    })
    .attrTween("y2", function(d) {
      return function() {
        return d.target.y;
      };
    })
    .remove();

  link = link.enter().append("line")
    .call(function(link) {
      link.transition().attr("stroke-opacity", 1);
    })
    .merge(link);

  simulation
      .nodes(nodes)
      .on("tick", ticked);
 
}

function ticked() {
  node.attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });

  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;
    });
}

function dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}

forceGraphUpdate();

function addNode() {
  nodes.push({
    name: "test",
    type: "testing"
  });
  forceGraphUpdate();
}
addNode();
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="500" height="500"></svg>


Related Query