![](img/hackreactor-logo-white-bg.png)
# I like to explain things
![](img/central-limit-theorem.png)
![](img/monty-hall.png)
![](img/simpsons-paradox.png)
# I'm writing a book
![](img/d3-on-angular.png)
# Interactivity across visualizations
[Demo 1](http://vudlab.com/simpsons/) [Demo 2](demos/AI-editor/index.html)
# __How__ to make a donut chart directive
## What we'll build
[demo](demos/lets-make-a-donut-chart-directive/v9-using-a-controller-and-seperating-out-business-logic.html)
# An (extremely) brief intro to [D3](http://d3js.org)
D
ata
D
riven
D
ocuments
# D3
D3(data) -> DOM
for example
Data
````javascript
// somehow you get data
var data = [20, 50, 80];
````
D3
````javascript
d3.select('body').selectAll('div').data(data)
.enter().append('div')
// set the width based on the current data item
.style('width', function(d){ return d + '%' });
````
````javascript
// a function that takes a pie layout item and produces a
// new arc shaped <path> tag.
var arc = d3.svg.arc().innerRadius(400).outerRadius(600);
// create the arcs, passing each data element of the
// pie layout to the `arc` generator function.
d3.select('svg').selectAll('path').data(pie(data))
.enter().append('path')
.attr('d', arc);
````
````javascript
d3.select('svg').append('g')
// nudge the content in the svg down and to the right
.attr('transform', 'translate(300, 300)')
.selectAll('path').data(pie(data))
.enter().append('path')
.attr('d', arc);
````
[demo](demos/lets-make-a-donut-chart-directive/v0.2-d3-layout.pie.html)
# Additional Resources
### [An SVG Primer](http://alignedleft.com/tutorials/d3/an-svg-primer)
by Scott Murray
### [Let's Make a Bar Chart](http://bost.ocks.org/mike/bar/)
intro to D3 by Mike Bostock
### [Thinking with Joins](http://bost.ocks.org/mike/join/)
also by Mike Bostock
explains this black magic:
````javascript
d3.select('svg').append('g')
.selectAll('path').data(pie(data))
.enter().append('path')
.attr('d', arc);
````
# Directives
````javascript
var $timeout = function(callback, delay){
setTimeout(function(){
// after the callback, check all the scopes for changes
$scope.apply(function(){
callback();
});
}, delay);
}
````
it usually knows automatically via:
+ `ng-mouseover`
+ `ng-click`
+ `$timeout`
+ `$http`
+ etc...
````javascript
svg.on('mousedown', function(d) {
scope.$apply(function(){
// now inside angular world. safely update the data
scope.data = d3.range(4).map(Math.random);
});
});
scope.$watch('data', function(data) {
// `data` changed! update the arc <path>s
arcs.data(pie(data)).attr('d', arc);
});
````
[demo](demos/lets-make-a-donut-chart-directive/v4-updating-shared-data-with-watch-and-apply.html)
sweet
rrr.. wait a sec.. now ng-repeat don't work...
`ng-repeat` items each get a new scope.
[(more on object inheritance)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance)
````javascript
// our data changed! update the arcs
scope.$watch('data', function(data){
arcs.data(pie(data)).transition().attrTween('d', arcTween);
});
// transition the arc angles
function arcTween(a) {
// see: http://bl.ocks.org/mbostock/1346410
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
````
[transitioning arc angles demo](demos/arch-angels/index.html)
whoops... lets try that again. [transitioning arc angles demo](demos/lets-make-a-donut-chart-directive/v7-animation.html)
okay, but things break if the length of our data doesn't remain the same. now what?
# `.enter()`
# &
# `.exit()`
````javascript
scope.$watch('data', function(newData, oldData){
// 1.) animate the arcs that stayed around
// 2.) add and animate any new arcs (if newData.length > oldData.length)
// 3.) or remove any old arcs (if newData.length < oldData.length )
});
````
[demo](demos/lets-make-a-donut-chart-directive/v8-enter-and-exit.html)
But wait! Our directive is _still_ modifying our data directly. That doesn't sound __modular__...