2

Question short: How do I access the whole this.selection in a subtransition of this.selection.exit()?

I'm trying to make a d3.js transition sequence. I know how to use the transition.transition() function to create a sequence, but here is my problem.

The sequence should be: [ remove .exit() nodes ] → [ move nodes ] → [ add .enter() nodes ]

code is:

        this.selection.exit().remove();
        this.selection
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight);
        this.selection.enter().append("div")
            .attr("class", "node")
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight);

If I add transition() to each of the commands above, all transitions would start at the same time. .delay() doesn't seem to work correctly on more than one transition at once.

So I would like to use subtransitions with .transition(), but if I apply the second command to the first one, I only have the .exit() selection.

EDIT 1:

Example how it doesn't work:

        this.selection.exit().transition()
        .duration(1000).style("opacity", 0).remove();

        this.selection.transition().delay(1010)
            .duration(1000)
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight)

        this.selection.enter().append("div")
            .attr("class", "node")
            .style("opacity", 0)
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight)
            .transition()
            .delay(2020)
            .duration(1000)
            .style("opacity", 1);

Error here: The last transition does not start, therefore all new nodes are opaque. But it works if I disable the second transition.

EDIT 2:

http://jsfiddle.net/dq6d117g/6/

The problem occurs if the function gets called again during the transitions.

Also, the delay should as long as the animation. If there is no animation, the delay should be 0. That's why I wanted to use the end-events.

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Powerswitch
  • 187
  • 2
  • 9

1 Answers1

3

You can use d3.transition().each() to chain transitions on pre-existing selections as per Mike Bostock's answer here, however, in my tests it didn't skip the unneeded transitions, so I added conditionals to skip the transition for empty selections:

http://jsfiddle.net/dq6d117g/8/

var transition=d3.transition().duration(2000);

if (!selection.exit().empty()) transition=transition.each(function(){
    selection.exit()
        .transition()
        .style("opacity", 0)
        .remove();
}).transition();

if (!selection.empty()) transition=transition.each(function(){
    selection.transition()
    .style("height", function (d) {
        return (d.value * 10) + "px";
    });
}).transition();

transition.each(function(){
    selection.enter()
        .append("div")
        .attr("class", "bar")
        .attr("id", function (d) {
            return d;
        })
        .style("opacity", 0)
        .style("height", function (d) {
            return (d.value * 9) + "px";
        })
        .text(function (d) {
            return d.id
        })
        .transition()
        .style("opacity", 1)
        .style("height", function (d) {
            return (d * 10) + "px";
        });
});
Community
  • 1
  • 1
CupawnTae
  • 14,192
  • 3
  • 29
  • 60