score:2

Accepted answer

You should not use cx and cy in the ticked function, since you're dealing with <path>s, not <circle>s. You should use translate instead.

Therefore, it has to be:

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

Here is your code with that change (I'm using fake data here):

var width = 600;
var height = 400;
var nominal_stroke = 4;

// Simulation
var simulation = d3.forceSimulation()
  .force("link", d3.forceLink().id(function(d) {
    return d.id;
  }))
  .force("charge", d3.forceManyBody().strength(-400))
  .force("center", d3.forceCenter(width / 2, height / 2));

// Create SVG window
var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);
var g = svg.append("g");
svg.style("cursor", "move");

graph = {
  nodes: [{
    id: 1,
    shape: "rect"
  }, {
    id: 2,
    shape: "circle"
  }, {
    id: 3,
    shape: "rect"
  }, {
    id: 4,
    shape: "rect"
  }, {
    id: 5,
    shape: "circle"
  }, {
    id: 6,
    shape: "circle"
  }, {
    id: 7,
    shape: "circle"
  }],
  links: [{
    source: 1,
    target: 2
  }, {
    source: 1,
    target: 3
  }, {
    source: 1,
    target: 4
  }, {
    source: 1,
    target: 5
  }, {
    source: 3,
    target: 6
  }, {
    source: 3,
    target: 7
  }]
}

// Draw links
var link = g.selectAll(".link")
  .data(graph.links)
  .enter().append("line")
  .attr("class", "link")
  .style("stroke-width", nominal_stroke)
  .style("stroke", "#999")
  .style("stroke-opacity", 0.6);

// Draw nodes
var node = g.selectAll(".node")
  .data(graph.nodes)
  .enter().append("g")
  .attr("class", "node")
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

// Setup node properties
var circle = node.append("path")
  .attr("d", d3.symbol()
    .type(function(d) {
      if (d.shape == "rect") {
        return d3.symbolSquare;
      } else if (d.shape == "circle") {
        return d3.symbolCircle;
      }
    })
    .size(400))
  .style("stroke", "#999")
  .style("stroke-opacity", 0.6)
  .style("fill", function(d) {
    return "blue"
  });

// Add titles
node.append("title")
  .text(function(d) {
    return d.id;
  });

// Start Simulation
simulation
  .nodes(graph.nodes)
  .on("tick", ticked);

simulation.force("link")
  .links(graph.links);

// Refresh page
function ticked() {
  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 + ")";
  });
}

// Zoom handler
svg.call(d3.zoom()
  .scaleExtent([1 / 2, 8])
  .on("zoom", zoomed));

function zoomed() {
  g.attr("transform", d3.event.transform);
}


// Functions

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 = d.x;
  d.fy = d.y;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

PS: Your zoom function is not working, which is a different problem. I also fixed it.


Related Query

More Query from same tag