Skip to content

Instantly share code, notes, and snippets.

@greaneym
Last active July 16, 2017 15:20
Show Gist options
  • Save greaneym/9e143318d54563be664c923a036faee9 to your computer and use it in GitHub Desktop.
Save greaneym/9e143318d54563be664c923a036faee9 to your computer and use it in GitHub Desktop.
fcc zipline using d3 for scatter plot
<!DOCTYPE html>
<meta charset="utf-8">
<title>FCC Zipline Scatter Plot using D3</title>
<style>
#header1 {
background: url("https://static.pexels.com/photos/248547/pexels-photo-248547.jpeg");
width:100%;
height: 90%;
background-size: cover;
z-index: -10;
}
html {
width:100%;
height: 100%;
font-color: white;
}
/*
.bg-img {
background: url('bikes.jpeg') center center no-repeat ;
width: 100%;
height: 100%;
background-size: cover; */
/* &:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-image: linear-gradient(to bottom right,#002f4b,#dc4225);
opacity: .6;
} */
}
body{
background-color: transparent;
font-color: white;
}
.container {
background-color: transparent;
position: absolute;
/* left:-200px%;
top:-500px;
left:200px;
top:500px; */
height:100%;
width:100%;
/ *border-style:solid;
border-width:2px;
border-color:green;
*/
}
.ttcontainer {
position: absolute;
left:300px;
top:500px;
stroke: #fff;
font-color: white;
border-style:solid;
border-width:2px;
border-color:black;
background-color: white;
z-axis: 200;
}
.axis path,
.axis line {
fill: none;
//fill: white;
stroke: #fff;
shape-rendering: crispEdges;
background-color: white;
}
.axistext {
font-family: sans-serif;
font-size: 10px;
stroke: #fff;
/* text-shadow: 2px 2px black; */
z-index:200;
}
g.axis, g.tick.text {
stroke: #fff;
}
div.tooltip {
position: absolute;
text-align: center;
left:250px;
width: 200px;
height: 70px;
padding: 2px;
font: 14px sans-serif;
font-style: bold;
background-color: white;
stroke: #fff;
border: 3px;
border-radius: 8px;
border-color: #3182bd;
z-index: 200;
}
.hidden {
display: none;
}
.legendtext {
font-family: sans-serif;
/* font-color: black; */
font-color: white;
font-size: 10px;
z-index:200;
}
.legendrect {
stroke-width: 2;
}
h1 {
color: white;
/* background-color: rgba(0, 0, 0, 0.7); */
background-color: rgba(0, 0, 0, 0.75);
/*padding-top: 0px;
padding-bottom: 0px;
padding-left: 0px;
padding-right: 0px; */
width: 100%;
height: 100%;
background-size: cover;
}
</style>
<body>
<!-- <script src="/d3new/d3.js"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script> -->
<!-- <script src="/camp/clock/dtest/d3.v4.js"></script> -->
<script>
//As a starting point used book “Interactive Data Visualization for the Web” by Scott Murray, published in March 2013 by O’Reilly.
//24_scatterplot_labels.html from chapter 6
// challenges for me since being away from d3.js for a while were,
// finding out the name replacements for functions in d3 v3 and d3 v5
// placing a background url that would not compete with text labels on graph
// placing text labels inside the margins that would not get clipped
// other challenge, background display with cover
//tooltips used from barchart on previous fcc zipline
//legend help from
//http://zeroviscosity.com/d3-js-step-by-step/step-3-adding-a-legend
//Width and height
var w = 550;
var h = 340;
var padding = 30;
var parseDate = d3.timeFormat("%Y-%m-%d %H:%M:%S").parse;
var now = new Date;
// Formatters for counts and times (converting numbers to Dates).
var formatCount = d3.format(",.0f"),
formatTime = d3.timeFormat("%H:%M"),
formatMinutes = function(d) { return formatTime(new Date(2012, 0, 1, 0, d)); };
var parseDate = d3.timeFormat("%Y-%m-%d %H:%M:%S");
var jdata = {};
var diff, fastTime,lastTime;
//d3.json("cyclist.json", function(error,data) {
d3.json("https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/cyclist-data.json", function(error,data) {
jdata = data;
jdata.forEach(function (d,i) {
//console.log('d,i',d,i);
d.raceTime = d.Time;
d.creat_time = parseDate(d.Time);
d.place = +d.Place;
d.secs = +d.Seconds;
if (i === 0) { fastTime = d.secs; }
d.name = d.Name;
d.year = d.Year;
//d.diff = fastTime - d.secs;
d.diff = d.secs - fastTime;
//console.log("d.diff",d.diff);
if (d.Doping === '') { d.class = "violation"; }
else { d.class = "no_violation"; }
if (i === 34) { lastTime = d.secs + 500;console.log("lastTime",lastTime); }
//console.log('jdata',jdata);
});
//Create scale functions
//var xScale = d3.scale.linear() //older version d3 use this
var xScale = d3.scaleTime()
.domain([d3.max(jdata, function(d) { return d.diff + 5; }),-3])
.range([padding, w - padding]);
//`var yScale = d3.scale.linear()
var yScale = d3.scaleLinear()
.domain([d3.max(jdata, function(d) { return d.place + 1; }),0])
.range([h - padding, padding]);
//var rScale = d3.scale.linear()
var rScale = d3.scaleLinear()
.domain([0, d3.max(jdata, function(d) {
//console.log("d3maxjdata", d3.max(jdata, function(d) { d.place;)});
//console.log("d3maxjdata",d.place);
return d.place; })])
.range([0, 35]);
//var x = d3.scale.linear()
var x = d3.scaleTime()
.range([0, w + 50])
.domain([5000,0]);
//var y = d3.scale.ordinal()
var y = d3.scaleLinear()
//.rangeRoundPoints([h-10,0])
//.rangeRoundPoints([35,0])
.range([35,0])
.domain(data.map(function(d){
//console.log("d.place in y domain",d.place);
return d.place;}));
//Define X axis
// var xAxis = d3.svg.axis()
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(6)
.tickFormat(formatMinutes);
//Define Y axis
//var yAxis = d3.svg.axis()
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(7);
//Create SVG element
var svg = d3.select("#container")
.append("svg")
.attr("width", w)
.attr("height", h);
var g = svg.append('g').attr('transform', 'translate(0,0)'); // use g for several appends
var div = d3.select("#container").append("div")
.attr("class", "tooltip")
.attr("fill", "white")
.style("opacity", 0);
//Create circles
svg.selectAll("circle")
.data(jdata)
.enter()
.append("circle")
.style("fill", function (d) {
if (d.class === "violation") {
return "green"; }
else if (d.class ==="no_violation") {
return "red"; };
})
.attr("cx", function(d) {
return xScale((d.diff));
})
.attr("cy", function(d) {
return yScale(d.place);
})
.attr("r", function(d) {
//console.log("r",Math.sqrt(h - d.place));
return 2;
})//;
.attr("transform", "translate(12," + 5 + ")")
.on("mouseover", function(d,i) {
div.transition(300)
.style("opacity", 1.0);
div .html(d.name + "<br>" + "Year: " + d.year + " Time: " + d.raceTime + "<br/>"+ d.Doping)
//.style("left", (d3.event.pageX) + "px")
//.style("top", (d3.event.pageY - 28) + "px")
.style("left", "352px")
.style("top", "202px")
.style("z-index", "200")
.style("font-color", "white")
.style("fill", "white")
.style("stroke", "white");
});
div.on("mouseout", function(d) {
div.transition()
.duration(20)
.style("opacity", 0);
});
//Create labels
svg.selectAll("text")
.data(jdata)
.enter()
.append("text")
.text(function(d) {
return d.name;
})
.attr("x", function(d) {
//return xScale(format(d.Time));
return xScale((d.diff));
//return d.diff;
})
.attr("y", function(d) {
return yScale(d.place);
})
.attr("font-family", "sans-serif")
.attr("font-size", "8px")
.attr("fill", "red")
.attr("transform", "translate(14," + 7 + ")");
//Create X axis
svg.append("g")
.attr("class", "axis")
//.attr("class", "axistext")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
//append titles and axis legends
var title = d3.selectAll("svg").append("g:text")
.attr('text-anchor', 'end')
.attr("x", 450)
.attr("y", 40)
.attr("class", "axistext")
.text("Doping in Professional Bike Racing");
var legend = d3.selectAll("svg").append("g:text")
.attr('text-anchor', 'end')
.attr("x", 350)
.attr("y", 338)
.attr("class", "axistext")
.attr("fill", "white")
.attr("z-index", "200")
.text("Minutes Behind Fastest Time")
.attr("fill", "white")
.attr("z-index", "200");
g.append('g')
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 2) //acts as x because rotated
.attr('x', -125)// acts as y because rotated
.attr('dy', '0.6em') //spacing from axis
.attr('text-anchor', 'end')
.attr("class", "axistext")
.text("Ranking");
var legendRectSize = 10;
var legendSpacing = 4;
var colorRules = d3.scaleOrdinal()
.domain(["violation", "no_violation"])
.range(["red", "green"]);
//color is not working so am using fill
var legendrect = svg.selectAll('svg')
.data(colorRules)
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
//console.log("legend height",height);
//var offset = height * color.domain().length / 2;
var offset = height * 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
svg.append('rect')
.attr('x', 375)
.attr('y', 280)
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', "red")
.style('stroke', 'white');
svg.append('text')
.attr('x', 390)
.attr('y', 288)
.attr("class", "legendtext")
.style('stroke', 'white')
.style('fill', 'white')
.text(function(d) { return "Doping Allegations Found"; });
svg.append('rect')
.attr('x', 375)
.attr('y', 290)
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', "green")
.style('stroke', 'white');
svg.append('text')
.attr('x', 390)
.attr('y', 300)
.attr("class", "legendtext")
.style('stroke', 'white')
.style('fill', 'white')
.text(function(d) { return "No Doping Allegations Found"; });
});
</script>
</body>
<div id="container" class="bg-img" alt="bike racing picture">
<div class="header">
<div class="overlay">
<div class="container" id="header1">
<h1></h1>
</div>
</div>
</div>
<div id="ttcontainer">
<div id="tooltip" class="hidden"> </div>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment