We're going to build an app that uses the Github API to allow users to figure out which of their coworkers have been slacking off analyze commit data for a given project. I was inspired by this very slick app by David Haglund, which is also written with AngularJS.

There are a few things to note about the boilerplate. The <gh-visualization> tag is for a directive that we'll write later. When we register the directive, we'll use the normalized form: ghVisualization.

Getting the Data from Github

We'll start by adding a controller that makes requests to the Github API. Most of the code in the controller is for reformating the response from Github as a two-dimensional array: the first dimension is the author, the second dimension is the number of commits for that author for each day.

In a larger application, it would probably be a good idea to move reformatGithubResponse into its own service so that it can be easily reused.

Another thing to make note of is that if you want to use Github's API, you'll need to register it if you're hosting it somewhere other than localhost.

The Chart

The chart we're going to make is based on the stacked bar chart example. We want to bind some model on the scope to the data used by the chart. The chart also has the option of "stacked" and "grouped" layouts. We can also setup a binding to this option as well.

In order to write this, there are a few things to understand about directives. Here is a quick rundown of the way we're going to structure the directive:

app.directive('myDirective', function( /* dependencies */ ) {// define constants and helpers used for the directive// ...return {
restrict: 'E', // the directive can be invoked only by using <my-directive> tag in the template
scope: { // attributes bound to the scope of the directive
val: '='
},
link: function(scope, element, attrs) {// initialization, done once per my-directive tag in template. If my-directive is within an// ng-repeat-ed template then it will be called every time ngRepeat creates a new copy of the template.// ...// whenever the bound 'exp' expression changes, execute this
scope.$watch('exp', function(newVal, oldVal) {// ...
});
}
};
});

There's a lot more to directives than what I just mentioned, so I recommend reading the documentation on the AngularJS site to learn more.

So using the example from D3, and breaking up the code from that example, we are able to write this directive:

We setup margins, dimensions, and colors inside of the directive's closure. We bind val and grouped to the visualization's internal scope based on the attributes on <visualization>. Then, we append an SVG element to the base <visualization> element within the link function. Finally, all of the code to draw and redraw the chart goes inside of the $watch.

Finishing Touches

Let's add some styling to the app. Create a CSS file with the following contents, and add it to the head of the HTML:

So whenever the user presses "enter" or submits the form, the controller makes a request for the data on the Github API. When the call to Github resolves, the model updates, and because our visualization directive is listening to the data model on the scope, it knows to update itself. Similarly, we listen to grouped on the scope and run the animated transition accordingly.

Conclusion

D3.js is a very powerful tool for making visualizations that plays well with AngularJS. Besides D3.js, you can integrate many other libraries by writing services and directives to handle imperatively manipulating the DOM and binding to native browser events.