After finishing the course Node.js Basics, I decided to take advantage of the fact that Team Treehouse allows you to access a user’s profile data in JSON format. One thing that seemed easy and doable in a day was making the donut chart displayed in the user’s profile.

Originally, I planned to use D3.js to make the donut chart but decided I’d use Canvas since I wanted some more expreince with it.

The Process

First, I needed to establish a basic HTML structure to hold the chart and data. This is how it looks like:

<div class="treehouse-dashboard">
  <div class="loader-container">
    <div id="loader"></div>
  </div>

  <div class="flex">
    <span class="flex-item">Name: <span class="treehouse-attr" id="treehouse-name"></span></span>
    <span class="flex-item">Username: <span class="treehouse-attr" id="username"></span></span>
    <span class="flex-item">Badges: <span class="treehouse-attr" id="badge-number"></span></span>
  </div>

  <div class="flex">
    <canvas id="canvas" width="300" height="300"></canvas>
    <div class="flex-item">
      <div class="flex courses-container">
      </div>
    </div>
  </div>
</div>

Pretty simple structure. Also, I discovered that setting the size of canvas vis CSS resulted in blurry graphics so the width and height need to be set in the HTML.

This was the SCSS:

#canvas{
	@include flex(0 0 300px); //flex: 0 0 300px;
}

.treehouse-dashboard{
	text-align: center;
	@extend .container; //max-width: 800px; margin: 0 auto;
}

.treehouse-attr{
	color: $second-color; //#dc5355;
}

.course{
	@include flex(1 25%); //flex: 1 25%;
	margin: $spacing-unit/6; //margin: 1.5rem / 6;
	padding: $spacing-unit/3; //margin: 1.5rem / 3;
	color: $white; //#F5F5F5;
}

And finally, the main part.

The JavaScript is fairly simple; there are only 4 functions and one main function to handle the ajax data call which I implemented using jQuery.

First thing I did was grabbed the canvas using vanilla JS and set the context to a variable like this:

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

The first function I include was a function to simplify the deg to rad conversion for the canvas arc function. Just one line:

var degToRad = function(deg){
	return deg * (Math.PI/180);
}

My plan was to calculate get the percentage of a given course relative to the donut chart. In other words, I had to calculate the percentage of the course by dividing the points of a course with the total points. Next, in order to know how long the arc should be, I used the calculated percentage to get the value from 360 (the circle).

For example, if I have a total of 250 points and my Javascript score was 100, the percentage would be 40%. Knowing that, I know that in the donut chart, JavaScript would occupy 40% of the circle. So 40% of 360 would be 144 meaning that the JavaScript arc should extend 144 degrees.

var calculatePercentage= function(value, total){
	return Math.ceil(Math.ceil(value/total * 100)/100 * 360);
}

I also need a function to obtain the values of an object. This was required in order to give each arc and course labels their respective color (I defined a color object that held the colors from the treehouse palette which I did not include in this post)

var getObjectValues = function(object, keys){
	var values = [];
	for(var i = 0; i < keys.length; i++){
		values[i] = object[keys[i]];
	}
	return values;
}

Lastly, here is the main function used to paint the chart onto the canvas. The function only bothers to draw if the course point total is above 1 else it is ignored. When the course points are more than one, the calculatePercentage function is called to get the arc length and stored in the variable percentage. Next the color is set for the corresponding course. The function then starts drawing at the prevDeg which initially is 0 and draws until the needed length. After it finishes drawing the current arc, the prevDeg gets updated in order for the next arc to continue from there.

var createDonutChart = function(keys, values, total){
  var prevDeg = 0;
  context.lineWidth = lineWidth;
	for(var i = 1; i < values.length; i++){
		if(values[i] > 1){
			var percentage = calculatePercentage(values[i], total) + 2;
			context.strokeStyle = colors[keys[i]];
			context.beginPath();
			context.arc(xVal, yVal, radius, degToRad(prevDeg), degToRad(prevDeg+percentage));
			context.stroke();
			context.closePath();
			prevDeg = prevDeg+percentage;
		}
	}
}

If you want to see the full source, head over to my github.