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.
For a graph to be "complete" you need to show all the important features.
- Peaks
- Valleys
- Flat Areas
- Asymptotes
- Any other special feature
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.
- <script type="text/javascript">
- var canvas = document.getElementById('mycanvas');
- var ctx = canvas.getContext("2d");
- </script>
Step 3
In the following code we will create a "Graph" function in which we define various methods, variables, constants and properties.
- function Graph(config)
- {
-
- this.canvas = document.getElementById(config.canvasId);
- this.minX = config.minX;
- this.minY = config.minY;
- this.maxX = config.maxX;
- this.maxY = config.maxY;
- this.unitsPerTick = config.unitsPerTick;
-
-
- this.axisColor = "#aaa";
- this.font = "8pt Calibri";
- this.tickSize = 20;
-
-
- this.context = this.canvas.getContext("2d");
- this.rangeX = this.maxX - this.minX;
- this.rangeY = this.maxY - this.minY;
- this.unitX = this.canvas.width / this.rangeX;
- this.unitY = this.canvas.height / this.rangeY;
- this.centerY = Math.round(Math.abs(this.minY / this.rangeY) * this.canvas.height);
- this.centerX = Math.round(Math.abs(this.minX / this.rangeX) * this.canvas.width);
- this.iteration = (this.maxX - this.minX) / 1000;
- this.scaleX = this.canvas.width / this.rangeX;
- this.scaleY = this.canvas.height / this.rangeY;
-
-
- this.drawXAxis();
- this.drawYAxis();
- }
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.
- Graph.prototype.drawXAxis = function ()
- {
- var context = this.context;
- context.save();
- context.beginPath();
- context.moveTo(0, this.centerY);
- context.lineTo(this.canvas.width, this.centerY);
- context.strokeStyle = this.axisColor;
- context.lineWidth = 2;
- context.stroke();
Figure 1
The following figure represents the x-axis:
-
- var xPosIncrement = this.unitsPerTick * this.unitX;
- var xPos, unit;
- context.font = this.font;
- context.textAlign = "center";
- context.textBaseline = "top";
-
-
- xPos = this.centerX - xPosIncrement;
- unit = -1 * this.unitsPerTick;
- while (xPos > 0)
- {
- context.moveTo(xPos, this.centerY - this.tickSize / 2);
- context.lineTo(xPos, this.centerY + this.tickSize / 2);
- context.stroke();
- context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
- unit -= this.unitsPerTick;
- xPos = Math.round(xPos - xPosIncrement);
- }
Figure 2
The following figure represents the left side tick mark of the x-axis:
-
- xPos = this.centerX + xPosIncrement;
- unit = this.unitsPerTick;
- while (xPos < this.canvas.width)
- {
- context.moveTo(xPos, this.centerY - this.tickSize / 2);
- context.lineTo(xPos, this.centerY + this.tickSize / 2);
- context.stroke();
- context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
- unit += this.unitsPerTick;
- xPos = Math.round(xPos + xPosIncrement);
- }
- context.restore();
Figure 3
The following figure represents the right side tick mark of the x-axis
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.
- Graph.prototype.drawYAxis = function ()
- {
- var context = this.context;
- context.save();
- context.beginPath();
- context.moveTo(this.centerX, 0);
- context.lineTo(this.centerX, this.canvas.height);
- context.strokeStyle = this.axisColor;
- context.lineWidth = 2;
- context.stroke();
Figure 4
The following figure represents the y-axis
-
- var yPosIncrement = this.unitsPerTick * this.unitY;
- var yPos, unit;
- context.font = this.font;
- context.textAlign = "right";
- context.textBaseline = "middle";
-
-
- yPos = this.centerY - yPosIncrement;
- unit = this.unitsPerTick;
- while (yPos > 0)
- {
- context.moveTo(this.centerX - this.tickSize / 2, yPos);
- context.lineTo(this.centerX + this.tickSize / 2, yPos);
- context.stroke();
- context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
- unit += this.unitsPerTick;
- yPos = Math.round(yPos - yPosIncrement);
- }
Figure 5
The following figure represents the upper side tick mark on the y-axis
-
- yPos = this.centerY + yPosIncrement;
- unit = -1 * this.unitsPerTick;
- while (yPos < this.canvas.height)
- {
- context.moveTo(this.centerX - this.tickSize / 2, yPos);
- context.lineTo(this.centerX + this.tickSize / 2, yPos);
- context.stroke();
- context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
- unit -= this.unitsPerTick;
- yPos = Math.round(yPos + yPosIncrement);
- }
- context.restore();
Figure 6
The following figure represents the lower side of the y-axis
Figure 7
The following figure represents the combination of the x-axis and the y-axis. Both form a graph.
Step 6
In the following step we will draw the equation on the graph. We will apply the loop for drawing the equation.
- Graph.prototype.drawEquation = function (equation, color, thickness)
- {
- var context = this.context;
- context.save();
- context.save();
- this.transformContext();
-
- context.beginPath();
- context.moveTo(this.minX, equation(this.minX));
-
- for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration)
- {
- context.lineTo(x, equation(x));
- }
-
- context.restore();
- context.lineJoin = "round";
- context.lineWidth = thickness;
- context.strokeStyle = color;
- context.stroke();
- context.restore();
- };
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.
- Graph.prototype.transformContext = function ()
- {
- var context = this.context;
-
-
- this.context.translate(this.centerX, this.centerY);
-
- context.scale(this.scaleX, -this.scaleY);
- };
Step 8
In the following code the window onload we will draw lines on the graph.
- window.onload = function ()
- {
- var myGraph = new Graph({
- canvasId: "myCanvas",
- minX: -10,
- minY: -10,
- maxX: 10,
- maxY: 10,
- unitsPerTick: 1
- });
-
- myGraph.drawEquation(function (x) {
- return 5 * Math.sin(x);
- }, "green", 3);
-
- myGraph.drawEquation(function (x) {
- return x * x;
- }, "blue", 3);
-
- myGraph.drawEquation(function (x) {
- return 1 * x;
- }, "red", 3);
- };
Example
- <!DOCTYPE html>
-
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="utf-8" />
- <title>Graphing Equation in HTML5</title>
- <script>
- function Graph(con) {
-
- this.canvas = document.getElementById(con.canvasId);
- this.minX = con.minX;
- this.minY = con.minY;
- this.maxX = con.maxX;
- this.maxY = con.maxY;
- this.unitsPerTick = con.unitsPerTick;
-
-
- this.axisColor = "#aaa";
- this.font = "8pt Calibri";
- this.tickSize = 20;
-
-
- this.context = this.canvas.getContext("2d");
- this.rangeX = this.maxX - this.minX;
- this.rangeY = this.maxY - this.minY;
- this.unitX = this.canvas.width / this.rangeX;
- this.unitY = this.canvas.height / this.rangeY;
- this.centerY = Math.round(Math.abs(this.minY / this.rangeY) * this.canvas.height);
- this.centerX = Math.round(Math.abs(this.minX / this.rangeX) * this.canvas.width);
- this.iteration = (this.maxX - this.minX) / 1000;
- this.scaleX = this.canvas.width / this.rangeX;
- this.scaleY = this.canvas.height / this.rangeY;
-
-
- this.drawXAxis();
- this.drawYAxis();
- }
-
- Graph.prototype.drawXAxis = function () {
- var context = this.context;
- context.save();
- context.beginPath();
- context.moveTo(0, this.centerY);
- context.lineTo(this.canvas.width, this.centerY);
- context.strokeStyle = this.axisColor;
- context.lineWidth = 2;
- context.stroke();
-
-
- var xPosIncrement = this.unitsPerTick * this.unitX;
- var xPos, unit;
- context.font = this.font;
- context.textAlign = "center";
- context.textBaseline = "top";
-
-
- xPos = this.centerX - xPosIncrement;
- unit = -1 * this.unitsPerTick;
- while (xPos > 0) {
- context.moveTo(xPos, this.centerY - this.tickSize / 2);
- context.lineTo(xPos, this.centerY + this.tickSize / 2);
- context.stroke();
- context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
- unit -= this.unitsPerTick;
- xPos = Math.round(xPos - xPosIncrement);
- }
-
-
- xPos = this.centerX + xPosIncrement;
- unit = this.unitsPerTick;
- while (xPos < this.canvas.width) {
- context.moveTo(xPos, this.centerY - this.tickSize / 2);
- context.lineTo(xPos, this.centerY + this.tickSize / 2);
- context.stroke();
- context.fillText(unit, xPos, this.centerY + this.tickSize / 2 + 3);
- unit += this.unitsPerTick;
- xPos = Math.round(xPos + xPosIncrement);
- }
- context.restore();
- };
-
- Graph.prototype.drawYAxis = function () {
- var context = this.context;
- context.save();
- context.beginPath();
- context.moveTo(this.centerX, 0);
- context.lineTo(this.centerX, this.canvas.height);
- context.strokeStyle = this.axisColor;
- context.lineWidth = 2;
- context.stroke();
-
-
- var yPosIncrement = this.unitsPerTick * this.unitY;
- var yPos, unit;
- context.font = this.font;
- context.textAlign = "right";
- context.textBaseline = "middle";
-
-
- yPos = this.centerY - yPosIncrement;
- unit = this.unitsPerTick;
- while (yPos > 0) {
- context.moveTo(this.centerX - this.tickSize / 2, yPos);
- context.lineTo(this.centerX + this.tickSize / 2, yPos);
- context.stroke();
- context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
- unit += this.unitsPerTick;
- yPos = Math.round(yPos - yPosIncrement);
- }
-
-
- yPos = this.centerY + yPosIncrement;
- unit = -1 * this.unitsPerTick;
- while (yPos < this.canvas.height) {
- context.moveTo(this.centerX - this.tickSize / 2, yPos);
- context.lineTo(this.centerX + this.tickSize / 2, yPos);
- context.stroke();
- context.fillText(unit, this.centerX - this.tickSize / 2 - 3, yPos);
- unit -= this.unitsPerTick;
- yPos = Math.round(yPos + yPosIncrement);
- }
- context.restore();
- };
-
- Graph.prototype.drawEquation = function (equation, color, thickness) {
- var context = this.context;
- context.save();
- context.save();
- this.transformContext();
-
- context.beginPath();
- context.moveTo(this.minX, equation(this.minX));
-
- for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
- context.lineTo(x, equation(x));
- }
-
- context.restore();
- context.lineJoin = "round";
- context.lineWidth = thickness;
- context.strokeStyle = color;
- context.stroke();
- context.restore();
- };
-
- Graph.prototype.transformContext = function () {
- var context = this.context;
-
-
- this.context.translate(this.centerX, this.centerY);
-
- context.scale(this.scaleX, -this.scaleY);
- };
-
- window.onload = function () {
- var myGraph = new Graph({
- canvasId: "myCanvas",
- minX: -10,
- minY: -10,
- maxX: 10,
- maxY: 10,
- unitsPerTick: 1
- });
-
- myGraph.drawEquation(function (x) {
- return 5 * Math.sin(x);
- }, "green", 3);
-
- myGraph.drawEquation(function (x) {
- return x * x;
- }, "blue", 3);
-
- myGraph.drawEquation(function (x) {
- return 1 * x;
- }, "red", 3);
- };
- </script>
- </head>
- <body>
- <canvas id="myCanvas" width="600" height="300" style="border: 1px solid black;"></canvas>
- </body>
- </html>
Output