Graphing Equation in HTML5 Using Canvas

Introduction

In this article I will walk through how to use a graphing equation in a 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.

  • 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)

{

   // user defined properties

   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;

 

   // constants

   this.axisColor = "#aaa";

   this.font = "8pt Calibri";

   this.tickSize = 20;

 

   // relationships

   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;

 

   // draw x and y axis

   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:

 

graph1.jpg

 

   // draw tick marks

   var xPosIncrement = this.unitsPerTick * this.unitX;

   var xPos, unit;

   context.font = this.font;

   context.textAlign = "center";

   context.textBaseline = "top";

 

   // draw left tick marks

   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:

 

lgraph.jpg

 

    // draw right tick marks

    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:

rigraph.jpg

Step 5

Similarily, we will draw the y-axis. On 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:

 

line.jpg

 

   // draw tick marks 

   var yPosIncrement = this.unitsPerTick * this.unitY;

   var yPos, unit;

   context.font = this.font;

   context.textAlign = "right";

   context.textBaseline = "middle";

 

   // draw top tick marks

   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:

 

ugraph.jpg

 

    // draw bottom tick marks

    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 represent the lower side of the y-axis:

lograph.jpg

Figure 7

The following figure represents the combination of x-axis and 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.

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;

 

   // move context to center of canvas

   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) {

            // user defined properties

            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;

 

            // constants

            this.axisColor = "#aaa";

            this.font = "8pt Calibri";

            this.tickSize = 20;

 

            // relationships

            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;

 

            // draw x and y axis

            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();

 

            // draw tick marks

            var xPosIncrement = this.unitsPerTick * this.unitX;

            var xPos, unit;

            context.font = this.font;

            context.textAlign = "center";

            context.textBaseline = "top";

 

            // draw left tick marks

            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);

            }

 

            // draw right tick marks

            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();

 

            // draw tick marks 

            var yPosIncrement = this.unitsPerTick * this.unitY;

            var yPos, unit;

            context.font = this.font;

            context.textAlign = "right";

            context.textBaseline = "middle";

 

            // draw top tick marks

            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);

            }

 

            // draw bottom tick marks

            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;

 

            // move context to center of canvas

            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

graph2.jpg

Up Next
    Ebook Download
    View all
    Learn
    View all