Skip to content

Instantly share code, notes, and snippets.

@barnettjw
Last active December 27, 2015 18:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barnettjw/7366985 to your computer and use it in GitHub Desktop.
Save barnettjw/7366985 to your computer and use it in GitHub Desktop.
Treehouse Acheivements Calendar
<div class = "activity-chart">
<h1>Treehouse Achievements Calendar</h1>
<ol class = "days-of-week">
<li>M</li>
<li>W</li>
<li>F</li>
</ol>
<div id = "month" class = "month"></div>
<div id = "days" class = "days"></div>
<div class = "key">
<span>Less</span>
<ul>
<li class = "activity-four"></li>
<li class = "activity-three"></li>
<li class = "activity-two"></li>
<li class = "activity"></li>
<li class = "day-key"></li>
</ul>
<span>More</span>
</div>
</div>
$(document).ready(function() {
var user = "jessicasideways";
//var user = "jamesbarnett";
$.getJSON("http://teamtreehouse.com/" + user + ".json", function(data) {
var dates = [];
var start_time = moment().subtract("year", 1);
/* because we are filtering by date, don't use the for loop counter because it will add in undefined items to the arry for each of the filtered items*/
var countBadges = 0;
for (var a in data.badges) {
if ((moment(data.badges[a].earned_date)).isAfter(moment(start_time))){
countBadges++;
dates[countBadges] = moment(data.badges[a].earned_date).format("MM-DD-YY");
}
}
var counted = compressArray(dates);
/*** draw months ***/
var month = moment();
var outputMonth = "<ol class = 'month'>";
for (i = 0; i <= 12; i++) {
var durationMonth = moment.duration({'months' : 1});
outputMonth += "<li>";
outputMonth += moment(month).format("MMM");
outputMonth += "</li>";
month = moment(month).subtract(durationMonth);
}
outputMonth += "</ol>";
var output = "<ol><div class = 'week'>";
var day = moment();
/* Calculate the offset for days of the week to line up correctly */
var dayOfWeekOffset = 6 - (parseInt(moment().format("d"),10));
/* draw offset */
for (i = 0; i < (dayOfWeekOffset); i++) { output += "<li class = 'offset'></li>"; }
/*** draw calendar ***/
var badgeHigh = 0;
for (i = 365; i >= 0; i--) {
var badges = "No";
var activity4 = false;
var activity3 = false;
var activity2 = false;
var activity = false;
checkDay = moment(day).format("MM-DD-YY");
/* find highest single day badge count */
for( b = 0; b < counted.length; b++) {
if (counted[b].value === checkDay)
{
badges = counted[b].count;
if( badges > badgeHigh){
badgeHigh = badges;
}
}}
/* apply activity colors relative to highest single day badge count */
for( c = 0; c < counted.length; c++) {
if (counted[c].value === checkDay)
{
badges = counted[c].count;
if (badges >= (Math.floor(badgeHigh * 0.75))){
activity4 = true;
}
else if (badges > (Math.floor(badgeHigh * 0.5))){
activity3 = true;
}
else if (badges > (Math.floor(badgeHigh * 0.25))){ activity2 = true;}
else {
activity = true;
}
}
}
/* stick date in data attribute so we can parse it later for filtering purposes */
var dataDate = moment(day).format("MM-DD-YY");
var li = "<li data-date = '" + checkDay + "' class =";
if(activity4 === true){ output += li + "'activity-four'>";}
else if(activity3 === true){ output += li + "'activity-three'>";}
else if(activity2 === true){ output += li + "'activity-two'>";}
else if(activity === true){ output += li + "'activity'>";}
else { output += li + "''>";}
output += '<span class = "tooltip"><span class = "bold">' + badges + " badges</span> earned on " + moment(day).format("MMMM Do YYYY") + '</span>';
output += "</li>";
var duration = moment.duration({'days' : 1});
day = moment(day).subtract(duration);
}
output += "</div></ol>";
document.getElementById("month").innerHTML = outputMonth;
document.getElementById("days").innerHTML = output;
/* parse which day was clicked */
var selectedDay = moment().format("MM-DD-YY");
$(".days li").click(function() {
selectedDay = ($(this).attr("data-date"));
console.log(selectedDay);
});
/*** streak count ***/
var streakOverall = 1;
var maxStreak = streakOverall;
for (var e = 0; e < counted.length; e++) {
var current = counted[e].value;
var next = current;
var tomorrow = moment(current).add("days", 1);
//don't overflow array by comparing last item
if((e + 1) < counted.length){
next = counted[(e + 1)].value;
}
// check if "next" item in array is the same day as the "current" item + 1 day
if (moment(next).isSame(moment(tomorrow), 'day')) {
streakOverall++;
}
else { streakOverall = 1; }
// check if current streak is longer than previous max streak
if (streakOverall > maxStreak) { maxStreak = streakOverall; }
}
console.log("max streak: " + maxStreak);
//######################################3
var streakCurrent = 1;
for (var f = counted.length - 1 ; f > 0; f--) {
var dayCurrent = counted[f].value;
var previous = dayCurrent;
//don't overflow array by comparing last item
if (f > 1){ previous = counted[(f - 1)].value; }
var yesterday = moment(dayCurrent).subtract("days", 1);
if (moment(previous).isSame(moment(yesterday), 'day')) { streakCurrent++; }
else { break; }
}
console.log("current streak: " + streakCurrent);
console.log("badge count: " + countBadges);
});
function compressArray(original) {
var compressed = [];
var copy = original.slice(0);
for (var i = 0; i < original.length; i++) {
var myCount = 0;
for (var w = 0; w < copy.length; w++) {
if (original[i] == copy[w]) {
myCount++;
delete copy[w];
}
}
if (myCount > 0) {
var a = {};
a.value = original[i];
a.count = myCount;
compressed.push(a);
}
}
return compressed;
}
});
ol, li { padding: 0; margin: 0; list-style: none;}
h1 {
font-size: 1.5em;
margin: 70px 75px;
}
.activity-chart, h1 {color: #525252;}
.days li, .day-key { background: #eee; }
.activity-chart {
width: 720px;
height: 205px;
padding-left: 110px; /* center in container */
margin: 50px 150px;
position: relative;
/*outline: solid;*/
}
/*** day of week heading ***/
.days-of-week {
width: 15px;
position: absolute;
left: -10px;
top: 80px;
}
@-moz-document url-prefix() {
.days-of-week { left: 23px; }
}
.days-of-week { font-size: 0.7em; }
.days-of-week li:nth-child(2) { margin: 13px 0; }
/*** month headings ***/
.month ol {
position: absolute;
top: 40px;
left: -30px;
}
.month li {
float: right;
margin-left: 39px;
font-size: 0.75em;
}
/*** draw days ***/
.days {
font-size: 0.75em;
margin-top: 15px;
float: right; /* needed to float onto screen */
}
/* offset so days of the week line up
over-specified to win specificity battle */
.activity-chart .offset:hover { outline: none; }
.activity-chart .offset { background: none; }
/* create vertical weeks */
.week {
width: 108px;
transform: rotate(90deg);
}
.days li, .key li {
width: 12px;
height: 12px;
float: right; /* order days starting at the bottom right */
}
.days .bold { font-weight: bold; }
.days li { margin: 1.5px; }
/*** color-code by activity level ***/
.activity-chart .activity { background: #d6e685; }
.activity-chart .activity-two { background: #8cc665; }
.activity-chart .activity-three { background: #44a340; }
.activity-chart .activity-four { background: #1e6823; }
.key {
position: absolute;
bottom: 0;
right: 55px;
}
.key ul {
display: inline-block;
margin: 0;
padding: 0;
}
.key li { margin: 0px 2px; }
/*** tooltips ***/
.days li .tooltip { display: none; }
.days li:hover
{
/*outline disabled due to firefox cross-broswer issue */
/*outline: 1px solid #555;*/
position: relative;
z-index: 3;
}
.days li:hover .tooltip {
transform: rotate(-90deg);
display: block;
position: absolute;
/* top & left are reversed because the calendar is rotated 90 deg */
top: -13px;
left: -185px;
width: 300px;
padding: 10px 5px;
text-align: center;
background-color: #333;
color: #f1f1f1;
}
/*** little triangle on the tooltip ***/
.tooltip:before {
content: "";
position: absolute;
width: 0;
height: 0;
bottom: -10px;
right: 150px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 11px solid #333;
}

Treehouse Acheivements Calendar

Gets Treehouse badge data as JSON and uses moment.js to create a github-like activity calendar.

A Pen by James Barnett on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment