Skip to content

Instantly share code, notes, and snippets.

@TiagoDevezas
Last active August 29, 2015 14:15
Show Gist options
  • Save TiagoDevezas/46b891dc390099cb86cd to your computer and use it in GitHub Desktop.
Save TiagoDevezas/46b891dc390099cb86cd to your computer and use it in GitHub Desktop.
PhotoFinish
<!doctype html>
<html>
<head>
<title>PhotoFinish</title>
<meta charset="utf-8">
<style>
svg {
background-color: #eee;
}
text {
fill: #2A363B;
}
.axis text {
font: 10px sans-serif;;
}
.label {
font: 12px sans-serif;
cursor: pointer;
opacity: 0;
}
.axis path,
.axis line {
fill: none;
stroke: #bbb;
shape-rendering: crispEdges;
stroke-width: 1px;
}
.x.axis path {
display: none;
}
.source {
stroke: #222;
stroke-width: 1px;
cursor: pointer;
}
.source.highlight, .source.winner {
stroke: #222;
stroke-width: 2px;
}
.label.highlight, .label.winner {
font-weight: bold;
opacity: 1;
/*fill: #E1F5C4;*/
}
line.finish {
fill: none;
stroke: #FF4E50;
stroke-width: 2px;
shape-rendering: crispEdges;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/colorbrewer.v1.min.js"></script>
</head>
<body>
<div id="viz">
</div>
<script>
// Load the CSV
d3.json('newspapers.json', photoFinish);
function photoFinish(data) {
// Set margins and dimensions
var margin = {top: 50, right: 50, bottom: 50, left: 100 };
var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
// format data
var dateFormat = d3.time.format("%H:%M:%S");
data.splice(15, data.length);
var data = d3.shuffle(data);
data.forEach(function(el) {
el.name = el.source
el.date = new Date(el.first_date);
el.count = +el.count;
});
var dateExtent = d3.extent(data, function(el) {
return el.date;
});
var maxCount = d3.max(data, function(el) {
return el.count;
});
var sources = data.map(function(el) {
return el.name
});
sources.push('');
// Create scales
xScale = d3.time.scale.utc().domain(dateExtent.reverse()).range([margin.left / 2, width - margin.right])
.nice(d3.time.hour);
//yScale = d3.scale.linear().domain([0, maxCount + 1]).range([height, 0]);
yScale = d3.scale.ordinal().domain(sources).rangeRoundBands([height, 0], 0, 0);
rScale = d3.scale.linear().domain([0, maxCount]).range([5, 10]);
colorScale = d3.scale.category20();
// Create x and y axis
xAxis = d3.svg.axis()
.scale(xScale)
//.tickFormat(dateFormat)
.orient('bottom');
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickValues(sources)
.tickSize(-width);
var svg = d3.select('#viz')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.left)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(' + 0 + ',' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
//.attr('transform', 'translate(' + 0 + ',' + 0 + ')')
.call(yAxis)
.selectAll('text')
.attr('y', - yScale.rangeBand() / 2);
var finishLine = svg.append('line')
.attr('class', 'finish')
.attr('x1', xScale(d3.min(dateExtent.reverse())))
.attr('y1', height)
.attr('x2', xScale(d3.min(dateExtent.reverse())))
.attr('y2', 0)
.style('opacity', 0);
//rData = d3.shuffle(data);
var groups = svg.selectAll('g.news')
.data(data)
.enter()
.append('g')
.attr('class', 'news')
.attr('transform', function(d) {
return 'translate(' + 0 + ',' + yScale(d.name) + ')'
})
.on('mouseover', highlight)
.on('mouseout', unHighlight);
groups.each(function(d, i) {
d3.select(this)
.append('circle')
.attr('class', 'source')
.attr('r', 5)
.style('fill', function(d, i) { return colorScale(d.name); })
.style('opacity', .85);
});
var circles = d3.selectAll('circle.source');
var t0 = groups
.transition()
.duration(2000)
.ease('cubic out-in')
//.delay(function(d, i) { return 100 * i})
.attr('transform', function(d) {
return 'translate(' + xScale(d.date) + ',' + yScale(d.name) + ')';
});
// var t1 = t0.transition()
// .attr('transform', function(d) {
// return 'translate(' + xScale(d.date) + ',' + yScale(d.count) + ')';
// });
var t1 = t0.transition()
.select('circle.source')
.attr('r', function(d) { return rScale(d.count);})
.each('end', drawLabels);
function drawLabels() {
var parentEl = this.parentElement;
d3.select(parentEl)
.append('text')
.attr('class', 'label')
.text(function(d) { return d.name; })
.attr('text-anchor', 'middle')
.attr('transform', function(d, i) {
return 'translate(' + 0 + ',' + (-rScale(d.count) - 5) + ')'
})
.classed('highlight winner', function(d) {
if(d.date === d3.min(dateExtent)) {
return true;
}
});
d3.select(this)
.classed('highlight winner', function(d) {
if(d.date === d3.min(dateExtent)) {
return true;
}
});
drawFinishLine();
}
function drawFinishLine() {
finishLine
.style('opacity', 1);
}
function highlight() {
var parentEl = this.parentElement;
d3.select(this).select('circle.source')
.classed('highlight', true);
d3.select(this).select('text.label')
.classed('highlight', true);
parentEl.appendChild(this);
}
function unHighlight() {
d3.select(this).select('circle.source')
.classed('highlight', false)
d3.select(this).select('text.label')
.classed('highlight', false)
}
}
</script>
</body>
</html>
name date count
Público Thu Jan 1 2015 21:30 10
Diário de Notícias Thu Jan 1 2015 15:23 5
Jornal de Notícias Thu Jan 1 2015 09:14 25
Expresso Thu Jan 1 2015 23:30 9
Correio da Manhã Thu Jan 1 2015 13:45 7
Observador Thu Jan 1 2015 23:10 9
iOnline Thu Jan 1 2015 06:05 1
RTP Thu Jan 1 2015 16:05 6
[{"source":"RTP","count":323,"first_date":"2014-12-05T07:52:46.000Z","first_id":2224},{"source":"O Jogo","count":871,"first_date":"2014-12-05T09:29:00.000Z","first_id":545},{"source":"TSF","count":127,"first_date":"2014-12-05T10:02:00.000Z","first_id":794},{"source":"Económico","count":20,"first_date":"2014-12-05T14:20:00.000Z","first_id":486},{"source":"Diário de Notícias","count":294,"first_date":"2014-12-05T15:56:00.000Z","first_id":63},{"source":"Sábado","count":395,"first_date":"2014-12-05T17:36:34.000Z","first_id":915},{"source":"iOnline","count":27,"first_date":"2014-12-05T22:00:00.000Z","first_id":175},{"source":"Porto Canal","count":29,"first_date":"2014-12-06T00:00:00.000Z","first_id":5097},{"source":"A Bola","count":680,"first_date":"2014-12-06T00:13:37.000Z","first_id":2400},{"source":"Maisfutebol","count":734,"first_date":"2014-12-06T00:41:00.000Z","first_id":696},{"source":"Correio da Manhã","count":188,"first_date":"2014-12-06T08:47:19.000Z","first_id":184},{"source":"Jornal de Notícias","count":123,"first_date":"2014-12-06T11:44:00.000Z","first_id":2817},{"source":"Record","count":895,"first_date":"2014-12-06T13:12:00.000Z","first_id":3509},{"source":"P3","count":17,"first_date":"2014-12-06T18:52:00.000Z","first_id":4821},{"source":"Público","count":97,"first_date":"2014-12-06T18:54:47.000Z","first_id":3833},{"source":"Expresso","count":26,"first_date":"2014-12-06T18:55:00.000Z","first_id":4806},{"source":"Observador","count":42,"first_date":"2014-12-06T19:13:46.000Z","first_id":3854},{"source":"Visão","count":46,"first_date":"2014-12-08T11:13:00.000Z","first_id":7082},{"source":"Sol","count":53,"first_date":"2014-12-09T20:41:42.000Z","first_id":11703},{"source":"31 da Armada","count":5,"first_date":"2014-12-09T21:37:00.000Z","first_id":12062},{"source":"O Insurgente","count":8,"first_date":"2014-12-10T23:59:24.000Z","first_id":15324},{"source":"The Guardian","count":9,"first_date":"2014-12-11T12:22:32.000Z","first_id":16678},{"source":"Antena 1","count":2,"first_date":"2014-12-12T18:05:56.000Z","first_id":20694},{"source":"El País","count":2,"first_date":"2014-12-15T07:54:41.000Z","first_id":25334},{"source":"Jornal de Negócios","count":5,"first_date":"2014-12-15T12:10:20.000Z","first_id":25727},{"source":"Corta-Fitas","count":1,"first_date":"2014-12-15T22:08:00.000Z","first_id":27281},{"source":"El Mundo","count":2,"first_date":"2014-12-19T16:43:36.000Z","first_id":40552},{"source":"BBC","count":2,"first_date":"2014-12-23T13:59:31.000Z","first_id":52178},{"source":"Aventar","count":3,"first_date":"2015-01-06T09:36:39.000Z","first_id":87043},{"source":"Diário Digital","count":105,"first_date":"2015-01-13T16:33:01.000Z","first_id":118743},{"source":"SAPO Desporto","count":452,"first_date":"2015-01-15T15:50:00.000Z","first_id":120921},{"source":"SAPO Notícias","count":239,"first_date":"2015-01-15T19:14:10.000Z","first_id":121570},{"source":"Renascença","count":5,"first_date":"2015-02-03T18:03:10.000Z","first_id":201200},{"source":"O JUMENTO","count":2,"first_date":"2015-02-08T00:00:00.000Z","first_id":239948},{"source":"Blasfémias","count":3,"first_date":"2015-02-13T09:40:56.000Z","first_id":243703},{"source":"TVI24","count":1,"first_date":"2015-02-13T20:02:00.000Z","first_id":246607},{"source":"Porto24","count":1,"first_date":"2015-02-14T12:34:52.396Z","first_id":248394}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment