Using a drilldown with Angular Chart’s

So, recently I was working on a project for work that required me to create a dashboard page which would display some statistics in a user friendly manner, using charts. One of the requirements was that I use completely  open source libraries to accomplish this. Therefore, the library I decided to use  angular-chart.js. Which provides some really user friendly, easy to use charts. This is built upon the Chart.js library, meaning most elements can be customized to look how I want it to. However, one of the biggest missing features is that neither of the libraries provide drilldowns. Since having a drilldown was absolutely essential, and i wasn’t willing to change libraries as I was pretty comfortable with angular-charts I decided to implement my own drilldown. Utilizing the power of angular’s data binding and some smart data modelling (if i may say so myself), I was able to get it to work.

Now, How does it work? To understand that you need to understand how angular-charts work, and the best tutorial can be found here.

Once you understand how angular charts work it becoes easy to think about how you implement a drilldown.

First, you have to know on which element the user is clicking on(i.e. which slice of the pie the user is clicking on). This is found out by the on click provided by the library itself.

        <canvas chart-click="clickHandler" chart-colors="chart.primary.colors" chart-data="chart.primary.data" chart-labels="chart.primary.labels" chart-options="chart.primary.options" class="chart chart-pie" id="{{chart.uid}}">
        </canvas>

As you can see, on click the method clickHandler gets called. Here is what clickHandler does:

    $scope.onClick = function(points, evt) {
        //gets the id of the chart
        var chartId = evt.target.id;
        //different use case
        //navigates to a page if ctrl is pressed while cliclomg
        if (points.length != 0) {
            if (evt.ctrlKey) {
                $window.location.href = 'http://www.google.com';
                return;
            }
            //gets the label name
            var labelName = points[0]._model.label;
            //gets the dataset index
            var datasetIndex = points[0]._index;
            changeToDrilldown(chartId, labelName, datasetIndex)
        }
    };

The method signature :

$scope.onClick = function(points, evt)

Please note the method name is different because the html is in a directive and onClick is passed as clickHandler. It is the same method that gets fired though.

The parameters points and evt are passed by the chart-click directive itself, evt is the event that occurred and points is a object containing the information about the graph.

The most important step is to extract the data set index, which is the index of the data in the array which is passed to the chart directive.(Refer the link to angular chart tutorial.)

So basically what I do is i get the dataset index from the click event and i have an associative array of drilldown objects, which means that the drill down in the 1st postion is for the data in the 1st position. Check out this model below.

        //This is my promarty data. Even without drill downs this data will be displays
        var primaryData = {
            header: "Popular Vehicle's 2016",
            labels: ["Car", "Jeep", "SUV", "Van"],
            data: [10, 15, 10, 25],
            colors: colors,
            options: options,
        };
        //Drilldown Data
        var drilldownData1 = {
            header: "Car Colours",
            labels: ["Red", "Grey", "Orange", "Black"],
            data: [
                100, 100, 200, 250
            ],
            colors: colors,
            options: options,
        };
        //Drilldown Data
        var drilldownData2 = {
            header: "Jeep Colours",
            labels: ["Green", "Grey", "Mixed", "Blue", "Yellow"],
            data: [125, 130, 120, 53, 240],
            colors: colors,
            options: options,
        };
        //Since the arrays are associative by index,
        //if there is no drilldown it is still essential to
        //send a null element to indicate
        //there is no drill down
        var drilldownData3 = null;
        //Drilldown Data
        var drilldownData4 = {
            header: "Van Colours",
            labels: ["White", "Black"],
            data: [130, 220],
            colors: colors,
            options: options,
        };
        //This is the chart model which is to my custom directive
        var chart1 = {
            //A uid to identify individual charts(for when you have multiple charts)
            uid: "chart1",
            //The primary daya
            primary: primaryData,
            //The drill down data, associative to the primary data
            drilldown: [drilldownData1,drilldownData2,drilldownData3,drilldownData4],
            //A temp variable to store the primary data when the drilldown data is switched
            //to the primary. When null we know the primary data is being displayed.
            temp:null
        };

Now that you have seen the model let me show you the code that does the actual work.

     function changeToDrilldown(chartId, labelName, datasetIndex) {
        for (var i = 0; i < $scope.charts.length; i++) {
            if ($scope.charts[i].uid === chartId) {
                if ($scope.charts[i].drilldown.length !== 0) {
                    if ($scope.charts[i].temp === null) {
                        if ($scope.charts[i].drilldown[datasetIndex] !== null) {
                            $scope.charts[i].temp = $scope.charts[i].primary;
                            $scope.charts[i].primary =    $scope.charts[i].drilldown[datasetIndex];
                        }
                    }
                }
            }
        }
    }

What the code does is:

  1. Searches for the chart in the array which contains all the charts.
  2. Checks if there are drilldowns available
  3. Checks if the temp is null(To check if we are in the primary level or drilldown level)
  4. Then checks if the drilldown element at the index of the primary data is null
  5. Swaps the temp and primary
  6. Swaps the primary with the drilldown.

To revert back to normal, simply switch the primary data with the temp data and make temp null again.

The entire code can be found on my github.

Hope this helps!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s