重置d3.js中的setTimeout

时间:2016-12-23 05:05:37

标签: javascript jquery d3.js

我在d3.js中运行可视化 - 这是一个live working example

我有一个setTimeout,它位于另一个函数中:

// initialize layout (for reset button)
var initForce = function() {

// clear svg
  container.selectAll('*').remove();

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


  graph.links.forEach(function(d, i) {

    setTimeout(function() {

...

我有一个重置按钮。当我按下按钮时,我希望可视化重新启动。代码就在这里:

 // When the user clicks on the "Reset" button, we'll
// start the whole process over again.


d3.select('#reset').on('click', function() {




// my attempt at stopping setTimeOut
  if (force) {
        force.stop();
    }

  // Re-initialize to start over again.

initForce();

});

我的问题是,当点击重置按钮时,它不会清除setTimeout。我已经玩了添加clearTimeout,因为很明显我在点击重置时所做的就是启动一个单独的计时器,而不是消除第一个计时器。我似乎无法弄清楚如何引用原始的setTimeout - 我尝试了一种不同的方法。

1 个答案:

答案 0 :(得分:2)

您可以使用3个步骤解决问题。

  • 在为每个链接创建超时功能时,创建一个数组变量来存储超时功能。例如: - var timeOuts = [];

  • 在迭代期间将每个超时函数推送到新的timeOuts数组。

  • 然后单击重置按钮清除所有超时功能。

代码段



var graph = {
   "nodes": [{
     "name": "1",
     "rating": 90,
     "id": 2951
   }, {
     "name": "2",
     "rating": 80,
     "id": 654654
   }, {
     "name": "3",
     "rating": 80,
     "id": 6546544
   }, {
     "name": "4",
     "rating": 1,
     "id": 68987978
   }, {
     "name": "5",
     "rating": 1,
     "id": 9878933
   }, {
     "name": "6",
     "rating": 1,
     "id": 6161
   }, {
     "name": "7",
     "rating": 1,
     "id": 64654
   }, {
     "name": "8",
     "rating": 20,
     "id": 354654
   }, {
     "name": "9",
     "rating": 50,
     "id": 8494
   }, {
     "name": "10",
     "rating": 1,
     "id": 6846874
   }, {
     "name": "11",
     "rating": 1,
     "id": 5487
   }, {
     "name": "12",
     "rating": 80,
     "id": "parfum_kenzo"
   }, {
     "name": "13",
     "rating": 1,
     "id": 65465465
   }, {
     "name": "14",
     "rating": 90,
     "id": "jungle_de_kenzo"
   }, {
     "name": "15",
     "rating": 20,
     "id": 313514
   }, {
     "name": "16",
     "rating": 40,
     "id": 36543614
   }, {
     "name": "17",
     "rating": 100,
     "id": "Yann_YA645"
   }, {
     "name": "18",
     "rating": 1,
     "id": 97413
   }, {
     "name": "19",
     "rating": 1,
     "id": 97414
   }, {
     "name": "20",
     "rating": 100,
     "id": 976431231
   }, {
     "name": "21",
     "rating": 1,
     "id": 9416
   }, {
     "name": "22",
     "rating": 1,
     "id": 998949
   }, {
     "name": "23",
     "rating": 100,
     "id": 984941
   }, {
     "name": "24",
     "rating": 100,
     "id": "99843"
   }, {
     "name": "25",
     "rating": 1,
     "id": 94915
   }, {
     "name": "26",
     "rating": 1,
     "id": 913134
   }, {
     "name": "27",
     "rating": 1,
     "id": 9134371
   }, {
     "name": "28",
     "rating": 1,
     "id": 971
   }],
   "links": [{
     "source": 6,
     "target": 5,
     "value": 6,
     "label": "publishedOn"
   }, {
     "source": 8,
     "target": 5,
     "value": 6,
     "label": "publishedOn"
   }, {
     "source": 7,
     "target": 1,
     "value": 4,
     "label": "containsKeyword"
   }, {
     "source": 8,
     "target": 10,
     "value": 3,
     "label": "containsKeyword"
   }, {
     "source": 7,
     "target": 14,
     "value": 4,
     "label": "publishedBy"
   }, {
     "source": 8,
     "target": 15,
     "value": 6,
     "label": "publishedBy"
   }, {
     "source": 9,
     "target": 1,
     "value": 6,
     "label": "depicts"
   }, {
     "source": 10,
     "target": 1,
     "value": 6,
     "label": "depicts"
   }, {
     "source": 16,
     "target": 1,
     "value": 6,
     "label": "manageWebsite"
   }, {
     "source": 27,
     "target": 27,
     "value": 6,
     "label": "byitself"
   }, {
     "source": 16,
     "target": 2,
     "value": 5,
     "label": "manageWebsite"
   }, {
     "source": 16,
     "target": 3,
     "value": 6,
     "label": "manageWebsite"
   }, {
     "source": 16,
     "target": 4,
     "value": 6,
     "label": "manageWebsite"
   }, {
     "source": 19,
     "target": 18,
     "value": 2,
     "label": "postedOn"
   }, {
     "source": 18,
     "target": 1,
     "value": 6,
     "label": "childOf"
   }, {
     "source": 17,
     "target": 19,
     "value": 8,
     "label": "describes"
   }, {
     "source": 18,
     "target": 11,
     "value": 6,
     "label": "containsKeyword"
   }, {
     "source": 17,
     "target": 13,
     "value": 3,
     "label": "containsKeyword"
   }, {
     "source": 20,
     "target": 13,
     "value": 3,
     "label": "containsKeyword"
   }, {
     "source": 20,
     "target": 21,
     "value": 3,
     "label": "postedOn"
   }, {
     "source": 22,
     "target": 20,
     "value": 3,
     "label": "postedOn"
   }, {
     "source": 23,
     "target": 21,
     "value": 3,
     "label": "manageWebsite"
   }, {
     "source": 23,
     "target": 24,
     "value": 3,
     "label": "manageWebsite"
   }, {
     "source": 23,
     "target": 25,
     "value": 3,
     "label": "manageWebsite"
   }, {
     "source": 23,
     "target": 26,
     "value": 3,
     "label": "manageWebsite"
   }]
 }


 var margin = {
   top: -5,
   right: -5,
   bottom: -5,
   left: -5
 };

 var width = 400 - margin.left - margin.right,
   height = 400 - margin.top - margin.bottom;

 var color = d3.scale.category20();

 var force = d3.layout.force()
   .charge(-200)
   .linkDistance(50)
   .size([width + margin.left + margin.right, height + margin.top + margin.bottom]);

 var zoom = d3.behavior.zoom()
   .scaleExtent([1, 10])
   .on("zoom", zoomed);

 var drag = d3.behavior.drag()
   .origin(function(d) {
     return d;
   })
   .on("dragstart", dragstarted)
   .on("drag", dragged)
   .on("dragend", dragended);


 var timeOuts = [];

 var svg = d3.select("#map").append("svg")
   .attr("width", width + margin.left + margin.right)
   .attr("height", height + margin.top + margin.bottom)
   .append("g")
   .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
   .call(zoom);

 var rect = svg.append("rect")
   .attr("width", width)
   .attr("height", height)
   .style("fill", "none")
   .style("pointer-events", "all");

 var container = svg.append("g");




 // initialize layout (for reset button)
 var initForce = function() {


   // clear svg
   container.selectAll('*').remove();

   // my attempt at stopping setTimeOut
   if (force) {
     force.stop();
   }

   // counter  
   var countern = 0;


   force
     .nodes(graph.nodes)
     .links(graph.links)
     .start();
   
   graph.links.forEach(function(d, i) {
     timeOuts.push(setTimeout(function() {


       var nodes = graph.nodes.filter(function(n, i) {
         return d.source.index == i || d.target.index == i
       });      


       // add one to counter
       countern = countern + 1;

       // add edge 
       container.append("line")
         .datum(d)
         .attr("class", "link")
         // delay on line appearing - do i need i * 10 ???
         // delay is half delay of node. 
         .transition()
         .style("stroke-width", 0)
         .delay(function(d, i) {
           return i * 10;
         }) //do i need this ?
         .duration(350)
         .style("stroke-width", function(d) {
           return Math.sqrt(d.value);
         });

       nodes.forEach(function(node) {
         var nodeG = container.append("g")
           .datum(node)
           .attr("class", "node")
           .attr("cx", function(d) {
             return d.x;
           })
           .attr("cy", function(d) {
             return d.y;
           })
           .call(drag);



         // add node
         nodeG.append("circle")
           .style('opacity', 0)
           .attr("r", function(d) {
             return d.weight * 2 + 5;
           })
           .style("fill", function(d) {
             return color(1 / d.rating);
           })
           // delay on line appearing - do i need i * 10 ???
           // delay is half delay of node. 
           .transition()
           .delay(function(d, i) {
             return i * 10;
           })
           .duration(700)
           .style('opacity', 1);
       });
       force.resume();
     }, 700 * i));
   });



   force.on("tick", function() {
     container.selectAll(".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;
       });

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

   var linkedByIndex = {};
   graph.links.forEach(function(d) {
     linkedByIndex[d.source.index + "," + d.target.index] = 1;
   });

   function isConnected(a, b) {
     return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
   }

   container.selectAll(".node").on("mouseover", function(d) {

     container.selectAll(".node").classed("node-active", function(o) {
       thisOpacity = isConnected(d, o) ? true : false;
       this.setAttribute('fill-opacity', thisOpacity);
       return thisOpacity;
     });

     container.selectAll(".link").classed("link-active", function(o) {
       return o.source === d || o.target === d ? true : false;
     });

     d3.select(this).classed("node-active", true);
     d3.select(this).select("circle").transition()
       .duration(700)
       .attr("r", (d.weight * 2 + 12) * 1.5);
   })

   .on("mouseout", function(d) {

     container.selectAll(".node").classed("node-active", false);
     container.selectAll(".link").classed("link-active", false);

     d3.select(this).select("circle").transition()
       .duration(700)
       .attr("r", d.weight * 2 + 12);
   });


 }; //initforce end


 function dottype(d) {
   d.x = +d.x;
   d.y = +d.y;
   return d;
 }

 function zoomed() {
   container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
 }

 function dragstarted(d) {
   d3.event.sourceEvent.stopPropagation();

   d3.select(this).classed("dragging", true);
   force.start();
 }

 function dragged(d) {

   d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);

 }

 function dragended(d) {

   d3.select(this).classed("dragging", false);
 }

 // When the user clicks on the "Reset" button, we'll
 // start the whole process over again.


 d3.select('#reset').on('click', function() {


   // Re-initialize to start over again.
   timeOuts.forEach(function(timeOutFn) {
     clearTimeout(timeOutFn);
   });
   initForce();

 });



 // Now we can initialize the force layout so that it's ready
 // to run.

 initForce();

body {
  margin: 0;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
.node {
  stroke: #fff;
  stroke-width: 1.5px;
}
.node-active {
  stroke: #555;
  stroke-width: 1.5px;
}
.link {
  stroke: #555;
  stroke-opacity: .3;
}
.link-active {
  stroke-opacity: 1;
}
.overlay {
  fill: none;
  pointer-events: all;
}
#map {
  border: 2px #555 dashed;
  width: 400px;
  height: 400px;
}
button {
  position: absolute;
  width: 40px;
  height: 30px;
}
button#reset {
  margin-top: 80px;
  margin-left: 8px;
}

<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <link href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">

</head>

<body>
  <div id="map">
    <button id='reset' title='Reset Layout to Beginning'>
      <i class='fa fa-undo'></i>
    </button>
  </div>
</body>
&#13;
&#13;
&#13;