Reputation: 14364
Currently, the code below moves the squares in an undulating fashion, but I want to change it so there is a single traveling wave (like they do in the stadiums). I guess what I have to do is figure out how to add a delay to the repeat loop so the first square goes down and stays down until the last square starts to go up.
Here's my code and a jsfiddle:
var margin = {top: 40, bottom: 40, left: 40, right: 40},
width = 960 - margin.left - margin.right,
height = 200 - margin.bottom - margin.top;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var n = 20,
rect_width = 20,
padding = 1,
speed = 1000,
item_delay = 40;
var x = d3.scale.ordinal()
.domain(d3.range(n))
.rangePoints([0, n * (rect_width + padding)]);
var rects = svg.selectAll(".rect")
.data(x.domain())
.enter().append("rect")
.attr("x", function(d,i){ return x(i); })
.attr("y", 0)
.attr("height", rect_width)
.attr("width", rect_width)
.attr("class", "rect")
.transition()
.duration(speed)
.delay(function(d,i){ return i * 120; })
.each(start_repeat);
function start_repeat(){
var rect = d3.select(this);
(function repeat(){
rect = rect.transition()
.attr("y", 0)
.transition()
.attr("y", 100)
.each("end", repeat);
})()
}
I think my problem is that I don't really understand what's going on inside the repeat
function.
UPDATE
I figured out a simple to loop the transition, but it requires that I manually calculate the loop duration and I'd like to avoid this (see snippet for a live version).
speed = 500;
var loop_duration = 2000;
(function loop(){
rects.transition()
.delay(function(d,i){ return i * item_delay; })
.duration(speed)
.attr("y", 100) // down
.transition()
.attr("y", 0)
setTimeout(loop, loop_duration)
})()
var margin = {top: 40, bottom: 40, left: 40, right: 40},
width = 960 - margin.left - margin.right,
height = 300 - margin.bottom - margin.top;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var n = 20,
rect_width = 20,
padding = 1,
speed = 500,
item_delay = 100;
var x = d3.scale.ordinal()
.domain(d3.range(n))
.rangePoints([0, n * (rect_width + padding)]);
var rects = svg.selectAll(".rect")
.data(x.domain())
.enter().append("rect")
.attr("x", function(d,i){ return x(i); })
.attr("height", rect_width)
.attr("width", rect_width)
.attr("class", "rect")
.attr("y", 0); // up - very important, if you don't set this, there is no interpolation
var loop_duration = 2000;
(function loop(){
rects.transition()
.delay(function(d,i){ return i * item_delay; })
.duration(speed)
.attr("y", 100) // down
.transition()
.attr("y", 0)
setTimeout(loop, loop_duration)
})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I've tried deparsing the start_repeat
function to understand what's going on, but I still don't get it. For example, what is the difference between old_rect
and rect
?
function start_repeat() {
var rect = d3.select(this);
(function repeat() {
var move_down_t0 = rect.transition() // chain the down-transition on the same selection
.attr("y", 100);
var move_up_t1 = move_down_t0.transition()
.attr("y", 0)
old_rect = rect;
rect = move_up_t1.each("end", repeat);
})();
}
Upvotes: 3
Views: 1942
Reputation: 1841
My solution:
http://jsfiddle.net/k5zm18hn/2/
function repeat(){
if(d3.select(this).attr("y")==0){
d3.select(this).transition()
.delay(pausing_delay)
.duration(speed)
.attr("y", 100)
.each("end", repeat);
}
else{
d3.select(this).transition()
.attr("y", 0)
.duration(speed)
.each("end", repeat);
}
}
Change pausing_delay variable for optimal results.
Upvotes: 1
Reputation: 8150
I am a bit confused myself, but I tried setting the duration and delays to be equal, such that the transition lasts as long as the values are set down.
Try this:
var rects = svg.selectAll(".rect")
.data(x.domain())
.enter().append("rect")
.attr("x", function(d,i){ return x(i); })
.attr("y", 0)
.attr("height", rect_width)
.attr("width", rect_width)
.attr("class", "rect")
.transition()
.duration(speed)
.delay(function(d,i){ return i * (speed/(n*2)); })
.each(start_repeat);
Upvotes: 1