Josh Flori
Josh Flori

Reputation: 41

Delay start of force simulation

I would like to delay the start of a force simulation by about 2 seconds. How do I do this? I feel like you should be able to say "if tick < n, don't start" or something like that... but I do not understand how or even if this is possible. I have reviewed the documentation but don't know.

Here is the code I am working with if that matters.

          var simulation = d3.forceSimulation(data)
          .force('charge', d3.forceManyBody().strength(33))
          .force('x', d3.forceX().x(function(d) {
            return d.xx;
          }))
          .force('y', d3.forceY().y(function(d) {
            return d.yy;
          }))
          .force('collision', d3.forceCollide().radius(function(d) {
            return d.radius;
          }))
          .on('tick', ticked);




         function ticked() {
          var u = d3.select('svg')
            .selectAll('text')
            .filter(function(d, i) { return i != 0; })
            .data(data);

          u.enter()
            .append('text')
            .merge(u)
            .text(function(d) { return d.t; })
        .attr("fill","rgb(200,101,200)")    
        .attr('x', function(d) {
              return d.x;
            })
            .attr('y', function(d) {
              return d.y;
            })


          u.exit().remove();
        }

Upvotes: 1

Views: 313

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

A D3 simulation will start automatically. According to the documentation, d3.forceSimulation...

Creates a new simulation with the specified array of nodes and no forces. If nodes is not specified, it defaults to the empty array. The simulator starts automatically. (emphasis mine)

The solution is stoping the simulation...

simulation.stop();

And then restarting it after the desired delay, for instance using setTimeout:

setTimeout(function(){
  simulation.restart();
},2000);

Here is the original code you're building upon with a delay of 2 seconds:

<!DOCTYPE html>
<meta charset="utf-8">

<head>
  <title>Force layout (with links)</title>
</head>

<style>
  circle {
    fill: cadetblue;
  }
  
  line {
    stroke: #ccc;
  }
  
  text {
    text-anchor: middle;
    font-family: "Helvetica Neue", Helvetica, sans-serif;
    fill: #666;
    font-size: 16px;
  }
</style>

<body>
  <div id="content">
    <svg width="400" height="300">
      <g class="links"></g>
      <g class="nodes"></g>
    </svg>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>

  <script>
    var width = 400,
      height = 300

    var nodes = [{
        name: 'A'
      },
      {
        name: 'B'
      },
      {
        name: 'C'
      },
      {
        name: 'D'
      },
      {
        name: 'E'
      },
      {
        name: 'F'
      },
      {
        name: 'G'
      },
      {
        name: 'H'
      },
    ]

    var links = [{
        source: 0,
        target: 1
      },
      {
        source: 0,
        target: 2
      },
      {
        source: 0,
        target: 3
      },
      {
        source: 1,
        target: 6
      },
      {
        source: 3,
        target: 4
      },
      {
        source: 3,
        target: 7
      },
      {
        source: 4,
        target: 5
      },
      {
        source: 4,
        target: 7
      }
    ]

    var simulation = d3.forceSimulation(nodes)
      .force('charge', d3.forceManyBody().strength(-100))
      .force('center', d3.forceCenter(width / 2, height / 2))
      .force('link', d3.forceLink().links(links))
      .on('tick', ticked)
      .stop();

    setTimeout(function() {
      simulation.restart();
    }, 2000);

    function updateLinks() {
      var u = d3.select('.links')
        .selectAll('line')
        .data(links)

      u.enter()
        .append('line')
        .merge(u)
        .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
        })

      u.exit().remove()
    }

    function updateNodes() {
      u = d3.select('.nodes')
        .selectAll('text')
        .data(nodes)

      u.enter()
        .append('text')
        .text(function(d) {
          return d.name
        })
        .merge(u)
        .attr('x', function(d) {
          return d.x
        })
        .attr('y', function(d) {
          return d.y
        })
        .attr('dy', function(d) {
          return 5
        })

      u.exit().remove()
    }

    function ticked() {
      updateLinks()
      updateNodes()
    }
  </script>
</body>

</html>

Upvotes: 2

Related Questions