D3:具有连续转换的事件函数

时间:2017-02-19 21:47:28

标签: javascript d3.js event-handling delay transitions

我有以下代码:

selection.
    .transition()
    .delay(1000)
    .each("start",f1)
    ...
    .transition()
    .delay(2000)
    .each("start",f2)
    ...
    .transition()
    .delay(3000)
    .each("start",f3)
    ...

函数f1f2f3会更改页面中某些DOM元素的外观。

当转换开始产生效果时,即在延迟指定的时间之后,我需要运行函数f1f2f3

但首先,当发生相应的转换时,我需要运行函数f1f2f3

相反在我看来f3f1f2之后立即执行,因此它隐藏了他们的DOM更改。

做什么是正确的?

1 个答案:

答案 0 :(得分:1)

如果你的函数一次运行而且一次全部运行而不考虑监听器,可能是因为你在连接你的监听器时在函数后面放了一个括号:

.each('start',function());

虽然您在问题中没有说明这一点,但您可能已将其排除在外以获得更清晰的问题。

如果您需要将参数传递给函数,您需要实际编写内联函数来调用函数:

.each('start', function() { functionName(param1,param2); })

即使是括号也不是麻烦的来源,我希望下面的例子可能有所帮助。

我在回答中使用了d3.js v4:此处使用的是.on方法,而不是.each

虽然我使用的是持续时间而不是延迟,但答案仍应适用于我的简短测试。

<强>片断:

基于您的问题的示例(假设括号是令人头疼的原因):

&#13;
&#13;
var svg = d3.select('body').append('svg').attr('width',400).attr('height',200);

var data = [4,12,4,12,4,12,4];

svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('cx', function(d,i) { return 40 + (i * 20); })
  .attr('cy', 50)
  .attr('r', function(d) { return d; })
  .attr('fill','black');
  

svg.selectAll('circle')
  // Transition 1
  .transition()
  .attr('r', function(d) { return (d == 4) ? 10 : 4; })
  .duration(3000)
  .on('start', s1() )
  .on('end', e1() )

  // Transition 2
  .transition()
  .attr('fill', function(d) { return (d == 4) ? "steelblue" : "orange"; })
  .duration(3000)
  .on('start', s2() )
  .on('end', e2() )
  
  // Transition 3
  .transition()
  .attr('cy', function(d,i) { return (d==4) ? 30:60; })
  .attr('r', function(d) { return (d == 4) ? 14 : 18; })
  .duration(3000)
  .on('start', s3() )
  .on('end', e3() )
  ;
  
  function s1() {  console.log("Transition 1 Start");  }
  function s2() {  console.log("Transition 2 Start");  }
  function s3() {  console.log("Transition 3 Start");  }
  function e1() {  console.log("Transition 1 End");    }
  function e2() {  console.log("Transition 2 End");    }  
  function e3() {  console.log("Transition 3 End");    }
&#13;
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
&#13;
&#13;
&#13;

所有功能一次触发,并触发一次。

删除括号将为您提供:

&#13;
&#13;
var svg = d3.select('body').append('svg').attr('width',400).attr('height',200);

var data = [4,12,4,12,4,12,4];

svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('cx', function(d,i) { return 40 + (i * 20); })
  .attr('cy', 50)
  .attr('r', function(d) { return d; })
  .attr('fill','black');
  

svg.selectAll('circle')
  // Transition 1
  .transition()
  .attr('r', function(d) { return (d == 4) ? 10 : 4; })
  .duration(3000)
  .on('start', s1 )
  .on('end', e1 )

  // Transition 2
  .transition()
  .attr('fill', function(d) { return (d == 4) ? "steelblue" : "orange"; })
  .duration(3000)
  .on('start', s2 )
  .on('end', e2 )
  
  // Transition 3
  .transition()
  .attr('cy', function(d,i) { return (d==4) ? 30:60; })
  .attr('r', function(d) { return (d == 4) ? 14 : 18; })
  .duration(3000)
  .on('start', s3 )
  .on('end', e3 )
  ;
  
  function s1() {  console.log("Transition 1 Start");  }
  function s2() {  console.log("Transition 2 Start");  }
  function s3() {  console.log("Transition 3 Start");  }
  function e1() {  console.log("Transition 1 End");    }
  function e2() {  console.log("Transition 2 End");    }  
  function e3() {  console.log("Transition 3 End");    }
&#13;
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
&#13;
&#13;
&#13;

选择没有转换,每个元素都单独转换,导致对每个函数的多次调用(这可能是期望的,我不确定它是否在您的情况下)。

如果你想要触发每个函数一次,那么你需要计算完成转换的元素数量(我已经为下面的结束事件做了这个)。或者,如果您确信所有转换几乎同时完成,您可以通过使用if语句在每个选项中调用该函数,该语句在特定元素开始或结束时触发事件(我已经为下面的启动事件执行了此操作) :

&#13;
&#13;
var svg = d3.select('body').append('svg').attr('width',400).attr('height',200);

var data = [4,12,4,12,4,12,4];

svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('cx', function(d,i) { return 40 + (i * 20); })
  .attr('cy', 50)
  .attr('r', function(d) { return d; })
  .attr('fill','black');
  

var n = 6;
var m = 6;

svg.selectAll('circle')
  // Transition 1
  .transition()
  .on('start',function(d,i) { if (i == 6) { log('transition 1 started'); } })
  .on('end',function(d,i) { if(--m == 0) { m = 6; log('transition 1 ended'); } })
  .attr('r', function(d) { return (d == 4) ? 10 : 4; })
  .duration(3000)

  // Transition 2
  .transition()
  .on('start',function(d,i) { if (i == 6) { log('transition 2 started'); } })
  .on('end',function(d,i) { if(--m == 0) { m = 6; log('transition 2 ended'); } })
  .attr('fill', function(d) { return (d == 4) ? "steelblue" : "orange"; })
  .duration(3000)
  
  // Transition 3
  .transition()
  .on('start',function(d,i) { if (i == 6) { log('transition 3 started'); } })
  .on('end',function(d,i) { if(--m == 0) { m = 6; log('transition 3 ended'); } })
  .attr('cy', function(d,i) { return (d==4) ? 30:60; })
  .attr('r', function(d) { return (d == 4) ? 14 : 18; })
  .duration(3000)
  ;
  
  function log(string) {
    console.log(string);
  }
&#13;
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
&#13;
&#13;
&#13;