Website for visualizing a persons github network.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

242 lines
6.9 KiB

<html>
<head>
<title>Stack Overflow - Calendar Heatmap</title>
<style>
.body {
height: 97%;
}
svg {
height: 1800;
width: 97%;
}
</style>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous">
</script>
<script src="js/githubAPI.js"></script>
<script src="js/utilities.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-color/1.2.1/d3-color.js"></script>
</head>
<body>
<h3>Stack Overflow - Calendar Heatmap</h3>
<h4>Daily Commits to RITlug/teleirc</h4>
<svg id="svg"></svg>
<script>
function countCommitsPerDay(commits)
{
var reduce = [];
console.log(commits);
var current_date = new Date(commits[0].date);
current_date.setHours(0,0,0,0);
var current_count = 0;
for(var i = 1; i < commits.length; i++)
{
var d = new Date(commits[i].date);
d.setHours(0,0,0,0);
console.log(d);
if(current_date.getTime() == d.getTime())
{
console.log("Stonks");
current_count++;
}
else
{
reduce.push({Date:current_date.toISOString(), AnswerCount: current_count});
current_count = 1;
current_date = d;
}
reduce.push({Date:current_date.toISOString(), AnswerCount: current_count});
}
console.log(reduce);
return reduce;
}
function createHeatmapGraph(commits, containerID)
{
var sample = countCommitsPerDay(commits);
sample.sort((a, b) => new Date(a.Date) - new Date(b.Date));
const dateValues = sample.map(dv => ({
date: d3.timeDay(new Date(dv.Date)),
value: Number(dv.AnswerCount)
}));
const svg = d3.select("#" + containerID);
const { width, height } = document
.getElementById(containerID)
.getBoundingClientRect();
function draw() {
const years = d3
.nest()
.key(d => d.date.getUTCFullYear())
.entries(dateValues)
.reverse();
const values = dateValues.map(c => c.value);
const maxValue = d3.max(values);
const minValue = d3.min(values);
const cellSize = 15;
const yearHeight = cellSize * 7;
const group = svg.append("g");
const year = group
.selectAll("g")
.data(years)
.join("g")
.attr(
"transform",
(d, i) => `translate(50, ${yearHeight * i + cellSize * 1.5})`
);
year
.append("text")
.attr("x", -5)
.attr("y", -30)
.attr("text-anchor", "end")
.attr("font-size", 16)
.attr("font-weight", 550)
.attr("transform", "rotate(270)")
.text(d => d.key);
const formatDay = d =>
["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"][d.getUTCDay()];
const countDay = d => d.getUTCDay();
const timeWeek = d3.utcSunday;
const formatDate = d3.utcFormat("%x");
const colorFn = d3
.scaleSequential(d3.interpolateBuGn)
.domain([Math.floor(minValue) -1, Math.ceil(maxValue)]);
const format = d3.format("+.2%");
year
.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(d3.range(7).map(i => new Date(1995, 0, i)))
.join("text")
.attr("x", -5)
.attr("y", d => (countDay(d) + 0.5) * cellSize)
.attr("dy", "0.31em")
.attr("font-size", 12)
.text(formatDay);
year
.append("g")
.selectAll("rect")
.data(d => d.values)
.join("rect")
.attr("width", cellSize - 1.5)
.attr("height", cellSize - 1.5)
.attr(
"x",
(d, i) => timeWeek.count(d3.utcYear(d.date), d.date) * cellSize + 10
)
.attr("y", d => countDay(d.date) * cellSize + 0.5)
.attr("fill", d => colorFn(d.value))
.append("title")
.text(d => `${formatDate(d.date)}: ${d.value.toFixed(2)}`);
const legend = group
.append("g")
.attr(
"transform",
`translate(10, ${years.length * yearHeight + cellSize * 4})`
);
const categoriesCount = 10;
const categories = [...Array(categoriesCount)].map((_, i) => {
const upperBound = (maxValue / categoriesCount) * (i + 1);
const lowerBound = (maxValue / categoriesCount) * i;
return {
upperBound,
lowerBound,
color: d3.interpolateBuGn(upperBound / maxValue),
selected: true
};
});
const legendWidth = 60;
function toggle(legend) {
const { lowerBound, upperBound, selected } = legend;
legend.selected = !selected;
const highlightedDates = years.map(y => ({
key: y.key,
values: y.values.filter(
v => v.value > lowerBound && v.value <= upperBound
)
}));
year
.data(highlightedDates)
.selectAll("rect")
.data(d => d.values, d => d.date)
.transition()
.duration(500)
.attr("fill", d => (legend.selected ? colorFn(d.value) : "white"));
}
legend
.selectAll("rect")
.data(categories)
.enter()
.append("rect")
.attr("fill", d => d.color)
.attr("x", (d, i) => legendWidth * i)
.attr("width", legendWidth)
.attr("height", 15)
.on("click", toggle);
legend
.selectAll("text")
.data(categories)
.join("text")
.attr("transform", "rotate(90)")
.attr("y", (d, i) => -legendWidth * i)
.attr("dy", -30)
.attr("x", 18)
.attr("text-anchor", "start")
.attr("font-size", 11)
.text(d => `${d.lowerBound.toFixed(2)} - ${d.upperBound.toFixed(2)}`);
legend
.append("text")
.attr("dy", -5)
.attr("font-size", 14)
.attr("text-decoration", "underline");
}
draw();
}
getRepoCommits("torvalds/linux", (data)=>
{
console.log(data);
createHeatmapGraph(data, "svg");
},
(error)=>
{
console.log(error);
})
</script>
</body>
</html>