<div id="container">
<div id="chartcontainer">
<div id="title">
<h1>Doping in Professional Cycling</h1>
<h2>35 Fastest times up Alpe d'Huez</h2>
</div>
<div id="chart"></div>
</div>
<div id="credits">Code by <a href="http://lukewalker.org" target="_blank">Luke Walker</a> as my solution for this <a href="https://www.freecodecamp.com/challenges/visualize-data-with-a-scatterplot-graph" target="_blank">Free Code Camp project</a>. See all my Data Visualization Projects and notes on <a href="https://ubershibs.github.io/dataviz/">Github</a>.</div>
<div id="notes">
<h2>Notes & References</h2>
<ul>
<li>Relied on <a href="https://bl.ocks.org/d3noob/6f082f0e3b820b6bf68b78f2f7786084" target="_blank">this scatterplot example</a> as the basic pattern.</li>
<li><a href="https://bl.ocks.org/d3noob/23e42c8f67210ac6c678db2cd07a747e">This example</a> was helpful with axis labelling</li>
<li><a href="http://zeroviscosity.com/d3-js-step-by-step/step-3-adding-a-legend" target="_blank">This example</a> was helpful when it came to adding a legend.</li>
</ul>
</div>
</div>
body {
background-color: lightgray;
}
#chart {
width: 800px;
margin: 10px auto;
}
#notes {
font-family: sans-serif;
width: 700px;
margin: 10px auto;
padding-left: 50px;
}
#notes h2 {
display: block;
font-size: 20px;
font-weight: 700;
padding: 10px 0;
}
#notes ul {
list-style-type: disc;
}
#notes li {
margin-left: 20px
}
#credits {
font-family: sans-serif;
font-size: 14px;
width: 850px;
text-align: center;
margin: 20px auto;
border: 1px solid black;
padding: 5px;
background-color: white;
}
.line {
fill: none;
stroke: none;
stroke-width: 0;
}
.axisLabel {
font-family: sans-serif;
}
#title h1 {
font-size: 30px;
font-family: sans-serif;
text-align: center;
width: 100%;
}
#title h2 {
font-family: sans-serif;
font-size: 20px;
margin-top: 15px;
width: 100%;
text-align: center;
}
#chartcontainer {
margin-top: 20px;
}
.legend {
font-size: 16px;
font-family: sans-serif;
}
circle {
stroke-width: 2;
}
.name {
font-family: sans-serif;
font-size: 12px;
}
.tooltip {
position: absolute;
text-align: center;
width: 200px;
height: auto;
padding: 10px 5px;
font: 16px sans-serif;
background: #999;
border: 0px;
border-radius: 8px;
display: none;
opacity: 0.9;
color: white;
}
.tooltip div {
margin: 10px auto;
}
.mouseover {
fill: white;
stroke: black;
stroke-width: 2;
r: 10;
font-family: sans-serif;
font-size: 12px;
}
#chart {
background-color: white;
border: 1px solid black;
}
var dataUrl = 'https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/cyclist-data.json';
var margin = {top: 30, right: 100, bottom: 30, left: 30},
width = 700 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var tooltip = d3.select('body').append("div").attr("class", "tooltip");
var secondsToMinutes = function(s) {
var minutes = Math.floor(s/ 60);
var seconds = s % 60;
if (seconds < 10) {
seconds = '0' + seconds;
}
return(minutes + ':' + seconds);
}
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([0, height]);
var color = d3.scaleOrdinal(d3.schemeCategory10);
var valueline = d3.line()
.x(function(d) { return x(d.Seconds); })
.y(function(d) { return y(d.Place); });
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
$.get(dataUrl, function(response, status) {
var data = JSON.parse(response);
var zeroTime = data[0].Seconds;
data.forEach(function(d) {
d.Seconds = d.Seconds - zeroTime;
d.Place = +d.Place;
if (d.Doping != '') {
d.legend = "Doping allegations";
} else {
d.legend = "No doping allegations";
}
});
x.domain([200, 0]);
y.domain([1, 36]);
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d, i) { return color(d.legend); })
.attr("cx", function(d) { return x(d.Seconds); })
.attr("cy", function(d) { return y(d.Place); })
.on("mouseover", showTip)
.on("mouseout", hideTip);
svg.selectAll("text")
.data(data)
.enter().append("text")
.text(function(d) {
return d.Name;
})
.attr("class", "name")
.attr("x", function(d) { return x(d.Seconds); })
.attr("y", function(d) { return y(d.Place); })
.attr("transform", "translate(10,7)")
.on("mouseover", showTip)
.on("mouseout", showName);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.ticks(5)
.tickFormat(secondsToMinutes));
svg.append("text")
.attr("y", height - 20)
.attr("x", width - 210)
.attr("dy", "1em")
.attr("class", "axisLabel")
.text("Minutes Behind Fastest Time");
svg.append("g")
.call(d3.axisLeft(y))
svg.append("text")
.attr("transform", "rotate(90)")
.attr("y", -20)
.attr("x", 0)
.attr("dy", "1em")
.attr("class", "axisLabel")
.text("Rank");
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = 20;
var horz = 400;
var vert = i * height + 300;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('circle')
.attr('r', 5)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', 10)
.attr('y', 5)
.text(function(d) { return d; });
});
function showTip(d) {
var circle = d3.select(this);
circle.attr("class", "mouseover");
tooltip.html('<div>' + d.Name + ', ' + d.Nationality + '</div><div>Year: ' + d.Year + ', Time: ' + d.Time + '</div><div>' + d.Doping + '</div>' )
.style('left', (d3.event.pageX + 10) + 'px')
.style('top', (d3.event.pageY + 10) + 'px')
.style('display', 'block');
}
function hideTip(d) {
var circle = d3.select(this);
circle.attr('class', 'circle')
tooltip.style('display', 'none');
}
function showName(d) {
var name = d3.select(this);
name.attr('class', 'name')
tooltip.style('display', 'none');
}
Also see: Tab Triggers