Introduction

In this article, I will walk through how to use a graphing equation in an HTML5 canvas.

Graphing Equation in HTML5 using Canvas

What is the Graph of an Equation?

It is the set of points where the equation is true.

Features of a Graph

For a graph to be "complete" you need to show all the important features.
Browser Support
It is supported by all major browsers such as Internet Explorer 9, Firefox 3.6+, Safari 4+ and Chrome, etc.
Procedure for creating the graphing equations
Step 1
We first define the element using a "canvas" in HTML5. The height and width attributes set the canvas and graph size.
<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 code we will create a "Graph" function in which we define various methods, variables, constants and properties.
  1. function Graph(config)
  2. {
  3. // user defined properties
  4. this.canvas = document.getElementById(config.canvasId);
  5. this.minX = config.minX;
  6. this.minY = config.minY;
  7. this.maxX = config.maxX;
  8. this.maxY = config.maxY;
  9. this.unitsPerTick = config.unitsPerTick;
  10. // constants
  11. this.axisColor = "#aaa";
  12. this.font = "8pt Calibri";
  13. this.tickSize = 20;
  14. // relationships
  15. this.context = this.canvas.getContext("2d");
  16. this.rangeX = this.maxX - this.minX;
  17. this.rangeY = this.maxY - this.minY;
  18. this.unitX = this.canvas.width / this.rangeX;
  19. this.unitY = this.canvas.height / this.rangeY;
  20. this.centerY = Math.round(Math.abs(this.minY / this.rangeY) * this.canvas.height);
  21. this.centerX = Math.round(Math.abs(this.minX / this.rangeX) * this.canvas.width);
  22. this.iteration = (this.maxX - this.minX) / 1000;
  23. this.scaleX = this.canvas.width / this.rangeX;
  24. this.scaleY = this.canvas.height / this.rangeY;
  25. // draw x and y axis
  26. this.drawXAxis();
  27. this.drawYAxis();
  28. }
Step 4
In the following code, we will draw the x-axis. On the x-axis, we draw the left tick marks and then draw the right tick marks. For drawing both of the tick marks we apply the loop.
  1. Graph.prototype.drawXAxis = function ()
  2. {
  3. var context = this.context;
  4. context.save();
  5. context.beginPath();
  6. context.moveTo(0, this.centerY);
  7. context.lineTo(this.canvas.width, this.centerY);
  8. context.strokeStyle = this.axisColor;
  9. context.lineWidth = 2;
  10. context.stroke();
Figure 1
The following figure represents the x-axis:
graph1.jpg
  1. // draw tick marks
  2. var xPosIncrement = this.unitsPerTick * this.unitX;
  3. var xPos, unit;
  4. context.font = this.font;
  5. context.textAlign = "center";
  6. context.textBaseline = "top";
  7. // draw left tick marks
  8. xPos = this.centerX - xPosIncrement;
  9. unit = -1 * this.unitsPerTick;
  10. while (xPos > 0)
  11. {
  12. context.moveTo(xPos, this.centerY - this.tickSize / 2);
  13. context.lineTo(xPos, this.centerY + this.tickSize / 2);
  14. context.stroke();
  15. context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
  16. unit -= this.unitsPerTick;
  17. xPos = Math.round(xPos - xPosIncrement);
  18. }
Figure 2
The following figure represents the left side tick mark of the x-axis:
lgraph.jpg
  1. // draw right tick marks
  2. xPos = this.centerX + xPosIncrement;
  3. unit = this.unitsPerTick;
  4. while (xPos < this.canvas.width)
  5. {
  6. context.moveTo(xPos, this.centerY - this.tickSize / 2);
  7. context.lineTo(xPos, this.centerY + this.tickSize / 2);
  8. context.stroke();
  9. context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
  10. unit += this.unitsPerTick;
  11. xPos = Math.round(xPos + xPosIncrement);
  12. }
  13. context.restore();
Figure 3
The following figure represents the right side tick mark of the x-axis
rigraph.jpg
Step 5
Similarily, we will draw the y-axis. On the y-axis we will draw the tick marks along the upper side of the y-axis and finally, we draw the tick mark for the bottom side of the y-axis. For drawing both of the tick marks and labels we apply the loop.
  1. Graph.prototype.drawYAxis = function ()
  2. {
  3. var context = this.context;
  4. context.save();
  5. context.beginPath();
  6. context.moveTo(this.centerX, 0);
  7. context.lineTo(this.centerX, this.canvas.height);
  8. context.strokeStyle = this.axisColor;
  9. context.lineWidth = 2;
  10. context.stroke();
Figure 4
The following figure represents the y-axis
line.jpg
  1. // draw tick marks
  2. var yPosIncrement = this.unitsPerTick * this.unitY;
  3. var yPos, unit;
  4. context.font = this.font;
  5. context.textAlign = "right";
  6. context.textBaseline = "middle";
  7. // draw top tick marks
  8. yPos = this.centerY - yPosIncrement;
  9. unit = this.unitsPerTick;
  10. while (yPos > 0)
  11. {
  12. context.moveTo(this.centerX - this.tickSize / 2, yPos);
  13. context.lineTo(this.centerX + this.tickSize / 2, yPos);
  14. context.stroke();
  15. context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
  16. unit += this.unitsPerTick;
  17. yPos = Math.round(yPos - yPosIncrement);
  18. }
Figure 5
The following figure represents the upper side tick mark on the y-axis
ugraph.jpg
  1. // draw bottom tick marks
  2. yPos = this.centerY + yPosIncrement;
  3. unit = -1 * this.unitsPerTick;
  4. while (yPos < this.canvas.height)
  5. {
  6. context.moveTo(this.centerX - this.tickSize / 2, yPos);
  7. context.lineTo(this.centerX + this.tickSize / 2, yPos);
  8. context.stroke();
  9. context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
  10. unit -= this.unitsPerTick;
  11. yPos = Math.round(yPos + yPosIncrement);
  12. }
  13. context.restore();
Figure 6
The following figure represents the lower side of the y-axis
lograph.jpg
Figure 7
The following figure represents the combination of the x-axis and the y-axis. Both form a graph.
graph3.jpg
Step 6
In the following step we will draw the equation on the graph. We will apply the loop for drawing the equation.
  1. Graph.prototype.drawEquation = function (equation, color, thickness)
  2. {
  3. var context = this.context;
  4. context.save();
  5. context.save();
  6. this.transformContext();
  7. context.beginPath();
  8. context.moveTo(this.minX, equation(this.minX));
  9. for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration)
  10. {
  11. context.lineTo(x, equation(x));
  12. }
  13. context.restore();
  14. context.lineJoin = "round";
  15. context.lineWidth = thickness;
  16. context.strokeStyle = color;
  17. context.stroke();
  18. context.restore();
  19. };
Step 7
We will transform the context to move it to the center. Then we will stretch the grid to fit the canvas window, and invert the y scale so that it increments as you move upwards.
  1. Graph.prototype.transformContext = function ()
  2. {
  3. var context = this.context;
  4. // move context to center of canvas
  5. this.context.translate(this.centerX, this.centerY);
  6. context.scale(this.scaleX, -this.scaleY);
  7. };
Step 8
In the following code the window onload we will draw lines on the graph.
  1. window.onload = function ()
  2. {
  3. var myGraph = new Graph({
  4. canvasId: "myCanvas",
  5. minX: -10,
  6. minY: -10,
  7. maxX: 10,
  8. maxY: 10,
  9. unitsPerTick: 1
  10. });
  11. myGraph.drawEquation(function (x) {
  12. return 5 * Math.sin(x);
  13. }, "green", 3);
  14. myGraph.drawEquation(function (x) {
  15. return x * x;
  16. }, "blue", 3);
  17. myGraph.drawEquation(function (x) {
  18. return 1 * x;
  19. }, "red", 3);
  20. };
Example
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Graphing Equation in HTML5</title>
  6. <script>
  7. function Graph(con) {
  8. // user defined properties
  9. this.canvas = document.getElementById(con.canvasId);
  10. this.minX = con.minX;
  11. this.minY = con.minY;
  12. this.maxX = con.maxX;
  13. this.maxY = con.maxY;
  14. this.unitsPerTick = con.unitsPerTick;
  15. // constants
  16. this.axisColor = "#aaa";
  17. this.font = "8pt Calibri";
  18. this.tickSize = 20;
  19. // relationships
  20. this.context = this.canvas.getContext("2d");
  21. this.rangeX = this.maxX - this.minX;
  22. this.rangeY = this.maxY - this.minY;
  23. this.unitX = this.canvas.width / this.rangeX;
  24. this.unitY = this.canvas.height / this.rangeY;
  25. this.centerY = Math.round(Math.abs(this.minY / this.rangeY) * this.canvas.height);
  26. this.centerX = Math.round(Math.abs(this.minX / this.rangeX) * this.canvas.width);
  27. this.iteration = (this.maxX - this.minX) / 1000;
  28. this.scaleX = this.canvas.width / this.rangeX;
  29. this.scaleY = this.canvas.height / this.rangeY;
  30. // draw x and y axis
  31. this.drawXAxis();
  32. this.drawYAxis();
  33. }
  34. Graph.prototype.drawXAxis = function () {
  35. var context = this.context;
  36. context.save();
  37. context.beginPath();
  38. context.moveTo(0, this.centerY);
  39. context.lineTo(this.canvas.width, this.centerY);
  40. context.strokeStyle = this.axisColor;
  41. context.lineWidth = 2;
  42. context.stroke();
  43. // draw tick marks
  44. var xPosIncrement = this.unitsPerTick * this.unitX;
  45. var xPos, unit;
  46. context.font = this.font;
  47. context.textAlign = "center";
  48. context.textBaseline = "top";
  49. // draw left tick marks
  50. xPos = this.centerX - xPosIncrement;
  51. unit = -1 * this.unitsPerTick;
  52. while (xPos > 0) {
  53. context.moveTo(xPos, this.centerY - this.tickSize / 2);
  54. context.lineTo(xPos, this.centerY + this.tickSize / 2);
  55. context.stroke();
  56. context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
  57. unit -= this.unitsPerTick;
  58. xPos = Math.round(xPos - xPosIncrement);
  59. }
  60. // draw right tick marks
  61. xPos = this.centerX + xPosIncrement;
  62. unit = this.unitsPerTick;
  63. while (xPos < this.canvas.width) {
  64. context.moveTo(xPos, this.centerY - this.tickSize / 2);
  65. context.lineTo(xPos, this.centerY + this.tickSize / 2);
  66. context.stroke();
  67. context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
  68. unit += this.unitsPerTick;
  69. xPos = Math.round(xPos + xPosIncrement);
  70. }
  71. context.restore();
  72. };
  73. Graph.prototype.drawYAxis = function () {
  74. var context = this.context;
  75. context.save();
  76. context.beginPath();
  77. context.moveTo(this.centerX, 0);
  78. context.lineTo(this.centerX, this.canvas.height);
  79. context.strokeStyle = this.axisColor;
  80. context.lineWidth = 2;
  81. context.stroke();
  82. // draw tick marks
  83. var yPosIncrement = this.unitsPerTick * this.unitY;
  84. var yPos, unit;
  85. context.font = this.font;
  86. context.textAlign = "right";
  87. context.textBaseline = "middle";
  88. // draw top tick marks
  89. yPos = this.centerY - yPosIncrement;
  90. unit = this.unitsPerTick;
  91. while (yPos > 0) {
  92. context.moveTo(this.centerX - this.tickSize / 2, yPos);
  93. context.lineTo(this.centerX + this.tickSize / 2, yPos);
  94. context.stroke();
  95. context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
  96. unit += this.unitsPerTick;
  97. yPos = Math.round(yPos - yPosIncrement);
  98. }
  99. // draw bottom tick marks
  100. yPos = this.centerY + yPosIncrement;
  101. unit = -1 * this.unitsPerTick;
  102. while (yPos < this.canvas.height) {
  103. context.moveTo(this.centerX - this.tickSize / 2, yPos);
  104. context.lineTo(this.centerX + this.tickSize / 2, yPos);
  105. context.stroke();
  106. context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
  107. unit -= this.unitsPerTick;
  108. yPos = Math.round(yPos + yPosIncrement);
  109. }
  110. context.restore();
  111. };
  112. Graph.prototype.drawEquation = function (equation, color, thickness) {
  113. var context = this.context;
  114. context.save();
  115. context.save();
  116. this.transformContext();
  117. context.beginPath();
  118. context.moveTo(this.minX, equation(this.minX));
  119. for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
  120. context.lineTo(x, equation(x));
  121. }
  122. context.restore();
  123. context.lineJoin = "round";
  124. context.lineWidth = thickness;
  125. context.strokeStyle = color;
  126. context.stroke();
  127. context.restore();
  128. };
  129. Graph.prototype.transformContext = function () {
  130. var context = this.context;
  131. // move context to center of canvas
  132. this.context.translate(this.centerX, this.centerY);
  133. context.scale(this.scaleX, -this.scaleY);
  134. };
  135. window.onload = function () {
  136. var myGraph = new Graph({
  137. canvasId: "myCanvas",
  138. minX: -10,
  139. minY: -10,
  140. maxX: 10,
  141. maxY: 10,
  142. unitsPerTick: 1
  143. });
  144. myGraph.drawEquation(function (x) {
  145. return 5 * Math.sin(x);
  146. }, "green", 3);
  147. myGraph.drawEquation(function (x) {
  148. return x * x;
  149. }, "blue", 3);
  150. myGraph.drawEquation(function (x) {
  151. return 1 * x;
  152. }, "red", 3);
  153. };
  154. </script>
  155. </head>
  156. <body>
  157. <canvas id="myCanvas" width="600" height="300" style="border: 1px solid black;"></canvas>
  158. </body>
  159. </html>
Output
graph2.jpg