D3:具有串联转换的事件函数
D3: event functions with concatenated transitions
我有如下代码:
selection.
.transition()
.delay(1000)
.each("start",f1)
...
.transition()
.delay(2000)
.each("start",f2)
...
.transition()
.delay(3000)
.each("start",f3)
...
函数 f1
、f2
和 f3
更改页面中某些 DOM 元素的外观。
我需要 运行 函数 f1
、f2
、f3
当转换开始产生效果时,即在 delay 指定的时间之后。
但首先我需要 运行 函数 f1
、f2
和 f3
当相应的转换发生时。
相反,在我看来,f3
是在 f1
和 f2
之后立即执行的,因此它隐藏了它们的 DOM 更改。
正确的做法是什么?
如果您的函数一次又一次地 运行 而不考虑监听器,这可能是因为您在附加监听器时在函数后面放置了括号:
.each('start',function());
虽然你没有在你的问题中指出这一点,但你可能已经排除了它们以获得更清晰的问题。
如果您需要将参数传递给函数,您需要实际编写一个内联函数来调用您的函数:
.each('start', function() { functionName(param1,param2); })
即使是括号也不是问题的根源,希望下面的示例可能有所帮助。
我在回答中使用了d3.js v4:这里使用.on
方法而不是.each
虽然我使用了持续时间而不是延迟,但答案在我的简短测试中应该仍然适用。
片段:
基于您的问题的示例(假设括号是令人头疼的原因):
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"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
所有函数一次触发,它们触发一次。
去掉括号会得到:
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"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
选择没有过渡,每个元素都是单独过渡的,导致对每个函数的多次调用(这可能是需要的,我不确定你的情况是否如此)。
如果你想触发每个函数一次,那么你将需要计算有多少元素已经完成转换(我已经为下面的结束事件完成了这个)。或者,如果您确信所有转换几乎同时完成,您可以通过使用 if 语句在每次选择时调用该函数一次,该语句在特定元素开始或完成时触发事件(我已经为下面的开始事件完成了此操作):
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);
}
<!--<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>
我有如下代码:
selection.
.transition()
.delay(1000)
.each("start",f1)
...
.transition()
.delay(2000)
.each("start",f2)
...
.transition()
.delay(3000)
.each("start",f3)
...
函数 f1
、f2
和 f3
更改页面中某些 DOM 元素的外观。
我需要 运行 函数 f1
、f2
、f3
当转换开始产生效果时,即在 delay 指定的时间之后。
但首先我需要 运行 函数 f1
、f2
和 f3
当相应的转换发生时。
相反,在我看来,f3
是在 f1
和 f2
之后立即执行的,因此它隐藏了它们的 DOM 更改。
正确的做法是什么?
如果您的函数一次又一次地 运行 而不考虑监听器,这可能是因为您在附加监听器时在函数后面放置了括号:
.each('start',function());
虽然你没有在你的问题中指出这一点,但你可能已经排除了它们以获得更清晰的问题。
如果您需要将参数传递给函数,您需要实际编写一个内联函数来调用您的函数:
.each('start', function() { functionName(param1,param2); })
即使是括号也不是问题的根源,希望下面的示例可能有所帮助。
我在回答中使用了d3.js v4:这里使用.on
方法而不是.each
虽然我使用了持续时间而不是延迟,但答案在我的简短测试中应该仍然适用。
片段:
基于您的问题的示例(假设括号是令人头疼的原因):
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"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
所有函数一次触发,它们触发一次。
去掉括号会得到:
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"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
选择没有过渡,每个元素都是单独过渡的,导致对每个函数的多次调用(这可能是需要的,我不确定你的情况是否如此)。
如果你想触发每个函数一次,那么你将需要计算有多少元素已经完成转换(我已经为下面的结束事件完成了这个)。或者,如果您确信所有转换几乎同时完成,您可以通过使用 if 语句在每次选择时调用该函数一次,该语句在特定元素开始或完成时触发事件(我已经为下面的开始事件完成了此操作):
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);
}
<!--<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>