Developing a PieChart in HTML5 Using Canvas

Introduction

 
This article shows how to use the HTML5 canvas element to create a simple Pie Chart.
 

What is a Pie Chart?

 
A Pie Chart or a Circular Graph is used to represent data graphically. It gets its name by how it looks, just like a circular pie that has been divided into several slices. A Pie Chart is helpful when graphing qualitative data where the information describes a trait or attribute. But it does not describe numerical information. Each attribute represents a different slice of the pie.
 
It is a circular chart that is divided into sectors.
 

Use of Pie Chart

 
Pie Charts are widely used in the business world and the mass media.
 
The disadvantage of Pie Charts
  • It cannot show more than a few values without separating the "slices" from the data they represent. When slices become too small, Pie Charts must rely on colors, textures or arrows so the reader can understand them. This makes them unsuitable for use with larger amounts of data.
  • Pie Charts also take up a larger amount of space on the page compared to bar charts, that do not need to have separate legends, and can also display other values such as averages or targets at the same time.
Step 1
 
We first define the element using the canvas tag. Note that the id, height, and width are a must.
 
<canvas id="myCanvas" width="600" height="300" style="border: 1px solid black;"></canvas>
 
Step 2
 
In order to interact with this canvas through JavaScript, we will need to first get the element by Id and then create a context.
  1. <script type="text/javascript">  
  2.     var canvas = document.getElementById('mycanvas');  
  3.     var ctx = canvas.getContext("2d");  
  4. </script> 
Step 3
 
In the following we will create a "PieChart()" function in which we define the variables, methods, properties and constants.
  1. function PieChart(canvasId, data) {  
  2.             // user defined properties  
  3.             this.canvas = document.getElementById(canvasId);  
  4.             this.data = data;  
  5.    
  6.             // constants  
  7.             this.padding = 10;  
  8.             this.legendBorder = 2;  
  9.             this.pieBorder = 5;  
  10.             this.colorLabelSize = 20;  
  11.             this.borderColor = "#555";  
  12.             this.shadowColor = "#777";  
  13.             this.shadowBlur = 10;  
  14.             this.shadowX = 2;  
  15.             this.shadowY = 2;  
  16.             this.font = "16pt Calibri";  
  17.    
  18.             // relationships  
  19.             thisthis.context = this.canvas.getContext("2d");  
  20.             thisthis.legendWidth = this.getLegendWidth();  
  21.             thisthis.legendX = this.canvas.width - this.legendWidth;  
  22.             thisthis.legendY = this.padding;  
  23.             this.pieAreaWidth = (this.canvas.width - this.legendWidth);  
  24.             thisthis.pieAreaHeight = this.canvas.height;  
  25.             thisthis.pieX = this.pieAreaWidth / 2;  
  26.             thisthis.pieY = this.pieAreaHeight / 2;  
  27.             this.pieRadius = (Math.min(this.pieAreaWidth, this.pieAreaHeight) / 2) - (this.padding);  
  28.    
  29.             // draw Pie Chart  
  30.             this.drawPieBorder();  
  31.             this.drawSlices();  
  32.             this.drawLegend();  
  33.         } 
Step 4
 
In the following we get the legend width on the basis of the size of the label text. After getting the legend width we will apply the loop through all the labels and determine which label is longest. In this step we will determine the label width.
  1. PieChart.prototype.getLegendWidth = function ()  
  2. {  
  3.    thisthis.context.font = this.font;  
  4.    var labelWidth = 0;  
  5.    
  6.    for (var n = 0; n < this.data.length; n++)  
  7.      {  
  8.        var label = this.data[n].label;  
  9.        labelWidth = Math.max(labelWidth, this.context.measureText(label).width);  
  10.      }  
  11.    
  12.    return labelWidth + (this.padding * 2) + this.legendBorder + this.colorLabelSize;  
  13. }; 
Step 5
 
In the following we will draw the Pie Chart border and apply the properties (such as fillStyle):
  1. PieChart.prototype.drawPieBorder = function ()  
  2. {  
  3.    var context = this.context;  
  4.    context.save();  
  5.    context.fillStyle = "white";  
  6.    context.shadowColor = this.shadowColor;  
  7.    context.shadowBlur = this.shadowBlur;  
  8.    context.shadowOffsetX = this.shadowX;  
  9.    context.shadowOffsetY = this.shadowY;  
  10.    context.beginPath();  
  11.    context.arc(this.pieX, this.pieY, this.pieRadius + this.pieBorder, 0, Math.PI * 2, false);  
  12.    context.fill();  
  13.    context.closePath();  
  14.    context.restore();  
  15. }; 
Step 6
 
In the following we will draw the slices of a Pie Chart.
  1. PieChart.prototype.drawSlices = function ()  
  2. {  
  3.    var context = this.context;  
  4.    context.save();  
  5.    var total = this.getTotalValue();  
  6.    var startAngle = 0;  
  7.    for (var n = 0; n < this.data.length; n++) {  
  8.        var slice = this.data[n];  
  9.    
  10.        // draw slice  
  11.        var sliceAngle = 2 * Math.PI * slice.value / total;  
  12.        var endAngle = startAngle + sliceAngle;  
  13.    
  14.        context.beginPath();  
  15.        context.moveTo(this.pieX, this.pieY);  
  16.        context.arc(this.pieX, this.pieY, this.pieRadius, startAngle, endAngle, false);  
  17.        context.fillStyle = slice.color;  
  18.        context.fill();  
  19.        context.closePath();  
  20.        startAngle = endAngle;  
  21.    }  
  22.    context.restore();  
  23. }; 
Step 7
 
In the following, we will get the total value of the Labels through the data by applying a loop and then adding up each value.
  1. PieChart.prototype.getTotalValue = function ()  
  2. {  
  3.    var data = this.data;  
  4.    var total = 0;  
  5.    
  6.    for (var n = 0; n < data.length; n++)  
  7.      {  
  8.        total += data[n].value;  
  9.      }  
  10.    
  11.    return total;  
  12. }; 
Step 8
 
In the following, we willfirst draw the legend and after that draw the legend labels.
  1. PieChart.prototype.drawLegend = function ()  
  2. {  
  3.    var context = this.context;  
  4.    context.save();  
  5.    var labelX = this.legendX;  
  6.    var labelY = this.legendY;  
  7.    
  8.    context.strokeStyle = "black";  
  9.    context.lineWidth = this.legendBorder;  
  10.    context.font = this.font;  
  11.    context.textBaseline = "middle";  
  12.    
  13.    for (var n = 0; n < this.data.length; n++) {  
  14.        var slice = this.data[n];  
  15.    
  16.        // draw legend label  
  17.        context.beginPath();  
  18.        context.rect(labelX, labelY, this.colorLabelSize, this.colorLabelSize);  
  19.        context.closePath();  
  20.        context.fillStyle = slice.color;  
  21.        context.fill();  
  22.        context.stroke();  
  23.    
  24.        context.fillStyle = "black";  
  25.        context.fillText(slice.label, labelX + this.colorLabelSize + this.padding, labelY + this.colorLabelSize / 2);  
  26.    
  27.        labelY += this.colorLabelSize + this.padding;  
  28.    }  
  29.    context.restore();  
  30. }; 
Step 9
 
In the following, window onload we will call the PieChart() function that brings the slices together.
  1. window.onload = function ()  
  2. {  
  3.    var data = [{  
  4.        label: "Eating",  
  5.        value: 4,  
  6.        color: "red"  
  7.    }, {  
  8.        label: "Working",  
  9.        value: 8,  
  10.        color: "blue"  
  11.    }, {  
  12.        label: "Sleeping",  
  13.        value: 8,  
  14.        color: "green"  
  15.    }, {  
  16.        label: "Playing]",  
  17.        value: 4,  
  18.        color: "yellow"  
  19.    }, {  
  20.        label: "Entertainment",  
  21.        value: 3,  
  22.        color: "violet"  
  23.    }];  
  24.    
  25.    new PieChart("myCanvas", data);  
  26. }; 
Example
  1. <!DOCTYPE html>  
  2.    
  3. <html lang="en" xmlns="http://www.w3.org/1999/xhtml">  
  4. <head>  
  5.     <meta charset="utf-8" />  
  6.     <title>Pie Chart in HTML5</title>  
  7.     <script>  
  8.    
  9.         function PieChart(canvasId, data) {  
  10.             // user defined properties  
  11.             this.canvas = document.getElementById(canvasId);  
  12.             this.data = data;  
  13.    
  14.             // constants  
  15.             this.padding = 10;  
  16.             this.legendBorder = 2;  
  17.             this.pieBorder = 5;  
  18.             this.colorLabelSize = 20;  
  19.             this.borderColor = "#555";  
  20.             this.shadowColor = "#777";  
  21.             this.shadowBlur = 10;  
  22.             this.shadowX = 2;  
  23.             this.shadowY = 2;  
  24.             this.font = "16pt Calibri";  
  25.    
  26.             // relationships  
  27.             thisthis.context = this.canvas.getContext("2d");  
  28.             thisthis.legendWidth = this.getLegendWidth();  
  29.             thisthis.legendX = this.canvas.width - this.legendWidth;  
  30.             thisthis.legendY = this.padding;  
  31.             this.pieAreaWidth = (this.canvas.width - this.legendWidth);  
  32.             thisthis.pieAreaHeight = this.canvas.height;  
  33.             thisthis.pieX = this.pieAreaWidth / 2;  
  34.             thisthis.pieY = this.pieAreaHeight / 2;  
  35.             this.pieRadius = (Math.min(this.pieAreaWidth, this.pieAreaHeight) / 2) - (this.padding);  
  36.    
  37.             // draw Pie Chart  
  38.             this.drawPieBorder();  
  39.             this.drawSlices();  
  40.             this.drawLegend();  
  41.         }  
  42.    
  43.         PieChart.prototype.getLegendWidth = function () {  
  44.    
  45.             thisthis.context.font = this.font;  
  46.             var labelWidth = 0;  
  47.    
  48.             for (var n = 0; n < this.data.length; n++) {  
  49.                 var label = this.data[n].label;  
  50.                 labelWidth = Math.max(labelWidth, this.context.measureText(label).width);  
  51.             }  
  52.    
  53.             return labelWidth + (this.padding * 2) + this.legendBorder + this.colorLabelSize;  
  54.         };  
  55.    
  56.         PieChart.prototype.drawPieBorder = function () {  
  57.             var context = this.context;  
  58.             context.save();  
  59.             context.fillStyle = "white";  
  60.             context.shadowColor = this.shadowColor;  
  61.             context.shadowBlur = this.shadowBlur;  
  62.             context.shadowOffsetX = this.shadowX;  
  63.             context.shadowOffsetY = this.shadowY;  
  64.             context.beginPath();  
  65.             context.arc(this.pieX, this.pieY, this.pieRadius + this.pieBorder, 0, Math.PI * 2, false);  
  66.             context.fill();  
  67.             context.closePath();  
  68.             context.restore();  
  69.         };  
  70.    
  71.         PieChart.prototype.drawSlices = function () {  
  72.             var context = this.context;  
  73.             context.save();  
  74.             var total = this.getTotalValue();  
  75.             var startAngle = 0;  
  76.             for (var n = 0; n < this.data.length; n++) {  
  77.                 var slice = this.data[n];  
  78.    
  79.                 // draw slice  
  80.                 var sliceAngle = 2 * Math.PI * slice.value / total;  
  81.                 var endAngle = startAngle + sliceAngle;  
  82.    
  83.                 context.beginPath();  
  84.                 context.moveTo(this.pieX, this.pieY);  
  85.                 context.arc(this.pieX, this.pieY, this.pieRadius, startAngle, endAngle, false);  
  86.                 context.fillStyle = slice.color;  
  87.                 context.fill();  
  88.                 context.closePath();  
  89.                 startAngle = endAngle;  
  90.             }  
  91.             context.restore();  
  92.         };  
  93.    
  94.         PieChart.prototype.getTotalValue = function () {  
  95.             var data = this.data;  
  96.             var total = 0;  
  97.    
  98.             for (var n = 0; n < data.length; n++) {  
  99.                 total += data[n].value;  
  100.             }  
  101.    
  102.             return total;  
  103.         };  
  104.    
  105.         PieChart.prototype.drawLegend = function () {  
  106.             var context = this.context;  
  107.             context.save();  
  108.             var labelX = this.legendX;  
  109.             var labelY = this.legendY;  
  110.    
  111.             context.strokeStyle = "black";  
  112.             context.lineWidth = this.legendBorder;  
  113.             context.font = this.font;  
  114.             context.textBaseline = "middle";  
  115.    
  116.             for (var n = 0; n < this.data.length; n++) {  
  117.                 var slice = this.data[n];  
  118.    
  119.                 // draw legend label  
  120.                 context.beginPath();  
  121.                 context.rect(labelX, labelY, this.colorLabelSize, this.colorLabelSize);  
  122.                 context.closePath();  
  123.                 context.fillStyle = slice.color;  
  124.                 context.fill();  
  125.                 context.stroke();  
  126.    
  127.                 context.fillStyle = "black";  
  128.                 context.fillText(slice.label, labelX + this.colorLabelSize + this.padding, labelY + this.colorLabelSize / 2);  
  129.    
  130.                 labelY += this.colorLabelSize + this.padding;  
  131.             }  
  132.             context.restore();  
  133.         };  
  134.    
  135.         window.onload = function () {  
  136.             var data = [{  
  137.                 label: "Eating",  
  138.                 value: 4,  
  139.                 color: "red"  
  140.             }, {  
  141.                 label: "Working",  
  142.                 value: 8,  
  143.                 color: "blue"  
  144.             }, {  
  145.                 label: "Sleeping",  
  146.                 value: 8,  
  147.                 color: "green"  
  148.             }, {  
  149.                 label: "Playing",  
  150.                 value: 4,  
  151.                 color: "yellow"  
  152.             }, {  
  153.                 label: "Entertainment",  
  154.                 value: 3,  
  155.                 color: "violet"  
  156.             }];  
  157.    
  158.             new PieChart("myCanvas", data);  
  159.         };  
  160.     </script>  
  161. </head>  
  162. <body>  
  163.     <canvas id="myCanvas" width="600" height="300" style="border: 1px solid black;"></canvas>  
  164. </body>  
  165. </html> 
Output
 
pie.jpg