|
|
- <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>
|