Tuesday, April 12, 2016

Working with D3 - Having an AJAX Loader Image

While D3 makes it easy to get started adding interesting visualizations to your web application and there are a lot of great examples on https://github.com/mbostock/d3/wiki/Gallery.  The problem is that almost none of these examples are ready for prime-time without some serious tweaking.  Either they need to be converted from using static data to relying on AJAX calls, or more importantly they do not support updates.

One suggestion is to use the excellent http://nvd3.org/ library by individuals who have taken the time to address these issues and provide a product that is production ready.

Another change you may need is to provide some kind of indication to the user while data is being loaded into the visualization.

Preparing for adding a loader - CSS code


First you will need to prepare an image to be used as your loading image.  One with a transparent background would likely work best.

In your style.css or whatever you are using for your style-sheet, place the following code that specifies the positioning of the loading image and opacity D3 svg container.  Also, you'll probably want to specify a minimum size of the container that will hold the D3 chart so the loading image knows where to position itself.

    div.ajax_loading {
        position: relative;
    }

    /* Grab only the direct descendant of the div that is an image */
    div.ajax_loading > img {
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        margin: auto;
    }

    /* Mark all children svg objects as being 50% transparent */
    div.ajax_loading svg {
        opacity: 0.5;
    }

    /* It is best to size your chart so the loader always knows where to display */
    /* An id specifier '#' was used here */
    #performance_chart {
        min-width: 400px;
        min-height: 300px;
    }


Add the Loading Image to the HTML code


Now you will need to add the 'ajax_loading' class to the HTML DIV that will contain the D3 visualization.  Within that DIV you will add the image.

    <div id="performance_chart" class="ajax_loading">
        <img src="img/ajax-loader.gif"/>
    </div>

This will display the loading image by default and also show a nice dimming effect on any svg objects contained in the target DIV.

The image I used has an opaque background, so it only looks right if you are dimming the DIV as we are doing here.  Otherwise you may want to use one with a transparent background.

Loading Image


Add Javascript Code to Control the Loading Image


You'll need to activate and deactivate the loading image from whatever code you are using to call and load the data.  In my case, before every AJAX call I display the loader and once the data is received I hide the loader using the following code.

    function setLoadingIndicator(id, status) {
        d3.select("#" + id).classed("ajax_loading", status);
        d3.select("#" + id + " img").classed("hidden", !status);
    }

Example program:

    //Show loading indicator
    setLoadingIndicator("chart_id", true);
    //Make the call to get data
    $.ajax({
        ...
        success: function(data) {
            //Draw the D3 chart
            draw_chart("chart_id", data);
            //Hide loading indicator
            setLoadingIndicator("chart_id", false);
        },
        error: function(result) {
            setLoadingIndicator("chart_id", false);
        }
    }); 


And that's all there is to it.