Dynamic rescaling of axes

In some cases, the scale used by axes might change when triggered by user interaction or changes from data feeds. For example, a user might change the time range for the visualization. This kind of change also needs to be reflected by rescaling the axes. In this recipe, we will explore how this can be achieved dynamically while also redrawing the grid lines associated with each tick.

Getting Ready

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

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter5/rescaling.html

How to do it...

Here is the code showing how to perform dynamic rescaling:

<script type="text/javascript">
    var height = 500, 
        width = 500, 
        margin = 25,
        xAxis, yAxis, xAxisLength, yAxisLength;
    
    var svg = d3.select("body").append("svg")     
            .attr("class", "axis")    
            .attr("width", width)
            .attr("height", height);
    
    function renderXAxis(){
        xAxisLength = width - 2 * margin;
    
        var scale = d3.scale.linear()
                        .domain([0, 100])
                        .range([0, xAxisLength]);
        
        xAxis = d3.svg.axis()
                .scale(scale)
                .tickSubdivide(1)
                .orient("bottom");
                
        svg.append("g")       
            .attr("class", "x-axis")
            .attr("transform", function(){ 
                return "translate(" + margin + "," 
                           + (height - margin) + ")";
            })
            .call(xAxis);
    }
    
            
    function rescale(){ // <-A
        var max = Math.round(Math.random() * 100);
        
        xAxis.scale().domain([0, max]); // <-B
        svg.select("g.x-axis")
            .transition()
            .call(xAxis); // <-C
        
        renderXGridlines();
    }       
    
    function renderXGridlines(){
        var lines = d3.selectAll("g.x-axis g.tick")
                .select("line.grid-line")
                .remove(); // <-D
                
        lines = d3.selectAll("g.x-axis g.tick")
                .append("line") 
                .classed("grid-line", true)

        lines.attr("x1", 0) 
                .attr("y1", 0)
                .attr("x2", 0)
                .attr("y2", - yAxisLength); 
    }
    
    
    renderXAxis();
    renderXGridlines();
</script>

The preceding code generates the following effects:

How to do it...

Dynamic axes rescaling

Note

Due to limited scope in this book, the y axis-related code has been omitted from the code example in this recipe. See the code example available online for a complete reference.

How it works...

As soon as you click the ReScale button on the screen, you will notice both the axes rescale while all the ticks as well as grid lines get redrawn accompanied with a smooth transition effect. In this section, we will focus on how rescaling works and leave the transition effect for the next chapter Transition with Style. Most of the heavy lifting in this recipe is done by the rescale function defined on line A.

function rescale(){ // <-A
  var max = Math.round(Math.random() * 100);
        
  xAxis.scale().domain([0, max]); // <-B
  svg.select("g.x-axis")
    .transition()
    .call(xAxis); // <-C
        
  renderXGridlines();
}   

To rescale an axis, we simply change its domain (see line B). If you recall, the scale domain represents the data domain, while its range corresponds to visual domain. Therefore, visual range should remain constant since we are not resizing the SVG canvas. Once updated, we call the xAxis again by passing in the svg:g element for the x axis (see line C); this simple call will take care of the axis updating, hence, our job is done with the axis. In the next step, we also need to update and redraw all the grid lines since the domain change will also change all the ticks:

function renderXGridlines(){
        var lines = d3.selectAll("g.x-axis g.tick")
                .select("line.grid-line")
                .remove(); // <-D
                
        lines = d3.selectAll("g.x-axis g.tick")
                .append("line") 
                .classed("grid-line", true)

        lines.attr("x1", 0) 
                .attr("y1", 0)
                .attr("x2", 0)
                .attr("y2", - yAxisLength); 
}

This is achieved by removing every grid line by calling the remove() function, as shown on line D, and then recreating the grid lines for all the new ticks on rescaled axes. This approach effectively keeps all grid lines consistent with the ticks during rescaling.

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

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