You're reading from Data Visualization with D3.js Cookbook
This age-old wisdom is arguably one of the most important cornerstones of data visualization. Animation on the other hand is generated using a series of still images in quick succession. Human eye-and-brain complex, through positive afterimage, phi phenomenon, and beta movement is able to create an illusion of continuous imagery. As Rick Parent put it perfectly in his brilliant work Computer Animation Algorithms and Techniques:
Images can quickly convey a large amount of information because the human visual system is a sophisticated information processor. It follows, then, that moving images have the potential to convey even more information in a short time. Indeed, the human visual system has evolved to provide for survival in an ever-changing world; it is designed to notice and interpret movement.
-Parent R. 2012
This is indeed the main goal of animation used in data visualization projects. In this chapter, we will focus on the mechanics...
In this recipe, we will first take a look at the simplest case of transition—interpolating attributes on a single element over time to produce a simple animation.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/single-element-transition.html
The code necessary to perform this simple transition is extremely short; good news for any animator:
<script type="text/javascript"> var body = d3.select("body"), duration = 5000; body.append("div") // <-A .classed("box", true) .style("background-color", "#e9967a") // <-B .transition() // <-C .duration(duration) // <-D .style("background-color", "#add8e6") // <-E .style("margin-left", "600px") // <-F .style("width", "100px") .style("height", "100px"); </script>
This code produces a moving...
A more elaborate data visualization requires animating multiple elements instead of a single element, as demonstrated in the previous recipe. More importantly, these transitions often need to be driven by data and coordinated with other elements within the same visualization. In this recipe, we will see how a data-driven multielement transition can be created to generate a moving bar chart. New bars are added over time while the chart shifts from right to left with a smooth transition.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/multi-element-transition.html
Transition can be thought of as a function of time. It is a function that maps time progression into numeric value progression, which then results in object motion (if the numeric value is used for positioning) or morphing (if the value is used to describe other visual attributes). Time always travels at a constant pace; in other words time progression is uniform (unless you are doing visualization near a black hole of course), however, the resulting value progression does not need to be uniform. Easing is a standard technique to provide flexibility and control to this kind of mapping. When a transition generates a uniform value progression, it is called linear easing. D3 provides support for different types of easing capabilities, and in this recipe, we will explore different built-in D3 easing functions, as well as how to implement custom easing functions with D3 transition.
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.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/tweening.html
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...
The first four recipes in this chapter are focused on single transition controls in D3, including custom easing and tweening functions. However, sometimes regardless of how much easing or tweening you do, a single transition is just not enough, for instance, you want to simulate teleporting a div
element by first squeezing the div
element into a beam, then passing the beam to a different position on the web page, and finally restoring the div
to its original size. In this recipe, we will see exactly how this type of transition can be achieved using
transition chaining.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/chaining.html
Under some circumstances, you might find it necessary to selectively apply transition to a subset of a certain selection. In this recipe, we will explore this effect using data-driven transition filtering techniques.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/filtering.html
In this recipe, we will move a set of div
elements (or boxes) across the web page from right to left. After moving all the boxes to the left, we selectively move only the boxes that are marked with Cat back, so they won't fight each other. Let's see the following code:
<script type="text/javascript"> var data = ["Cat", "Dog", "Cat", "Dog", "Cat", "Dog", "Cat", "Dog"], duration = 1500; d3.select("body").selectAll("div") .data(data) .enter() .append("div") .attr("class", "fixed-cell") .style("top", function (d,...
Transition chaining gives you the ability to trigger secondary transitions after the initial transition reaches its completion state; however, sometimes you might need to trigger certain action other than a transition, or maybe do something else during the transition. This is what transition event listeners are designed for, they are the topic of this recipe.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/events.html
In this recipe, we will demonstrate how to display different captions on an animated div
element based on its transition state. Obviously, this example can easily be extended to perform more meaningful tasks using the same technique:
<script type="text/javascript"> var body = d3.select("body"), duration = 3000; var div = body.append("div") .classed("box", true) .style("background-color", "steelblue...
In Chapter 4, Tipping the Scales, we explored how custom interpolators can be implemented in D3. In this recipe, we will demonstrate how this technique can be combined with D3 transition to generate special transition effects by leveraging custom interpolation.
Open your local copy of the following file in your web browser:
This recipe builds on top of what we have discussed in the Implementing a custom interpolator recipe in Chapter 4, Tipping the Scales. If you are not familiar with the concept of custom interpolation, please review the related recipe before proceeding with this one.
So far in this chapter we have discussed various topics on D3 transition. At this point you might be asking the question, What is powering D3 transition that is generating the animated frames?
In this recipe, we will explore a low-level D3 timer function that you can leverage to create your own custom animation from scratch.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/timer.html
In this recipe, we will create a custom animation that does not rely on D3 transition or interpolation at all; essentially a custom animation created from scratch. Let's look at the following code:
<script type="text/javascript"> var body = d3.select("body"); var countdown = body.append("div").append("input"); countdown.attr("type", "button") .attr("class", "countdown") .attr("value", "0"); function countup(target){ // ...