Last active
February 22, 2018 21:21
-
-
Save pmarshall111/d6234abcc757237092815d3c5995537b to your computer and use it in GitHub Desktop.
Github Contributions Graph made with D3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>JS Bin</title> | |
<style> | |
.tooltip { | |
position: absolute; | |
background: #333; | |
color: #ddd; | |
border: 3px solid #ddd; | |
border-radius: 2px; | |
pointer-events: none; | |
padding: 0.25em | |
} | |
.y-axis path { | |
transform: scaleY(1.5) translateY(-30%) | |
} | |
</style> | |
</head> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<body> | |
<svg height="300" width="900"></svg> | |
<script> | |
var testData = []; | |
for (var i = 1; i < 100; i++) { | |
var randomMonth = Math.floor(Math.random() * 12) + 1; | |
var randomDay = Math.floor(Math.random() * 28) + 1; | |
var randomNumb = Math.floor(Math.random() * 10); | |
var createdDate = new Date(`2018-${randomMonth}-${randomDay}`); | |
if (testData.filter(x => x.date == createdDate).length > 0) continue; | |
testData.push({ | |
date: createdDate, | |
numb: randomNumb | |
}); | |
} | |
//creating tooltip | |
var div = d3 | |
.select("body") | |
.append("div") | |
.classed("tooltip", true) | |
.style("opacity", 0); | |
var svg = d3.select("svg"); | |
var height = +svg.attr("height"); | |
var width = +svg.attr("width"); | |
var padding = 50; | |
var g = svg | |
.append("g") | |
.style("transform", `translate(${padding}px, ${padding}px)`); | |
var today = new Date(); | |
var oneYearAgo = new Date(); | |
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); | |
var cellSize = (width - padding * 2) / 53; | |
//setting positions of the ticks to be halfway between boundaries | |
var yAxisRange = []; | |
for (let i = 1; i < 7; i += 2) { | |
yAxisRange.push(cellSize / 2 + cellSize * i); | |
} | |
var yAxis = d3 | |
.scaleOrdinal() | |
.range(yAxisRange) | |
.domain(["Mon", "Wed", "Fri"]); | |
var xAxis = d3 | |
.scaleTime() | |
.range([0, width - padding * 2]) | |
.domain([oneYearAgo, today]); | |
var xAxisLine = g | |
.append("g") | |
.style("transform", `translate(0px, ${cellSize * 8}px)`) | |
.call(d3.axisBottom(xAxis)); | |
var yAxisLine = g | |
.append("g") | |
.style("transform", `translate(-${cellSize}px, 0px)`) | |
.classed("y-axis", true) | |
.call(d3.axisLeft(yAxis)); | |
//adding extra ticks for Tuesday and Thursday | |
for (let y = 0; y < 2; y++) { | |
let g = yAxisLine | |
.append("g") | |
.classed("tick", true) | |
.attr("transform", `translate(0, ${cellSize * (2 + 2 * y) + cellSize / 2})`) | |
.attr("opacity", 1); | |
g | |
.append("line") | |
.attr("x2", -4) | |
.attr("stroke", "#000"); | |
} | |
var rect = g | |
.selectAll("rect") | |
.data(d => d3.timeDays(oneYearAgo, today)) | |
.enter() | |
.append("rect") | |
.attr("stroke", "black") | |
.attr("fill", "transparent") | |
.attr("width", cellSize) | |
.attr("height", cellSize) | |
.attr("x", function(d) { | |
//gets num weeks between one year ago and date of current rect | |
return d3.timeWeek.count(oneYearAgo, d) * cellSize; | |
}) | |
.attr("y", function(d) { | |
return d.getDay() * cellSize; | |
}) | |
.on("mouseover", function(d) { | |
var text = this.getAttribute("data-info"); | |
if (!text) text = "0 contributions."; | |
div | |
.html(text) | |
.style("left", d3.event.pageX + "px") | |
.style("top", d3.event.pageY - 32 + "px"); | |
div | |
.transition() | |
.duration(100) | |
.style("opacity", 1); | |
}) | |
.on("mouseout", d => { | |
div | |
.transition() | |
.duration(100) | |
.style("opacity", 0); | |
}); | |
//adding colours | |
var maxMin = d3.extent(testData, x => x.numb); | |
var colours = new Array(5) | |
.fill("abc") | |
.map((x, i) => `hsl(60, ${100 * (5 - i) / 5}%, 50%)`); | |
var colourScale = d3 | |
.scaleQuantize() | |
.domain(maxMin) | |
.range(colours); | |
testData.forEach(entry => { | |
var indiv = rect.filter( | |
d => | |
d.getDate() == entry.date.getDate() && | |
d.getMonth() == entry.date.getMonth() | |
); | |
indiv | |
.attr("fill", colourScale(entry.numb)) | |
.attr("data-info", `${entry.numb} contributions.`); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment