
Data is the backbone of the web, and in the web’s early days, documents were shared between academic institutions. But large amounts of raw data can be hard to understand; this is where data visualisation comes in. All of a sudden great swathes of tabular data that were insurmountable are transformed into easily graspable graphics. Traditionally, <table>, <svg>, and <img> were the best ways to show this data but with the widespread adoption of HTML5 in browsers <canvas> is another, rich way to show data.
In this tutorial you’ll learn how to process data and turn it into delicious-looking charts using Chart.js by Nick Downie. Its documentation contains everything you’ll need to know and get started and you’ll soon have the confidence to integrate Chart.js with your own site and style it as you wish.
We’ll create a dashboard showing the population trends of 236 species of birds, as collected by the government during 1970 and 2010 (bit.ly/ZABlQg). This data set will push Chart.js’s performance capabilities and provide us with a few ways to visualise the data.
The Canvas element
Chart.js uses the HTML5 Canvas element to display it’s charts, so to start you need to make a Canvas on a new page. If you haven’t used Canvas before, fret not, there’s no need to handle the nitty gritty as the library handles that for us. Simply make a new Canvas element like any other HTML tag.
001 <main role=”main”> 002 <canvas id=”trends”></canvas> 003 </main>
Make Ajax request
Before you can visualise the data you need to get and parse the data in a way that Chart.js can use. This data is stored in an external file so you’ll need to send an Ajax request to retrieve it’s contents. You won’t be using jQuery so this is how an Ajax request looks in ‘vanilla’ JavaScript.
001 (function() {
002 var data; var url = ‘data/birds.csv’;
003 function makeRequest(url) {
004 var xhr = new XMLHttpRequest();
005 xhr.open(‘GET’, url);
006 xhr.onload = function() {
007 if (xhr.readyState === 4 && xhr.status === 200) {/*run code*/}
008 };
009 xhr.send(null);
010 }
011 })();
Easily parse CSV
Currently the data set is locked in a CSV (Comma-Separated Values) file which is commonly generated from spreadsheet programs. Thankfully there are a few libraries that will generate usable data structures (like arrays and objects) from it. The jQuery CSV plug-in is used here as it has a toArrays method. Then you can simply write:
001 data = CSV.toArrays(xhr.responseText);
Making data usable
toArrays() gives a structure that looks like [[‘Starling’,’100’,’78.6’],[‘Magpie’,[‘100’,’98’]] so each ‘row’ is a separate array. Next up is some pretty hairy-looking code that will convert all of the values from strings to numbers (specifically floats meaning that we can use decimal points) and convert empty values in our array to a 0.
001 for (var i = 0, len = data.length; i < len; i++) {
002 for (var j = 0, l = data[i].length; j < l; j++) {
003 if (!isNaN(parseFloat(data[i][j])))
004 data[i][j] = parseFloat(data[i][j]);
005 else if (!data[i][j].length)
006 data[i][j] = 0;
007 }
008 }
Nested for loops
The line chart takes an object that lists the labels and each data set separately like: labels: [“January”,”February”], data sets: [{data: [65,59]}, {data: [28,48]}]. To replicate this with your data, create a label for each year in your data set and then populate the data sets with an individual species’ data using a couple of for loops.
001 var years = []; 002 for (var i = 0; i < 2010-1970; i++) years. push([]); 003 for (var i = 0, len = data.length; i < len; i++) 004 for (var j = 0, l = data[i].length; j < l; j++) 005 if (j === 0) labels.push(data[i][j]); 006 else years[j-1].push(data[i] 007 [j]);
Looping through inputs
Data now contains a data set that we can use to compare species. To find out which bird’s data to get, read the value of each input and set a funky colour to both the bird data and the corresponding input. Setting a colour value for the input and bird will tell the user which bird relates to which colour.
001 var birds = document.
002 getElementsByClassName(‘bird-input’);
var datasets = [];
003 for (var i = 0, len = birds.length; i < len; i++) {
004 var bird = findBird(birds[i].value);
005 var colour = “rgba(80,116,3,0.5)”;
006 birds[i].style.background = colour;
007 }
Push the bird
Within the for loop of Step 6, you can push the data set with your configuration options and the data set for the individual bird. You can customise the fill, stroke, and point colours individually so that your chart can look as unique as your site’s style to tie in nicely. The colours can be in hex, RGB(A), or HSL(A).
001 datasets.push({
002 fillColor: colour,
003 strokeColor: “rgb(0,0,0)”,
004 pointColor: “rgb(0,0,0)”,
005 pointStrokeColor: “#fff”,
006 data: bird
007 });
Resulting data
This is a helper function that takes the name of a bird, finds it’s index in the labels array and returns the corresponding data set. The resulting graphData variable is the compiled data that Chart.js can read to create a line, bar or radar chart. If you’re hardcoding your labels and data set then an equal amount of each is needed.
001 var findBird = function(bird) {
002 var index = labels.indexOf(bird);
003 return data[index];
004 };
005 // [...]
006 var graphData = {
007 labels: labels,
008 datasets: datasets
009 };
Setting dimensions
Set the width and height to half the viewport width and as wide as the viewport or 960px (whichever fits). Then get the canvas’s rendering context and pass this to Chart.js. Using Chart.js all you have to do is tell it ‘I want a new chart (using this canvas) and I want it to be a Line chart (using this data), please’.
001 var graph = document. getElementById(‘trends’); 002 graph.height = window.innerHeight / 2; 003 graph.width = window.innerWidth > 960 ? 960 : window.innerWidth; 004 var ctx = graph.getContext(‘2d’), 005 chart = new Chart(ctx).Line(graphData);
Construct line chart
Refresh the page and before your eyes you should see the chart animate into life, rendering all those sexy data points. You can also pass a configuration object after the data to customise the chart, perhaps all of those animations aren’t for you? No problem. Or perhaps you don’t wish to label the Y axis. All of the options are listed at www.chartjs.org/docs/.
001 var chart = new Chart(ctx).Line(graphData, {
002 animation: false,
003 scaleShowLabels: false
004 });
Bar chart
Chart.js isn’t limited to just constructing simplistic line charts though. It also provides support for bar charts, radar charts, polar-area charts, pie charts, and doughnut charts. Using the same data as the line chart, you can swap line for bar and instantly your chart changes to a bar chart, the choice is yours.
001 var chart = new Chart(ctx).Bar(graphData);
Pie data
Next, create four pie charts, one to represent each decade, that will show the comparative success of the selected species of bird. It’s easy enough to create the pie chart with Chart.js but we have to massage the data so that Chart.js can make sense of it. This time it expects something that looks like:
001 var data = [{
002 value: 30,
003 color:”#F38630”
004 }, {
005 value : 50,
006 color : “#E0E4CC”
007 }];
Decades of data
To get the data you need, make four arrays that will contain the numbers for each bird per decade. This isn’t a very DRY (Don’t Repeat Yourself) approach but it serves the purpose. Iterate through each input, find the data for that particular bird and push each decade to it’s corresponding decade.
001 var pieData = [], 002 pieData2 = [], 003 pieData3 = [], 004 pieData4 = [];
Creating the data set
As we go through each bird, pull out the relevant data at the start of the decade. The pie chart needs one value per bird per decade so that the end result will look like [{ color: ‘rgba(x,y,z,0.5)’, value: 65.4 }, { color: ‘rgba(x,y,z,0.5)’, value: 23.5 }]. Even if the numbers don’t add up to 100 it’ll show the proportional amounts that number takes up compared to the other(s).
001 var inputs = document.
002 getElementsByClassName(‘bird-input’);
003 for (var i = 0, len = inputs.length; i < len; i++) {
004 var decade1 = {
005 color: inputs[i].style.backgroundColor,
006 value: graphData.datasets[i].data[1]
007 };
008 pieData.push(decade1);
009 }
Pie markup
Your new charts will also need somewhere to go so make a new Canvas element. Chart.js’s pie and doughnut charts do not support labels so you can add an <h2> with the name of the decade. Repeat this markup for each decade (1980s, 1990s, and 2000s) changing the ID for each one.
001 <div class=”decade”> 002 <h2>1970</h2> 003 <canvas id=”pieChart” class=”pie-chart”></ 004 canvas> 005 </div>
A middling position
To inject a little extra visual flair, you can position the text roughly in the middle of your pie chart. Remember that if you position a child object absolutely to a parent object that is relatively positioned then the absolutely positioned element will be relative to it’s parent, and not the page itself.
001 .decade {
002 position: relative;
003 }
004 .decade > h2 {
005 position: absolute;
006 left: 35%;
007 top: 42%;
008 }
Retina ready
Chart.js has built-in support for high-pixel-density devices, like Retina displays. So, all you have to worry about is how wide and high you would like the charts to be and it’ll internally do the maths to size them correctly (using devicePixelRatio) if viewed on high PPI devices.
001 var pies = document. getElementsByClassName(‘pie-chart’),
002 p = pies.length;
003 while (p--) {
004 pies[p].height = window.innerHeight / 2;
005 pies[p].width = 950 / 4;
006 }
Initiate pie
With your data in place you’ll initiate it in a similar way to the line chart, the only difference being pie instead of line. Refresh your browser and you should see a cute animation as the segments spin around, hits the other side as it comes full circle and bounces; I recommend that you view www.chartjs.org/ for the full effect.
001 var pCtx = document. getElementById(‘pieChart’). getContext(‘2d’), 002 pie = new Chart(pCtx).Pie(pieData);
Switching out charts
Pie charts are nice but we’re going to switch it out for the lesser-used and inherently cooler doughnut chart. These types of charts display your data in the exact same way as a pie chart – the only difference is that the middle segment is cut out so our <h2>s can stand out a little bit more. Similarly, you could also use the same data to create a polar-area chart.
001 var doughnut = new Chart(pCtx).
002 Doughnut(pieData);
003 var polarArea = new Chart(pCtx2).
004 PolarArea(pieData, {
005 segmentStrokeColor: ‘rgba(0,0,0,0.5)’,
segmentStrokeWidth: 1
});
Dashboard recap
Your dashboard is functional and you’ve seen how to use a fairly complicated data set and visualise it using Chart.js. Check out the disc included with this issue for some extra bits of code to ensure colours aren’t repeated in charts and the ability to add more inputs, meaning graphs can change and reanimate on the fly.
Radar chart
The final chart type that we haven’t looked at yet is the radar chart. This accepts the same-looking data set as the line and bar charts (ie with labels). Radar charts are a really good way to show multiple data points and the differences between them within two or more data sets.
001 var radarData = {
002 labels: [‘Flying’, ‘Nesting’, ‘Eating’, ‘Noisiness’, ‘Annoyance Rating’],
003 datasets: [{
004 data: [65,59,90,81,56]
005 }, {
006 data: [78,48,40,83,96]
007 }]
008 };
009 var radar = new Chart(ctx).Radar(radarData, { pointDot: false });
Get charting!
So far you will have covered Chart.js’s six types of charts, it’s a neat little library that lends itself well to attractive, simple charts. It’s definitely well suited to blogs, product pages and anywhere you want some pizzazz. If you’re looking for interactive charts or a library with a bit more customisation behind it then Highcharts (www.highcharts.com) is a good recommendation, but Chart.js is definitely a strong contender.