Using tweening

Tween comes from the word "inbetween", which is a common practice performed in traditional animation where after key frames were created by the master animator, less experienced animators were used to generate frames in between the key frames. This phrase is borrowed in modern computer-generated animation and it refers to the technique or algorithm controlling how the "inbetween" frames are generated. In this recipe, we will examine how the D3 transition supports tweening.

Getting Ready

Open your local copy of the following file in your web browser:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/tweening.html

How to do it...

In the following code example, we will create a custom tweening function to animate a button label through nine discrete integral numbers:

<script type="text/javascript">
    var body = d3.select("body"), duration = 5000;
    
    body.append("div").append("input")
        .attr("type", "button")
        .attr("class", "countdown")
        .attr("value", "0")
        .style("width", "150px")
        .transition().duration(duration).ease("linear")
            .style("width", "400px")
            .attr("value", "9");
    
    body.append("div").append("input")
        .attr("type", "button")
        .attr("class", "countdown")
        .attr("value", "0")
        .transition().duration(duration).ease("linear")
            .styleTween("width", widthTween) // <- A
            .attrTween("value", valueTween); // <- B
            
            
    function widthTween(a){
        var interpolate = d3.scale.quantize()
            .domain([0, 1])
            .range([150, 200, 250, 350, 400]);
    
        return function(t){
            return interpolate(t) + "px";
        };
    }
    
    function valueTween(){
        var interpolate = d3.scale.quantize() // <-C
            .domain([0, 1])
            .range([1, 2, 3, 4, 5, 6, 7, 8, 9]);
    
        return function(t){ // <-D
            return interpolate(t);
        };
    }        
</script>

The preceding code generates two buttons morphing at a very different rate, and the following screenshot is taken while this process is going on:

How to do it...

Tweening

How it works...

In this recipe, the first button was created using simple transition with linear easing:

body.append("div").append("input")
        .attr("type", "button")
        .attr("class", "countdown")
        .attr("value", "0")
        .style("width", "150px")
        .transition().duration(duration).ease("linear")
            .style("width", "400px")
            .attr("value", "9");

The transition changes the button's width from "150px" to "400px", while changing its value from "0" to "9". As expected, this transition simply relies on continuous linear interpolation of these values using D3 string interpolator. In comparison, the second button has the effect of changing these values in chunks. Moving from 1 to 2, then to 3, and so on up to 9. This is achieved using D3 tweening support with attrTween and styleTween functions. Let's first take a look at how the button value tweening works:

.transition().duration(duration).ease("linear")
            .styleTween("width", widthTween) // <- A
            .attrTween("value", valueTween); // <- B

In the preceding code snippet, we can see that instead of setting the end value for the value attribute as we have done in the case of the first button, we use attrTween function and offered a tweening function valueTween, which is implemented as the following:

function valueTween(){
    var interpolate = d3.scale.quantize() // <-C
        .domain([0, 1])
        .range([1, 2, 3, 4, 5, 6, 7, 8, 9]);
        
    return function(t){ // <-D
        return interpolate(t);
    };
}        

In D3, a tween function is expected to be a factory function, which constructs the actual function that will be used to perform the tweening. In this case, we have defined a quantize scale that maps the domain [0, 1] to a discrete integral range of [1, 9], on line C. The actual tweening function defined on line D simply interpolates the parametric time value using the quantize scale which generates the jumping integer effect.

Note

Quantize scales are a variant of linear scale with a discrete range rather than continuous. For more information on quantize scales, please visit the following link:

https://github.com/mbostock/d3/wiki/Quantitative-Scales#wiki-quantize

There's more...

At this point we have touched upon all three concepts related to transition: ease, tween, and interpolation. Typically, D3 transition is defined and driven through all the three levels shown in the following sequence diagram:

There's more...

Drivers of transition

As we have shown through multiple recipes, D3 transition supports customization in all three levels. This gives us tremendous flexibility to customize the transition behavior exactly the way we want.

Tip

Though custom tween is usually implemented using interpolation, there is no limit to what you can do in your own tween function. It is entirely possible to generate custom tween without using D3 interpolator at all.

We used linear easing in this recipe to highlight the effect of tweening, however, D3 fully supports eased tweening, meaning that you can combine any of the ease functions we have demonstrated in the previous recipe with your custom tween to generate even more complex transition effects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset