Interpolating compound objects

There will be cases when what you need to interpolate in your visualization is not a simple value but rather an object consisting of multiple and different values, for example, a rectangular object with width, height, and color attributes. Fortunately, D3 has a built-in support for this type of compound object interpolation.

Getting Ready

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

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter4/compound-interpolation.html

How to do it...

In this recipe, we will examine how compound object interpolation is performed in D3. The code for the compound-interpolation.html file is as follows:

<div id="compound" class="clear">
    <span>Compound Interpolation<br></span>
</div>

<script type="text/javascript">
    var max = 21, data = [];

    var compoundScale = d3.scale.pow()
            .exponent(2)
            .domain([0, max])
            .range([
                {color:"#add8e6", height:"15px"}, // <-A
                {color:"#4169e1", height:"150px"} // <-B
            ]);

    for (var i = 0; i < max; ++i) data.push(i);

    function render(data, scale, selector) { // <-C
        d3.select(selector).selectAll("div.v-bar")
                .data(data)
                .enter().append("div").classed("v-bar", true)
                .append("span");

        d3.select(selector).selectAll("div.v-bar")
                .data(data)
                .exit().remove();

        d3.select(selector).selectAll("div.v-bar")
                .data(data)
                .classed("v-bar", true)
                .style("height", function(d){ // <-D
                    return scale(d).height;
                }) 
                .style("background-color", function(d){ // <-E
                    return scale(d).color;
                })
                .select("span")
                .text(function(d,i){return i;});
    }

    render(data, compoundScale, "#compound");
</script>

The preceding code generates the following visual output:

How to do it...

Compound object interpolation

How it works...

This recipe is different from the previous recipes of this chapter by the fact that the scale we use in this recipe has a range defined using two objects rather than simple primitive data types:

var compoundScale = d3.scale.pow()
            .exponent(2)
            .domain([0, max])
            .range([
                {color:"#add8e6", height:"15px"}, // <-A
                {color:"#4169e1", height:"150px"} // <-B
            ]);

We can see on line A and B that the start and end of the scale range are two objects which contain two different kinds of values; one for RGB color and the other one for CSS height style. When you interpolate this kind of a scale containing compound range, D3 will iterate through each of the fields inside an object and recursively apply the simple interpolation rule on each one of them. Thus, in other words, for this example, D3 will interpolate the color field using color interpolation from #add8e6 to #4169e1 while using string interpolation on height field from 15px to 150px.

Tip

The recursive nature of this algorithm allows D3 to interpolate on even nested objects. Therefore you can interpolate on an object like this:

{
  color:"#add8e6", 
  size{ 
height:"15px", 
width: "25px"
  }
}

A compound scale function, when invoked, returns a compound object that matches the given range definition:

.style("height", function(d){
  return scale(d).height; // <-D
}) 
.style("background-color", function(d){
  return scale(d).color; // <-E
})

As we can see on line D and E, the returned value is a compound object, and this is why we can access its attribute to retrieve the interpolated values.

Tip

Though it is not a common case, if the start and end of your compound scale range do not have identical attributes, D3 won't complain but rather it will just treat the missing attribute as a constant. The following scale will render the height to be 15px for all the div elements:

var compoundScale = d3.scale.pow()
            .exponent(2)
            .domain([0, max])
            .range([
                {color:"#add8e6", height:"15px"}, // <-A
                {color:"#4169e1"} // <-B
            ]);
..................Content has been hidden....................

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