1. Web Design
  2. HTML/CSS
  3. HTML

How to Draw Bar Charts Using JavaScript and HTML5 Canvas

Scroll to top
Final product imageFinal product imageFinal product image
What You'll Be Creating

In an earlier tutorial, we covered how to draw a pie chart or doughnut chart using HTML5 canvas. In this tutorial, I will show you how to use JavaScript and the HTML5 canvas to graphically display data by using bar charts.

What Is a Bar Chart?

Bar charts are very common tools used to represent numerical data. From financial reports to PowerPoint presentations to infographics, bar charts are used very often since they offer a view of numerical data that is very easy to understand.

Bar charts represent numerical data using bars, which are rectangles with either their widths or heights proportional to the numerical data that they represent.

There are many types of bar charts, for example:

  • horizontal bar charts and vertical bar charts depending on the chart orientation
  • stacked bar charts or classic bar charts for representing multiple series of data
  • 2D or 3D bar charts

What Are the Components of a Bar Chart?

Let's take a look at the components that make up a bar chart, regardless of its type:

Bar Chart InfographicBar Chart InfographicBar Chart Infographic
  • The chart data: these are sets of numbers and associated categories which are represented by the chart.
  • Name of the data series (1).
  • The chart grid (2): gives a reference system so that the visual representation can be easily understood.
  • The bars (3): color-filled rectangles with dimensions proportional to the data represented.
  • Chart legend (4): shows the correspondence between the colors used and the data they represent.

Now that we know the components of a bar chart, let's see how we can write the JavaScript code to draw a chart like this.

Drawing the Bar Chart Using JavaScript

Setting Up the JS Project

To start drawing using JavaScript and the HTML5 canvas, we will need to set up our project like this:

  • Create a folder to hold the project files; let's call this folder bar-chart-tutorial.
  • Inside the project folder, create a file and call it index.html. This will contain our HTML code.
  • Also inside the project folder, create a file and call it script.js. This will contain the JavaScript code for drawing the bar chart.

We'll keep things very simple and add the following code in index.html:

1
<html>
2
<body>
3
    <canvas id="myCanvas"></canvas>
4
    <script type="text/javascript" src="script.js"></script>
5
</body>
6
</html>

We have the <canvas> element with the ID myCanvas so that we can reference it in our JS code. We then load the JS code via the <script> tag.

Add the following code in the script.js file:

1
var myCanvas = document.getElementById("myCanvas");
2
myCanvas.width = 500;
3
myCanvas.height = 500;
4
 
5
var ctx = myCanvas.getContext("2d");

This gets a reference to the canvas element and then sets the width and height to 300px. To draw on the canvas, we only need a reference to its 2D context, which contains all the drawing methods.

Adding a Few Helper Functions

Drawing the bar chart only requires knowing how to draw two elements:

  • drawing a line: for drawing the grid lines
  • drawing a color-filled rectangle: for drawing the bars of the chart

Let's create the helper JS functions for these two elements. We will add the functions in our script.js file.

1
function drawLine(ctx, startX, startY, endX, endY,color){
2
    ctx.save();
3
    ctx.strokeStyle = color;
4
    ctx.beginPath();
5
    ctx.moveTo(startX,startY);
6
    ctx.lineTo(endX,endY);
7
    ctx.stroke();
8
    ctx.restore();
9
}

The drawLine function takes six parameters:

  1. ctx: reference to the drawing context
  2. startX: the X coordinate of the line starting point
  3. startY: the Y coordinate of the line starting point
  4. endX: the X coordinate of the line end point
  5. endY: the Y coordinate of the line end point
  6. color: the color of the line

We are modifying the color settings for the strokeStyle. This determines the color used to draw the line. We use ctx.save() and ctx.restore() so that we don't affect the colors used outside this function.

We draw the line by calling beginPath(). This informs the drawing context that we are starting to draw something new on the canvas. We use moveTo() to set the starting point, call lineTo() to indicate the end point, and then do the actual drawing by calling stroke().

Another helper function that we need is a function to draw a bar—which is a color-filled rectangle. Let's add it to script.js:

1
function drawBar(ctx, upperLeftCornerX, upperLeftCornerY, width, height,color){
2
    ctx.save();
3
    ctx.fillStyle=color;
4
    ctx.fillRect(upperLeftCornerX,upperLeftCornerY,width,height);
5
    ctx.restore();
6
}

The drawBar function takes six parameters:

  1. ctx: reference to the drawing context
  2. upperLeftCornerX: the X coordinate of the bar's upper left corner
  3. upperLeftCornerY: the X coordinate of the bar's upper left corner
  4. width: the width of the bar
  5. height: the height of the bar
  6. color: the color of the bar

The Bar Chart Data Model

Now that we have the helper functions in place, let's move on to the chart's data model. All types of chart, including bar charts, have a data model behind them. The data model is a structured set of numerical data. For this tutorial, we will use a data series of categories and their associated numerical values representing the number of vinyl records in my collection of records grouped by music genre:

  • Classical music: 16
  • Alternative rock: 12
  • Pop: 18
  • Jazz: 32

We can represent this in JavaScript in the form of an object. We will pass this data to our BarChart object along with other information. Let's add it to our script.js file:

1
{
2
    "Classical Music": 16, 
3
    "Alternative Rock": 12, 
4
    "Pop": 18, 
5
    "Jazz": 32,
6
}

Implementing the BarChart Class

Our BarChart class will have a variety of methods to help split the code into separate related parts. Different components of the bar chart will be drawn by different methods.

Implementing the Bar Chart Component

Let's implement the class and methods that will do the actual drawing of our bar chart. We will do this by adding the following JavaScript code to our script.js file:

1
class BarChart {
2
  constructor(options) {
3
    this.options = options;
4
    this.canvas = options.canvas;
5
    this.ctx = this.canvas.getContext("2d");
6
    this.colors = options.colors;
7
    this.titleOptions = options.titleOptions;
8
    this.maxValue = Math.max(...Object.values(this.options.data));
9
  }
10
  
11
  drawGridLines() {
12
    var canvasActualHeight = this.canvas.height - this.options.padding * 2;
13
    var canvasActualWidth = this.canvas.width - this.options.padding * 2;
14
15
    var gridValue = 0;
16
    while (gridValue <= this.maxValue) {
17
      var gridY =
18
        canvasActualHeight * (1 - gridValue / this.maxValue) +
19
        this.options.padding;
20
      drawLine(
21
        this.ctx,
22
        0,
23
        gridY,
24
        this.canvas.width,
25
        gridY,
26
        this.options.gridColor
27
      );
28
29
      drawLine(
30
        this.ctx,
31
        15,
32
        this.options.padding/2,
33
        15,
34
        gridY + this.options.padding/2,
35
        this.options.gridColor
36
      );
37
38
      // Writing grid markers

39
      this.ctx.save();
40
      this.ctx.fillStyle = this.options.gridColor;
41
      this.ctx.textBaseline = "bottom";
42
      this.ctx.font = "bold 10px Arial";
43
      this.ctx.fillText(gridValue, 0, gridY - 2);
44
      this.ctx.restore();
45
46
      gridValue += this.options.gridScale;
47
    }
48
  }
49
50
  drawBars() {
51
    var canvasActualHeight = this.canvas.height - this.options.padding * 2;
52
    var canvasActualWidth = this.canvas.width - this.options.padding * 2;
53
54
    var barIndex = 0;
55
    var numberOfBars = Object.keys(this.options.data).length;
56
    var barSize = canvasActualWidth / numberOfBars;
57
    
58
    var values = Object.values(this.options.data);
59
60
    for (let val of values) {
61
      var barHeight = Math.round((canvasActualHeight * val) / this.maxValue);
62
      console.log(barHeight);
63
      
64
      drawBar(
65
        this.ctx,
66
        this.options.padding + barIndex * barSize,
67
        this.canvas.height - barHeight - this.options.padding,
68
        barSize,
69
        barHeight,
70
        this.colors[barIndex % this.colors.length]
71
      );
72
73
      barIndex++;
74
    }
75
  }
76
  
77
  draw() {
78
    this.drawGridLines();
79
    this.drawBars();
80
  }
81
}

The class starts defining the constructor method to do some basic initialization by storing the options passed as parameters in different properties. It stores the canvas reference and creates a drawing context also stored as a class member. Then it stores the colors array passed as options. It also extracts the maximum value of the keys from our data object and stores it in the maxValue property. We need this number because we will need to scale all the bars according to this value and according to the size of the canvas. Otherwise, our bars might go outside the display area, and we don't want that.

Now, we will implement the drawGridLines() method. This will draw the grid lines and the grid markers.

The canvasActualHeight and canvasActualWidth variables store the height and width of the canvas adjusted using the value of the padding passed via options. The padding variable indicates the number of pixels between the edge of the canvas and the chart inside.

We then draw the grid lines of the chart. The options.gridStep property sets the step used for drawing the lines. So an options.gridStep of 10 will mean drawing grid lines every 10 units.

To draw the grid lines, we use the helper function drawLine(); as for the color of the grid lines, we take it from the options.gridColor variable. Please note that the canvas coordinates start from 0,0 in the top left corner and increase towards the right and bottom, while our grid values increase in value from the bottom towards the top. That is why we used 1 - gridValue/maxValue in the formula calculating the gridY value.

For every grid line, we also draw the value of the grid line 2 pixels above the grid line (that's why we have gridY - 2 for the Y coordinates of the text).

Next, we draw the bars by using the drawBars() method. The math for calculating the height and width of each bar is pretty straightforward; it takes into account the padding and the value and color for each category in the chart's data model.

Using the Bar Chart Component

Let's now see how to use the BarChart class implemented above. We need to instantiate the class and call the draw() method. Add the following code to the script.js file:

1
var myBarchart = new BarChart({
2
  canvas: myCanvas,
3
  padding: 40,
4
  gridScale: 5,
5
  gridColor: "black",
6
  data: {
7
    "Classical Music": 16, 
8
    "Alternative Rock": 12, 
9
    "Pop": 18, 
10
    "Jazz": 32,
11
  },
12
  colors: ["#a55ca5", "#67b6c7", "#bccd7a", "#eb9743"],
13
});
14
15
myBarchart.draw();

The code creates a new instance of the BarChart class with the required options. We will write the methods that use the titleOptions object in the next section of the tutorial. Loading the index.html in a browser should produce a result like this:

Creating a Simple Bar ChartCreating a Simple Bar ChartCreating a Simple Bar Chart

Adding the Data Series Name and Chart Legend

To add the data series name below the chart, we need to add the following method to our BarChart class:

1
drawLabel() {
2
    this.ctx.save();
3
4
    this.ctx.textBaseline = "bottom";
5
    this.ctx.textAlign = this.titleOptions.align;
6
    this.ctx.fillStyle = this.titleOptions.fill;
7
    this.ctx.font = `${this.titleOptions.font.weight} ${this.titleOptions.font.size} ${this.titleOptions.font.family}`;
8
9
    let xPos = this.canvas.width / 2;
10
11
    if (this.titleOptions.align == "left") {
12
      xPos = 10;
13
    }
14
    if (this.titleOptions.align == "right") {
15
      xPos = this.canvas.width - 10;
16
    }
17
18
    this.ctx.fillText(this.options.seriesName, xPos, this.canvas.height);
19
20
    this.ctx.restore();
21
}

We accept a bunch of font properties inside our titleOptions object to set things like the font size, font family, and font weight. We also accept a string value to determine the alignment of the chart title. We use this value both to control the alignment of the title and to determine the position of the new string besides its alignment.

Also update the draw() method of the class to add a call to drawLabel().

1
draw() {
2
    this.drawGridLines();
3
    this.drawBars();
4
    this.drawLabel();
5
}

We also need to change the way we instantiate the Barchart class like this:

1
var myBarchart = new Barchart(
2
    {
3
        canvas:myCanvas,
4
        seriesName:"Vinyl records",
5
        padding:20,
6
        gridScale:5,
7
        gridColor:"#eeeeee",
8
        data: {
9
            "Classical Music": 16, 
10
            "Alternative Rock": 12, 
11
            "Pop": 18, 
12
            "Jazz": 32,
13
        },
14
        colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"],
15
        titleOptions: {
16
            align: "center",
17
            fill: "black",
18
            font: {
19
              weight: "bold",
20
              size: "18px",
21
              family: "Lato"
22
            }
23
        }
24
    }
25
);
26
27
myBarchart.draw();

And here is how the result looks:

Adding a Title to Bar ChartAdding a Title to Bar ChartAdding a Title to Bar Chart

To add the legend, we first need to modify index.html to look like this:

1
<html>
2
<body>
3
    <canvas id="myCanvas" style="background: white;"></canvas>
4
    <legend for="myCanvas"></legend>
5
    <script type="text/javascript" src="script.js"></script>
6
</body>
7
</html>

The legend tag will be used as a placeholder for the chart's legend. The for attribute links the legend to the canvas holding the chart. We now need to add the code that creates the legend. We will do this in the index.js file after the code that draws the data series name. The code identifies the legend tag corresponding to the chart, and it will add the list of categories from the chart's data model together with the corresponding color. The resulting index.js file will look like this:

1
var myCanvas = document.getElementById("myCanvas");
2
myCanvas.width = 500;
3
myCanvas.height = 500;
4
5
var ctx = myCanvas.getContext("2d");
6
7
function drawLine(ctx, startX, startY, endX, endY, color) {
8
  ctx.save();
9
  ctx.strokeStyle = color;
10
  ctx.beginPath();
11
  ctx.moveTo(startX, startY);
12
  ctx.lineTo(endX, endY);
13
  ctx.stroke();
14
  ctx.restore();
15
}
16
17
function drawBar(
18
  ctx,
19
  upperLeftCornerX,
20
  upperLeftCornerY,
21
  width,
22
  height,
23
  color
24
) {
25
  ctx.save();
26
  ctx.fillStyle = color;
27
  ctx.fillRect(upperLeftCornerX, upperLeftCornerY, width, height);
28
  ctx.restore();
29
}
30
31
class BarChart {
32
  constructor(options) {
33
    this.options = options;
34
    this.canvas = options.canvas;
35
    this.ctx = this.canvas.getContext("2d");
36
    this.colors = options.colors;
37
    this.titleOptions = options.titleOptions;
38
    this.maxValue = Math.max(...Object.values(this.options.data));
39
  }
40
41
  drawGridLines() {
42
    var canvasActualHeight = this.canvas.height - this.options.padding * 2;
43
    var canvasActualWidth = this.canvas.width - this.options.padding * 2;
44
45
    var gridValue = 0;
46
    while (gridValue <= this.maxValue) {
47
      var gridY =
48
        canvasActualHeight * (1 - gridValue / this.maxValue) +
49
        this.options.padding;
50
      drawLine(
51
        this.ctx,
52
        0,
53
        gridY,
54
        this.canvas.width,
55
        gridY,
56
        this.options.gridColor
57
      );
58
59
      drawLine(
60
        this.ctx,
61
        15,
62
        this.options.padding / 2,
63
        15,
64
        gridY + this.options.padding / 2,
65
        this.options.gridColor
66
      );
67
68
      // Writing grid markers

69
      this.ctx.save();
70
      this.ctx.fillStyle = this.options.gridColor;
71
      this.ctx.textBaseline = "bottom";
72
      this.ctx.font = "bold 10px Arial";
73
      this.ctx.fillText(gridValue, 0, gridY - 2);
74
      this.ctx.restore();
75
76
      gridValue += this.options.gridStep;
77
    }
78
  }
79
80
  drawBars() {
81
    var canvasActualHeight = this.canvas.height - this.options.padding * 2;
82
    var canvasActualWidth = this.canvas.width - this.options.padding * 2;
83
84
    var barIndex = 0;
85
    var numberOfBars = Object.keys(this.options.data).length;
86
    var barSize = canvasActualWidth / numberOfBars;
87
88
    var values = Object.values(this.options.data);
89
90
    for (let val of values) {
91
      var barHeight = Math.round((canvasActualHeight * val) / this.maxValue);
92
      console.log(barHeight);
93
94
      drawBar(
95
        this.ctx,
96
        this.options.padding + barIndex * barSize,
97
        this.canvas.height - barHeight - this.options.padding,
98
        barSize,
99
        barHeight,
100
        this.colors[barIndex % this.colors.length]
101
      );
102
103
      barIndex++;
104
    }
105
  }
106
107
  drawLabel() {
108
    this.ctx.save();
109
110
    this.ctx.textBaseline = "bottom";
111
    this.ctx.textAlign = this.titleOptions.align;
112
    this.ctx.fillStyle = this.titleOptions.fill;
113
    this.ctx.font = `${this.titleOptions.font.weight} ${this.titleOptions.font.size} ${this.titleOptions.font.family}`;
114
115
    let xPos = this.canvas.width / 2;
116
117
    if (this.titleOptions.align == "left") {
118
      xPos = 10;
119
    }
120
    if (this.titleOptions.align == "right") {
121
      xPos = this.canvas.width - 10;
122
    }
123
124
    this.ctx.fillText(this.options.seriesName, xPos, this.canvas.height);
125
126
    this.ctx.restore();
127
  }
128
129
  drawLegend() {
130
    let pIndex = 0;
131
    let legend = document.querySelector("legend[for='myCanvas']");
132
    let ul = document.createElement("ul");
133
    legend.append(ul);
134
135
    for (let ctg of Object.keys(this.options.data)) {
136
      let li = document.createElement("li");
137
      li.style.listStyle = "none";
138
      li.style.borderLeft =
139
        "20px solid " + this.colors[pIndex % this.colors.length];
140
      li.style.padding = "5px";
141
      li.textContent = ctg;
142
      ul.append(li);
143
      pIndex++;
144
    }
145
  }
146
147
  draw() {
148
    this.drawGridLines();
149
    this.drawBars();
150
    this.drawLabel();
151
    this.drawLegend();
152
  }
153
}
154
155
var myBarchart = new BarChart({
156
  canvas: myCanvas,
157
  seriesName: "Vinyl records",
158
  padding: 40,
159
  gridStep: 5,
160
  gridColor: "black",
161
  data: {
162
    "Classical Music": 16,
163
    "Alternative Rock": 12,
164
    Pop: 18,
165
    Jazz: 32
166
  },
167
  colors: ["#a55ca5", "#67b6c7", "#bccd7a", "#eb9743"],
168
  titleOptions: {
169
    align: "center",
170
    fill: "black",
171
    font: {
172
      weight: "bold",
173
      size: "18px",
174
      family: "Lato"
175
    }
176
  }
177
});
178
179
myBarchart.draw();

Which will produce a final result looking like this:

Try passing different options to the chart to see how it affects the final result. As an exercise, can you write to code make those grid lines multi-colored?

Congratulations

We have seen that drawing charts using the HTML5 canvas is actually not that hard. It only requires a bit of math and a bit of JavaScript knowledge. You now have everything you need for drawing your own bar charts.

This post has been updated with contributions from Nitish Kumar. Nitish is a web developer with experience in creating eCommerce websites on various platforms. He spends his free time working on personal projects that make his everyday life easier or taking long evening walks with friends.

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.