Fjotten Fjotten - 6 months ago 27
Javascript Question

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);
}

Answer

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.

Comments