How to do chained transitions on different elements in d3.js?

I would like to do chained transition on different elements. Throughout the program I want to run a sequence of transitions. After the first transition on element x finishes I want to start with transitioning on element y, and so forth. The transitions should vary in duration.

One way to "solve" it is delaying all the latter transitions based on the sum of durations of previous transitions. But this is pretty ugly since it is quite messy and not exact.

Here is an example I try to accomplish:

<!DOCTYPE html>
<meta charset="utf-8">
<head>
        <script src="https://d3js.org/d3.v4.js"></script>
</head>
<body>
    <script>
        let sel = d3.select("body")
        let selFirst = sel.append("h1").attr("class", "first").text("first");
        let selSecond = sel.append("h2").attr("class", "second").text("second");
        let selThird = sel.append("h3").attr("class", "third").text("third");

        let trans = d3.transition("body");
        let firstTrans = trans.each(function() {selFirst.transition().style("opacity", 0).transition().style("opacity",1); })
        let secondTrans = firstTrans.each(function() {selSecond.transition().style("opacity", 0).transition().style("opacity",1); })
        let thirdTrans = secondTrans.each(function() {selThird.transition().style("opacity", 0).transition().style("opacity",1); })

    </script>
</body>
</html> 

See this JSfiddle


Thanks to Gerardo Furtado, here is one possible solution.

Step 1: you have to mark all the corresponding elements with the same class, ie chained-transition .

    let sel = d3.select("body")
    let selFirst = sel.append("h1").attr("class", "chained-transition first").text("first");
    let selSecond = sel.append("h1").attr("class", "chained-transition second").text("second");
    let selThird = sel.append("h1").attr("class", "chained-transition third").text("third");

Step 2: Now you can create a selection containing all the elements which should be transitioned in succession. To have varying durations for each selection, you can attach the desired duration in milliseconds to each element. (If you have not already done that with the creation of the element in step 1, possible together with other data)

    let chainedSel = d3.selectAll(".chained-transition").data([1000,2000,3000]);

Step 3: create a function which takes one selection at a time, transitions it (with its duration) and calls itself with the next element. The code below is a function which is called with the whole chained selection. It filters down to the corresponding (next) element.

    transitionNext(chainedSel);

    // function gets the chained selection with 
    // all the corresponding elements. 
    // It start with the first one by default.
    function transitionNext(_selection, _index = 0){ 
        console.log("index: " + _index);
        // start off with the first element (_index === 0)
        let newSel = 
            _selection.filter(function(d,i) { return _index === i;});

            newSel.transition()
                    .duration(d => d) // take the corresponding duration
                    .style("opacity", 0)
                .transition()
                    .duration(d => d) // as above
                    .style("opacity",1)
                    .style("color", "green")
                // this function is called after the transition is finished
                .on ("end", function() { 
                    _index = _index + 1;
                    // call function and filter the next element
                    if (_selection.size() > _index) { transitionNext(_selection, _index);}
                });
    }

The complete example is here:

        let sel = d3.select("body")
        let selFirst = sel.append("h1").attr("class", "chained-transition first").text("first");
        let selSecond = sel.append("h1").attr("class", "chained-transition second").text("second");
        let selThird = sel.append("h1").attr("class", "chained-transition third").text("third");

        let chainedSel = d3.selectAll(".chained-transition").data([1000,2000,3000]);

        transitionNext(chainedSel);

        function transitionNext(_selection, _index = 0){
            console.log("index: " + _index);
            let newSel = 
                _selection.filter(function(d,i) { return _index === i;});

                newSel.transition()
                        .duration(d => d)
                        .style("opacity", 0)
                    .transition()
                        .duration(d => d)
                        .style("opacity",1)
                        .style("color", "green")
                    .on ("end", function() {
                        _index = _index + 1;
                        if (_selection.size() > _index) { transitionNext(_selection, _index);}
                    });
        }
<script src="https://d3js.org/d3.v4.js"></script>
链接地址: http://www.djcxy.com/p/83720.html

上一篇: 获取具有列的最大值的行

下一篇: 如何在d3.js中的不同元素上进行链式转换?