<!DOCTYPE html>
<html ng-app="charts">
 
<head>
  <meta charset="utf-8" />
  <title>Pie Chart &amp; Line Chart using AngularJS and D3</title>
  <link data-require="bootstrap-css@*" data-semver="3.2.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
  <script data-require="angular.js@1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js" data-semver="1.0.8"></script>
  <script data-require="d3@*" data-semver="3.4.6" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
  <script src='app.js'></script>
</head>
 
<body ng-controller="MainCtrl">
  <div class="row">
    <div class='col-xs-12'>
      <div ng-repeat="item in data">
        {{item.name}} : {{item.value}}
        <br />
        <input type="range" name="volume" min="0" max="100" ng-model="item.value" value="{{item.value}}" />
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-6">
      <div pie-chart="" style="width:100%;height:460px;" data="data"></div>
    </div>
    <div class="col-xs-6">
      <div line-chart="" style="width:100%;height:460px;" data="data"></div>
    </div>
  </div>
</body>
 
</html>
Pie Chart &amp; Line Chart using AngularJS and D3
=========

The line chart and pie chart are rendered using d3.js, and each are separate Angular directives. The data object is declared on the main controller and is watched by each of the chart directives. The HTML range inputs are then bound to the data object in the main index.html file. 

[see it in actions on plunkr]
 
[see it in actions on plunkr]:http://embed.plnkr.co/5dFxQ3/preview
/*global angular, d3 */
 
angular.module ('charts', [])
 
.controller('MainCtrl', function($scope) {
  $scope.data = [
		{
			name : "Blue",
			value : 10,
			color : "#4a87ee"
		},
		{
			name : "Green",
			value : 40,
			color : "#66cc33"
		},
		{
			name : "Orange",
			value : 70,
			color : "#f0b840"
		},
		{
			name : "Red",
			value : 2,
			color : "#ef4e3a"
		}
	];
})
 
.directive ("pieChart", function () {
	return {
		restrict : "A",
		scope : {
			data : "="
		},
		link : function (scope, element) {
			var width,
				height,
				radius,
				pie,
				arc,
				svg,
				path;
 
			width = element[0].clientWidth;
			height = element[0].clientHeight;
			radius = Math.min (width, height) / 2;
 
			pie = d3.layout.pie ()
					.value (function (d) {return d.value;})
					.sort (null);
 
			arc = d3.svg.arc ()
					.outerRadius (radius - 20)
					.innerRadius (radius - 80);
 
			svg = d3.select (element[0])
					.append ("svg")
					.attr ({width : width, height : height})
					.append ("g")
					.attr ("transform", "translate(" + width * 0.5 + "," + height * 0.5 + ")");
 
			path = svg.datum (scope.data)
					.selectAll ("path")
					.data (pie)
					.enter ()
					.append ("path")
					.attr ({
						fill : function (d, i) {return scope.data [i].color;},
						d : arc
					});
				
			scope.$watch (
				"data",
				function () {
					pie.value (function (d) {return d.value;});
					path = path.data(pie);
					path.attr ("d", arc);
				},
				true
			);
		}
	};
})
 
.directive ("lineChart", function () {
	return {
		restrict : "A",
		scope : {
			data : "="
		},
		link : function (scope, element) {
			var vis;
			var width;
			var height;
			var margin;
			var xRange;
			var yRange;
			var xAxis;
			var yAxis;
			var lineFunc;
 
			element.addClass ('line-chart');
  
      width = element [0].clientWidth;
			height = element [0].clientHeight;
			margin = 35;
			
			vis = d3.select (element[0])
					.append ("svg")
					.attr ({width : width, height : height});
 
			xRange = d3.scale.linear ()
						.range ([margin, width - margin])
						.domain ([0,3]);
 
			xAxis = d3.svg.axis ()
						.scale (xRange)
						.tickValues([]);
 
			vis.append ("svg:g")
				.attr ("class", "x axis")
				.attr ("transform", "translate(0," + (height - margin) + ")")
				.call (xAxis);
 
			yRange = d3.scale.linear ()
						.range ([height - margin, margin])
						.domain ([0, 100]);
			
			yAxis = d3.svg.axis()
						.scale(yRange)
						.tickValues([])
						.orient("left");
 
			vis.append ("svg:g")
				.attr ("class", "y axis")
				.attr ("transform", "translate(" + (margin) + ",0)")
				.call (yAxis);
 
			lineFunc = d3.svg.line ()
				.x (function (d, i) {return xRange (i);})
				.y (function (d) {return yRange (d.value);})
				.interpolate ('cardinal');
 
			var path = vis.append ("svg:path")
				.attr ("d", lineFunc (scope.data))
				.attr ("stroke", "black")
				.attr ("stroke-width", 1)
				.attr ("fill", "none");
 
			var circle = vis.selectAll ("circle")
							.data (scope.data);
 
			circle.enter ().append ("circle")
				.attr ("cx", function (d, i) {return i * ((width - margin*2)/3) + margin;})
				.attr ("cy", function (d) {return height - margin - (d.value/100)*height;})
				.attr ("r", 10)
				.style ("fill", function (d) {return d.color;});
 
			scope.$watch (
				"data",
				function () {
					path.attr ("d", lineFunc (scope.data));
 
					vis.selectAll ("circle")
						.attr ("cy", function (d) {return height - margin - (d.value/100)*(height-margin*2);});
				},
				true
			);
		}
	};
});