Monday 7 August 2017

Finding intersection between two lines with HTML5 and Javascript

This article will look at detecting intersection of two lines using Javascript and using HTML 5 Canvas to display the two lines.

A plunk is available here:
Plunk - Intersection of two lines

















We continue from the last article and add a LineIntersection function and add prototype functions. This "class" will help us find the intersection points. The code is as follows:

   function LineIntersection (config){
        this.m1 = config.m1;
        this.b1 = config.b1;
        this.m2 = config.m2;    
        this.b2 = config.b2;

        this.error = 0;
        this.marginOfError = 0.01;
        this.iterations = 0;
        this.maxIterations = 200;
   
      }

      LineIntersection.prototype.PrintData = function() {
        console.clear();
        console.log("m1: " + this.m1 + " b1: " + this.b1 + " m2: " + this.m2 + " b2: " + this.b2);
      }

      LineIntersection.prototype.GetGuess = function(guess){
        var newguess = ((this.b2 - this.b1) / (this.m1 - this.m2) + guess) / 2;
        return newguess;
      }

      LineIntersection.prototype.Y1 = function (guess){
        return this.m1 * guess + this.b1;
      }

      LineIntersection.prototype.Y2 = function (guess){
        return this.m2 * guess + this.b2;
      }

      LineIntersection.prototype.DeltaY = function (guess){
        return Math.abs(this.Y1(guess) - this.Y2(guess));
      }

      LineIntersection.prototype.FindIntersection = function(){

        this.iterations = 0;
       
        if (this.m1 == this.m2)
        {
          alert("The two lines are parallel!");
          return { x: "Infinity", y: "Infinity"};
        }

        guess = Math.floor(Math.random() * 10 + 1);

        do {
         guess = this.GetGuess(guess);

         this.error = this.DeltaY(guess);

         if (this.iterations > this.maxIterations){
          break;

          this.iterations = this.iterations + 1;
         }

        }
        while (this.error > this.marginOfError);

        return { x: guess.toFixed(2), y: this.Y1(guess).toFixed(2) }

      } //function LineIntersection 



The intersection point is then calculated using the code in the following jQuery button click event handler:

   $("#btnIntercept").click(function(){
          var m1,b1,m2,b2 = 0;

        m1 = parseFloat($("#m1").val());
        b1 = parseFloat($("#b1").val());
        m2 = parseFloat($("#m2").val());
        b2 = parseFloat($("#b2").val());
       
        var myGraph = new Graph({
         canvasId: 'Graph',
         minX: -10,
         minY: -10,
         maxX: 10,
         maxY: 10,
         unitsPerTick: 1
        });      

        myGraph.drawLine(m1, b1, 'blue', 3);

        myGraph.drawLine(m2, b2, 'red', 4);

        var lineIntersect = new LineIntersection({
          m1: m1,
          b1: b1,
          m2: m2,
          b2: b2
        });

        lineIntersect.PrintData();

        var intersect = lineIntersect.FindIntersection();
        console.log(intersect);
        console.log(intersect.x);

        myGraph.drawRect(intersect.x, intersect.y, 0.5, 0.5);

        $("#detailsInfo").append("Intersection point: " + " X: " + intersect.x + " Y: " + intersect.y);


To plot a dot where the calculated intersection point the following code is used:
        Graph.prototype.drawRect = function (x, y, width, height){
        var context = this.context; 
        this.transformContext();
        context.strokeStyle = 'green';
        context.fillRect(x - (width/2), y - (height/2), width, height);
      }
To move from object space coordinates to display coordinates we make use of the following helper function:

        Graph.prototype.transformContext = function() {
        var context = this.context;

        // move context to center of canvas
        this.context.translate(this.centerX, this.centerY);

        /*
         * stretch grid to fit the canvas window, and
         * invert the y scale so that that increments
         * as you move upwards
         */
        context.scale(this.scaleX, -this.scaleY);
      };

Sunday 6 August 2017

Drawing intercepting lines with HTML 5 and Js - Part One

I am working with a sample demo that will draw two lines and calculate the intersection. The demo will use Js and HTML 5 Canvas. I have made a Plunk available here:

Canvas line drawing Plunk

The image belows shows a rendering of two lines on the form : y = f(x) = ax + b, y1 = x + 1, y2 = -x + 3

The HTML and Js code is below. I will in the later articles focus on calculating the interception with an iterative approximation method for the intercept. In a future article I will clean up the code and I will look on the code bits and look at Canvas functionality. Here is the code:




















<!DOCTYPE html>
<html>

  <head>
    <meta charset="UTF-8" />
    <script data-require="jquery@*" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <link data-require="bootstrap-css@*" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Intersection of two lines with Canvas and Js </h1>
    
    <fieldset>
      <label>y = mx + b</label> <br /><br />
      
      <table>
        <tr>
        
          <td> <label for="m1">m1:</label> <input id="m1" type="text" style="width:50px" /></td>
          <td> <label for="b1">b1:</label> <input id="b1" type="text" style="width:50px" /></td>

          <td> <label for="slope2">m2:</label> <input id="m2" type="text" style="width:50px" /></td>
          <td> <label for="b2">b2:</label> <input id="b2" type="text" style="width:50px" /></td>

        </tr>
        <tr>
          <td><input id="btnGraph" type="button" value="Draw line" /></td>
        </tr>
      </table>
      
      <br />
      <h3>Graph</h3>
      
      <canvas id="Graph" style="background:aliceblue;border:1px solid #AFAFAF" width="600" height="600"></canvas>
     
    </fieldset>
    
      <script>
      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();
      }

      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.drawLine = function(slope, yintercept, color, thickness) {

        console.log("Inside drawline");

        console.log("this.maxX: " + this.maxX + " this.maxY: " + this.maxY);

        var context = this.context;

        // draw x and y axis
        this.drawXAxis();
        this.drawYAxis();

        //context.clearRect(0, 0, this.canvas.width, this.canvas.height);

        context.save();
        context.save();
        this.transformContext();

        console.log("this.minX: " + this.minX);
        console.log("this.iteration: " + this.iteration);
        console.log("yintercept: " + yintercept);
        console.log("slope:" + slope);

        context.beginPath();
        context.moveTo(this.minX, slope * this.minX + yintercept);

        for(var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
          if (this.iteration % 200 == 0){
           console.log("x: " + x + " y: " + (slope * x + yintercept));
          }
          context.lineTo(x, slope * x + yintercept);
        }

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

        /*
         * stretch grid to fit the canvas window, and
         * invert the y scale so that that increments
         * as you move upwards
         */
        context.scale(this.scaleX, -this.scaleY);
      };
    
    </script>
    
    <script>
     $(document).ready(function(){
     
      $("#btnGraph").click(function(){

        var m1,b1,m2,b2 = 0;

        m1 = parseFloat($("#m1").val());
        b1 = parseFloat($("#b1").val());
        m2 = parseFloat($("#m2").val());
        b2 = parseFloat($("#b2").val());



       
        var myGraph = new Graph({
         canvasId: 'Graph',
         minX: -10,
         minY: -10,
         maxX: 10,
         maxY: 10,
         unitsPerTick: 1
        });      

        myGraph.drawLine(m1, b1, 'blue', 3);

        myGraph.drawLine(m2, b2, 'red', 4);

        //myGraph.drawEquation(function(x) {
         //return 1 * x;
        //}, 'red', 3);

     
      });
     
     });
     
     </script>
    
  </body>

</html>


Wednesday 2 August 2017

Calculating the square root in Javascript using the Babylonian method

Calculating the square root in Javascript is easily done using Math.sqrt(n). But it can be entertaining to use an approximation method instead and build up an algorithm to calculate the square root. We will use the Babylonian method to approximate the square root using an iterative approximation method.

The Babylonian method is described in Wikipedia here:
Babylonian method.

The following image shows how each step of a revised value for the square root is calculated.


We calculate the square root of S by using an inital guess and then revise that step by adding that guess with S divided by the guess and dividing by 2. The revised value is then used again as the new guess value. We stop iterating when the margin of error is below a given treshold. In the calculus, x is the step guess value and e is the error.

We start the calculation sample by adding in Bootstrap CSS and jQuery.















<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <script data-require="jquery@*" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <link data-require="bootstrap-css@*" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
</head>

<body>
  <br />
  <div class="container">
    <h2>Find square root in JS with long division algorithm</h2>

    <hr />
    <!-- html code here -->
    <h3>Estimate Square Root</h3> Enter Number:
    <input id="num" value="700" size="2" type="text" />
    <br />
    <input id="submitButton" value="Calculate" type="submit" />
    <br />
    <br />
    <div id="details"></div>
  </div>
  <script type="text/javascript">
    "use strict";
    var x = 25;
    var guess = 9;
    var marginOfError = 0.1;
    var error = 0;
    var counter = 0;
    var htmlout = "";
    $(document).ready(function() {
      // function code goes here
      function getGuess(g) {
        console.log(g);
        var newguess = (g + x / g) / 2;
        return newguess;
      }
      $('#submitButton').click(function() {
        // JavaScript code here
        console.clear();
        counter = 0;
        x = parseFloat($('#num').val());
        guess = Math.floor(Math.random() * x + 1);
        error = Math.abs(guess * guess - x);
        while (error >= marginOfError) {
          guess = getGuess(guess)
          error = Math.abs(guess * guess - x);
          //console.log(guess);
          counter += 1;
        }
        console.log('Count is ' + counter)
        htmlout = "Square Root is " + guess.toFixed(2) + ". It took " + counter + " guesses";
        $('#details').html(htmlout);
        
      });
    });
  </script>
</body>

</html>

Let us clean up the code using classes in Ecmascript 6 (ES6) and use Traceur to support the ES6 syntax.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
     <script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
        <script src="https://google.github.io/traceur-compiler/bin/BrowserSystem.js"></script>
        <script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
  <script data-require="jquery@*" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <link data-require="bootstrap-css@*" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
</head>

<body>
  <br />
  <div class="container">
    <h2>Find square root in JS with long division algorithm</h2>

    <hr />
    <!-- html code here -->
    <h3>Estimate Square Root</h3> Enter Number:
    <input id="num" value="700" size="2" type="text" />
    <br />
    <input id="submitButton" value="Calculate" type="submit" />
    <br />
    <br />
    <div id="details"></div>
  </div>
  <script type="text/javascript">
    "use strict";
    
    class BabylonianSquareRootSolver {
      
      
      
      constructor(x_0, S, marginOfError = 0.1){
        this.S = S;
        this.x_0 = x_0;
        this.marginOfError = marginOfError;
      }
      
      getRevisedSquareRoot (x_n, S){
       var revisedValue = (x_n + (S/x_n)) / 2;
       return revisedValue;
      }
      
      calculateSqrt(){
        
        var counter = 0;
        var error = 0;
        var guess = this.x_0;
        
        error = Math.abs(this.x_0 * this.x_0 - S);
    
       while (error >= marginOfError) {
          guess = this.getRevisedSquareRoot(guess, this.S)
          error = Math.abs(guess * guess - this.S);
          console.log(guess);
          counter += 1;
          if (counter > 10)
           break;
        }
        
        var result = {
          S : this.S,
          error : error,
          iterations : counter,
          root : guess
        };
        
        return result;
        
      }
      
    }
  
    
    var S = 1;
    var guess = Math.floor(Math.random()*S);
    var marginOfError = 0.1;
    var error = 0;
    var counter = 0;
    var htmlout = "";
    $(document).ready(function() {
      // function code goes here
    
      $('#submitButton').click(function() {
        // JavaScript code here
        console.clear();
        counter = 0;
        S = parseFloat($('#num').val());
        guess = Math.floor(Math.random()*S);
        var bab = new BabylonianSquareRootSolver(guess, S);
        
        console.log(bab);
        var res = bab.calculateSqrt();
        htmlout = "Square Root is approximated to " + res.root.toFixed(2) + ". It took " + res.iterations 
        + " iterations. The error for this approximation is: " + res.error.toFixed(4);
        $('#details').html(htmlout);
        console.log(bab.calculateSqrt());
        
      });
    });
  </script>
</body>

</html>


You can test out the code yourself with the following Plunk:
Babylonian method - Plunk Here is an image of the GUI: