Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping transition in D3

Essential exposition: I'm a bit of a D3 newbie.

My goal is to have a line move from point A to point B, then immediately reappear at point A and repeat that transition. I've tried a lot of different things, but this is the closest I've come.

var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500);

// code, code, code, irrelevant code...

function timeForTimeline(){ // har
    var timeline = svg.append("line")
        .attr("stroke", "steelblue")
        .attr({
            'x1': 0,
            'y1': 130,
            'x2': 168,
            'y2': 130
        });
    (function repeat() {
        timeline = timeline
            .transition()
            .duration(4000)
            .ease("linear")
            .attr({
                'x1': 0,
                'y1': 430,
                'x2': 168,
                'y2': 430   
            })
            .each("end", function(){
                d3.select(this)
                    .transition()
                    .duration(0)
                    .attr({
                        'x1': 0,
                        'y1': 130,
                        'x2': 168,
                        'y2': 130
                    })
                    .each("end", repeat);
            });
    })();
};

The result is an excellent starting transition, followed by the line quickly jumping between point A and point B WITHOUT the duration(4000) bit taking effect. I've also tried removing the line at the bottom (d3.select(this).remove()) then appending a new one at the top of each call to repeat(). I've also tried just resetting x1, x2, y1, and y2 and skipping the transition altogether. I'm not saying I attempted those correctly, but my results were either no lines at all, infinite lines, or a single line that reaches point B and stays there.

Any other suggestions on how to accomplish my (likely very simplistic) goal? Thanks so much for your help!

like image 242
Andrew LaPrise Avatar asked Apr 23 '14 00:04

Andrew LaPrise


1 Answers

It seems to me that you don't need to specify the starting coordinates twice. You could just assign the initial coordinates inside the repeat function and call it immediately like so:

function timeForTimeline() {
    var timeline = svg.append("line")
        .attr("stroke", "steelblue");

    repeat();

    function repeat() {
      timeline.attr({
        'x1': 0,
        'y1': 130,
        'x2': 168,
        'y2': 130
      })
      .transition()
      .duration(4000)
      .ease("linear")
      .attr({
        'x1': 0,
        'y1': 430,
        'x2': 168,
        'y2': 430   
      })
      .each("end", repeat);
    }
}

Here's a fiddle

like image 144
jshanley Avatar answered Nov 11 '22 17:11

jshanley