This is a code excerpt from the book D3 on Angular. http://leanpub.com/d3angularjs
The data was scraped from Wikipedia on 3/15/2014: https://en.wikipedia.org/wiki/List_of_The_Walking_Dead_episodes
<!DOCTYPE html>
<html>
<head>
<title>Walking Dead Viewership</title>
</head>
<style>
body, html{
margin: 0;
width: 900px;
color: white;
background-color: black;
font-family: helvetica;
margin: auto;
}
.scatter-container{
width: 50%;
float: left;
height: 400px;
}
.detail{
width: 50%;
float: left;
height: 400px;
}
scatter{
width: 100%;
height: 100%;
display: block;
z-index: 0;
overflow: hidden;
font-size: 10px;
}
scatter circle{
opacity: 0.4;
cursor: pointer;
stroke-width: 2;
}
scatter circle:hover{
stroke: white;
}
scatter text{
fill: white;
stroke: none;
}
scatter .x-axis path, scatter .y-axis path{
stroke: none;
fill: none;
}
scatter .x-axis line, scatter .y-axis line{
stroke: rgba(255, 255, 255, 0.2);
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<body ng-app="myApp" ng-controller="MainCtrl">
<h1>Walking Dead Viewership</h1>
<div class="scatter-container">
<scatter
data="episodes"
accessor-x="d.air_date"
accessor-y="d.us_viewers"
selected-point="selectedEpisode"
color="color(d.season)">
</scatter>
</div>
<div class="detail">
<h2>Episode: {{selectedEpisode.title}}</h2>
<h3>season: {{selectedEpisode.season}}</h3>
<h3>us viewers: {{selectedEpisode.us_viewers | number}}</h3>
</div>
</body>
<script>
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope, $window){
$scope.color = d3.scale.category10();
angular.element($window).on('resize', function(){ $scope.$apply(); });
d3.csv('./episodes.csv', function(row){
row.season = +row.season; // number
row.air_date = new Date(row.air_date);
row.us_viewers = +row.us_viewers * 1e6; // us viwers in millions
return row;
}, function(err, episodes){
if(err){ throw err; }
$scope.$apply(function(){
// remove the few episodes that haven't air yet at time of writing.
episodes = episodes.slice(0, -3);
$scope.episodes = episodes;
$scope.selectedEpisode = episodes[0];
});
});
});
app.directive('scatter', function(){
function link(scope, el, attr){
el = el[0];
var w, h;
var svg = d3.select(el).append('svg');
var xAxisG = svg.append('g').attr('class', 'x-axis');
var yAxisG = svg.append('g').attr('class', 'y-axis');
var points = svg.append('g').attr('class', 'points').selectAll('g.point');
var x = d3.scale.linear();
var y = d3.scale.linear();
var yFormat = d3.format('.2s');
var timeFormat = d3.time.format('%m-%y');
var xFormat = function(d){ return timeFormat(new Date(d)) };
var xAxis = d3.svg.axis().scale(x).orient('bottom').tickFormat(xFormat);
var yAxis = d3.svg.axis().scale(y).orient('left').tickFormat(yFormat);
var m = 50;
scope.$watch(function(){
w = el.clientWidth;
h = el.clientHeight;
return w + h;
}, resize);
function resize(){
svg.attr({width: w, height: h});
x.range([m, w - m]);
y.range([h - m, m]);
xAxis.tickSize(-h + 2 * m);
yAxis.tickSize(-w + 2 * m);
xAxisG.attr('transform', 'translate(' + [0, y.range()[0] + 0.5] + ')');
yAxisG.attr('transform', 'translate(' + [x.range()[0], 0] + ')');
update();
}
scope.$watch('data', update);
function update(){
if(!scope.data){ return };
var data = scope.data;
var x_extent = d3.extent(data, function(d){ return scope.accessorX({d:d}) });
x.domain(x_extent);
var y_max = d3.max(data, function(d){ return scope.accessorY({d:d}) });
y.domain([0, y_max]);
points = points.data(data);
points.exit().remove();
var point = points.enter().append('g').attr('class', 'point');
point.append('circle').attr('r', 5)
.style('fill', function(d){ return scope.color({d:d}); })
.on('mouseover', function(d){
scope.$apply(function(){
scope.selectedPoint = d;
});
})
// update the position of all the points
points.attr('transform', function(d){
return 'translate(' + [x(scope.accessorX({d:d})), y(scope.accessorY({d:d}))] + ')';
});
xAxisG.call(xAxis);
yAxisG.call(yAxis);
};
}
return {
link: link,
restrict: 'E',
scope: { data: '=', accessorX: '&', accessorY: '&', color: '&', selectedPoint: '=' }
};
});
</script>
</html>
season,title,directed_by,written_by,air_date,us_viewers
1,Days Gone Bye,Frank Darabont,Teleplay by: Frank Darabont,2010-10-31,5.35
1,Guts,Michelle MacLaren,Frank Darabont,2010-11-07,4.71
1,Tell It to the Frogs,Gwyneth Horder-Payton,"Story by: Charles H. Eglee & Jack LoGiudice
Teleplay by: Charles H. Eglee & Jack LoGiudice and Frank Darabont",2010-11-14,5.07
1,Vatos,Johan Renck,Robert Kirkman,2010-11-21,4.75
1,Wildfire,Ernest Dickerson,Glen Mazzara,2010-11-28,5.56
1,TS-19,Guy Ferland,Adam Fierro and Frank Darabont,2010-12-05,5.97
2,What Lies Ahead,Ernest Dickerson & Gwyneth Horder-Payton,Ardeth Bey and Robert Kirkman,2011-10-16,7.26
2,Bloodletting,Ernest Dickerson,Glen Mazzara,2011-10-23,6.70
2,Save the Last One,Phil Abraham,Scott M. Gimple,2011-10-30,6.10
2,Cherokee Rose,Billy Gierhart,Evan Reilly,2011-11-06,6.29
2,Chupacabra,Guy Ferland,David Leslie Johnson,2011-11-13,6.12
2,Secrets,David Boyd,Angela Kang,2011-11-20,6.08
2,Pretty Much Dead Already,Michelle MacLaren,Scott M. Gimple,2011-11-27,6.62
2,Nebraska,Clark Johnson,Evan Reilly,2012-02-12,8.10
2,Triggerfinger,Billy Gierhart,David Leslie Johnson,2012-02-19,6.89
2,18 Miles Out,Ernest Dickerson,Scott M. Gimple & Glen Mazzara,2012-02-26,7.04
2,"Judge, Jury, Executioner",Greg Nicotero,Angela Kang,2012-03-04,6.77
2,Better Angels,Guy Ferland,Evan Reilly & Glen Mazzara,2012-03-11,6.89
2,Beside the Dying Fire,Ernest Dickerson,Robert Kirkman & Glen Mazzara,2012-03-18,8.99
3,Seed,Ernest Dickerson,Glen Mazzara,2012-10-14,10.87
3,Sick,Billy Gierhart,Nichole Beattie,2012-10-21,9.55
3,Walk with Me,Guy Ferland,Evan Reilly,2012-10-28,10.51
3,Killer Within,Guy Ferland,Sang Kyu Kim,2012-11-04,9.27
3,Say the Word,Greg Nicotero,Angela Kang,2012-11-11,10.37
3,Hounded,Dan Attias,Scott M. Gimple,2012-11-18,9.21
3,When the Dead Come Knocking,Dan Sackheim,Frank Renzulli,2012-11-25,10.43
3,Made to Suffer,Billy Gierhart,Robert Kirkman,2012-12-02,10.48
3,The Suicide King,Lesli Linka Glatter,Evan Reilly,2013-02-10,12.26
3,Home,Seith Mann,Nichole Beattie,2013-02-17,11.05
3,I Ain't a Judas,Greg Nicotero,Angela Kang,2013-02-24,11.01
3,Clear,Tricia Brock,Scott M. Gimple,2013-03-03,11.30
3,Arrow on the Doorpost,David Boyd,Ryan C. Coleman,2013-03-10,11.46
3,Prey,Stefan Schwartz,Glen Mazzara & Evan Reilly,2013-03-17,10.84
3,This Sorrowful Life,Greg Nicotero,Scott M. Gimple,2013-03-24,10.99
3,Welcome to the Tombs,Ernest Dickerson,Glen Mazzara,2013-03-31,12.42
4,30 Days Without an Accident,Greg Nicotero,Scott M. Gimple,2013-10-13,16.11
4,Infected,Guy Ferland,Angela Kang,2013-10-20,13.95
4,Isolation,Dan Sackheim,Robert Kirkman,2013-10-27,12.92
4,Indifference,Tricia Brock,Matthew Negrete,2013-11-03,13.31
4,Internment,David Boyd,Channing Powell,2013-11-10,12.20
4,Live Bait,Michael Uppendahl,Nichole Beattie,2013-11-17,12.00
4,Dead Weight,Jeremy Podeswa,Curtis Gwinn,2013-11-24,11.29
4,Too Far Gone,Ernest Dickerson,Seth Hoffman,2013-12-01,12.05
4,After,Greg Nicotero,Robert Kirkman,2014-02-09,15.76
4,Inmates,Tricia Brock,Matthew Negrete & Channing Powell,2014-02-16,13.34
4,Claimed,Seith Mann,Nichole Beattie & Seth Hoffman,2014-02-23,13.12
4,Still,Julius Ramsay,Angela Kang,2014-03-02,12.61
4,Alone,Ernest Dickerson,Curtis Gwinn,2014-03-09,12.65
4,The Grove,Michael Satrazemis,Scott M. Gimple,2014-03-16,
4,Us,David S. Goyer,,2014-03-23,
4,A,Michelle MacLaren,,2014-03-30,