score:1

Accepted answer

From the docs (bolding mine):

simulation.tick()

Increments the current alpha by (alphaTarget - alpha) × alphaDecay; then invokes each registered force, passing the new alpha; then decrements each node’s velocity by velocity × velocityDecay; lastly increments each node’s position by velocity.

This method does not dispatch events; events are only dispatched by the internal timer when the simulation is started automatically upon creation or by calling simulation.restart. The natural number of ticks when the simulation is started is ⌈log(alphaMin) / log(1 - alphaDecay)⌉; by default, this is 300.

This method can be used in conjunction with simulation.stop to compute a static force layout. For large graphs, static layouts should be computed in a web worker to avoid freezing the user interface.

Since it doesn't dispatch events your tick function is never called or used. Instead, just replace the line and set your path up once:

<!DOCTYPE html>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

  var n = 100,
    nodes = d3.range(n).map(function(i) {
      return {
        index: i
      };
    }),
    links = d3.range(n).map(function(i) {
      return {
        source: i,
        target: (i + 3) % n
      };
    });

  var simulation = d3.forceSimulation(nodes)
    .force("charge", d3.forceManyBody().strength(-80))
    .force("link", d3.forceLink(links).distance(20).strength(1).iterations(10))
    .force("x", d3.forceX())
    .force("y", d3.forceY())
    .stop();

  var loading = svg.append("text")
    .attr("dy", "0.35em")
    .attr("text-anchor", "middle")
    .attr("font-family", "sans-serif")
    .attr("font-size", 10)
    .text("Simulating. One moment please…");

  // Use a timeout to allow the rest of the page to load first.
  d3.timeout(function() {
    loading.remove();

    // See https://github.com/d3/d3-force/blob/master/README.md#simulation_tick
    for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
      simulation.tick();
    }

    g.append("g")
      .attr("stroke", "#000")
      .attr("stroke-width", 1.5)
      .selectAll("line")
      .data(links)
      .enter().append("path")
      .attr("d", function(d) {
        var x1 = d.source.x,
          y1 = d.source.y,
          x2 = d.target.x,
          y2 = d.target.y,
          dx = x2 - x1,
          dy = y2 - y1,
          dr = Math.sqrt(dx * dx + dy * dy),

          // z uzla do ineho uzla
          drx = dr,
          dry = dr,
          xRotation = 0,
          largeArc = 0,
          sweep = 1;

        //do sameho seba
        if (x1 === x2 && y1 === y2) {
          xRotation = -45;
          largeArc = 1;
          drx = 30;
          dry = 30;
          x2 = x2 + 1;
          y2 = y2 + 1;
        }

        return "M" + x1 + "," + y1 + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + x2 + "," + y2;
      });

    g.append("g")
      .attr("stroke", "#fff")
      .attr("stroke-width", 1.5)
      .selectAll("circle")
      .data(nodes)
      .enter().append("circle")
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      })
      .attr("r", 4.5);


  });
</script>

Response to comments:

To append a circle and text as a "node", I would create a g, position that and then put the circle and text in it:

  var g = node
    .selectAll(".node")
    .data(nodes)
    .enter()
    .append("g")
    .attr("transform", function(d){
      return "translate(" + d.x + "," + d.y + ")";
    });

  g.append("circle")
    .attr("class", "node")
    .attr("stroke", "#fff")
    .attr("r", 28);

  g.append("text")
    .text("test");

Related Query

More Query from same tag