Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do transitions flicker/stutter when applied in a separate function (D3)

I was messing around with transitions and I noticed some stuttering and flickering when the transitions are applied to the selection in a different function. If, however, the transition is applied with method chaining, it works exactly as prescribed.

Below is small example (Fiddle) of simply moving some text. The first, leftmost, string magically teleports down the page before the transition starts. The second, rightmost, string has a smooth transition from the top to the bottom of the page.

Why does this 'teleport' happen? Obviously applying the transitions in a separate function is not the same as chaining it, but is there a way to achieve this? Say, I want to apply the same transition to many different objects - retrieved from different selects - then is there a way to relegate the transition to its own function without getting this stuttering?

var svg = d3.select('svg');
var textElem = svg.append('text')
    .data(['hello world'])
    .attr('x', 30)
    .attr('y', 100)
    .attr('fill', '#000')
    .attr('id', 'a')
    .text(function (d) {
        return d;
    });
var textElem2 = svg.append('text')
    .data(['some text'])
    .attr('x', 230)
    .attr('y', 100)
    .attr('fill', '#000')
    .attr('id', 'a')
    .text(function (d) {
        return d;
    });
setTimeout(foo, 3000);

function foo() {
    textElem.data(['hello world, again!']);
    applyTextTransitions(textElem);
    textElem.attr({
        x: 30,
        y: 150
    });
    textElem.text(function (d) {
        return d;
    });

    textElem2.data(['some more text!'])
        .transition()
        .duration(1000)
        .style('opacity', 0)
        .transition()
        .duration(1000)
        .style('opacity', 1)
        .attr({
            x: 230,
            y: 150
        })
        .text(function (d) {
            return d;
        });
}

function applyTextTransitions(element) {
    element
        .transition()
        .duration(1000)
        .style('opacity', 0)
        .transition()
        .duration(1000)
        .style('opacity', 1);
}
like image 982
Fjotten Avatar asked May 18 '16 18:05

Fjotten


2 Answers

I haven't used d3, but do you mean to do this?

applyTextTransitions(textElem, { x: 30, y: 150 }); 

function applyTextTransitions(element, newPos) {
    element
    .transition()
    .duration(1000)
    .style('opacity', 0)
    .transition()
    .duration(1000)
    .attr(newPos)
    .style('opacity', 1)
    .text(function(d){
        return d; 
     }); 
}

https://jsfiddle.net/k8kv4arv/3/

The "jump" happens because the calling functions waits until applyTextTransitions() is finished, then applies the new dimensions.

like image 197
html_programmer Avatar answered Nov 10 '22 05:11

html_programmer


I know I'm late to the party, but...

The stuttering that you are getting is only because you call a transition function, applyTextTransition, and then immediately change the element's positioning.

applyTextTransitions(textElem);
textElem.attr({
    x: 30,
    y: 150
});

This is why you get the unwanted stuttering.


Additionally, the proper, D3 way to reuse functions that apply transitions is to use selection.call. This allows you to declare one function, and use the call method to invoke the function that applies the transition.

textElem.call(applyTextTransition);

function applyTextTransition(selection) {
  // perform selection.transition()
}

You can now use your function in your chaining and you aren't limited to using that function for just the current selection.

like image 21
Himmel Avatar answered Nov 10 '22 07:11

Himmel