Wednesday, 23 August 2017

Getting started with CSS3 Animations

CSS3 animations can give your web sites dynamic effects and visual queues for added user friendly navigation. Of course, such effects could quickly become noisy if exaggerated. I have added a sample demo of a Bookshelf with HTML and CSS3 below.

CSS3 Animated Bookshelf (Plunk)


The following HTML builds up the user interface - that is, the Bookshelf itself.


<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

  <body>
    <h1>CSS3 Animations - Bookshelf</h1>
    
    <div id="box1" class="box">
      <p>HTML 2.0 for beginners</p>
    </div>
    
     <div id="box2" class="box">
      <p>Internet Relay Chat Powertips</p></p>
    </div>
    
     <div id="box3" class="box">
      <p>MS-DOS 5.0 Masterclass</p>
    </div>
    
     <div id="box4" class="box">
      <p>QBasic Game Coding</p>
    </div>
    
  </body>

</html>

To animate these "Books", that is the < div > elements, CSS3 rules are added. The following CSS3 style sheet was added:


  /* Styles go here */

@keyframes FocusBook {
  0% { 
    transform: scale(1.1);
  }
100% {
    transform: scale(1.8) rotate(90deg);
    box-shadow: 8px 8px 8px #8080af;
    text-shadow: 1px 1px #102030;
    top: 50%;
    left: 50%;
    position: fixed;
    color: white;
    background:linear-gradient(90deg, peru, brown);
  }
}

.box {
    width:50px;
    height:250px;
    border:1px solid black;
    box-shadow: 2px 2px 2px #808080;
    background:linear-gradient(peru, burlywood);
    transform: rotate(0deg);
    transition: all 1s;
    float: left;
    opacity:0.9;
    margin: 2px;
    user-select: none;
}

.box:hover {
  transform: translate(2px, 0px) rotate(2deg) scale(1.1);
  cursor: pointer;
  box-shadow: 2px 2px 2px yellow;
  color:black;
  background:linear-gradient(45deg, peru, brown);
  z-index:20;
}

.box p {
  font-family: Verdana;
  color: charcoal;
  font-size:10pt;
  white-space: nowrap;
  transform: rotate(-90deg) translate(-190px, -10px);
}

.box:active {
  animation: FocusBook 1.0s infinite alternate;
}


To support transitions with CSS, you add the CSS attribute transition with a comma-separated list of css attributes to allow transitioning and the time the transition should take. We add first all here to allow transition all attribute changes:

.box {
    width:50px;
    height:250px;
    border:1px solid black;
    box-shadow: 2px 2px 2px #808080;
    background:linear-gradient(peru, burlywood);
    transform: rotate(0deg);
    transition: all 1s;
    float: left;
    opacity:0.9;
    margin: 2px;
    user-select: none;
}

The transition is then in effect for the hover transition.

.box:hover {
  transform: translate(2px, 0px) rotate(2deg) scale(1.1);
  cursor: pointer;
  box-shadow: 2px 2px 2px yellow;
  color:black;
  background:linear-gradient(45deg, peru, brown);
  z-index:20;
}

Now, let's take a look at the animation effect when the user clicks on one "Book". We define key frames first.
@keyframes FocusBook {
  0% { 
    transform: scale(1.1);
  }
100% {
    transform: scale(1.8) rotate(90deg);
    box-shadow: 8px 8px 8px #8080af;
    text-shadow: 1px 1px #102030;
    top: 50%;
    left: 50%;
    position: fixed;
    color: white;
    background:linear-gradient(90deg, peru, brown);
  }
}

Then we play the animation after defining the key frames (note the percentage to specify keys at a relative elapsed time of the animation):

.box:active {
   animation: FocusBook 1.0s infinite alternate; 
}

Note that the CSS attribute animation now points to the @keyframes defined. In addition, the animation uses the keywords infinite and alternate.

The best use of CSS3 animations is most likely subtle changes in color and size, and using CSS transforms. You can define many keys in @keyframes definition for complex animations.

Tuesday, 22 August 2017

Getting started with web fonts in CSS

Now a simple topic in this article. We will look into how to use web fonts in CSS. Web fonts lets you add additional fonts that the users can view on your web site and offer a variation to the usual fonts that different systems support. The standard fonts or web safe fonts will become tedious and boring in the long run, web fonts will offer you variation on a grand scale! First off, we need a source for fonts where we can download fonts. You can for example download web fonts from the following site:

Font Squirrel (www.fontsquirrel.com)

Look for a web font to test out, for example Gooddog. Choose the pane Webfont kit and then hit the button Download @Font-Face kit after selecting formats to download. The format WOFF (.woff) is most compatible with different browsers. Then a .zip file is downloaded where you already can test out a demo page with the necessary CSS and HTML to get started.

First off, put the .woff file into a folder near the CSS of your web page. Now define the web font as a resource in CSS using @font-face like the following CSS rule:

@font-face {
    font-family: Good-dog;
    src: url(../fonts/GoodDog-webfont.woff) format('woff');
}

You have now defined the font resource and can use it with the friendly name you defined for font-family. For example, for the standard ASP.NET Mvc sample site for Visual Studio 2017, add this rule:
h1 {
    font-family: Good-dog;
}

.lead {
    font-family: Good-dog;
}


The result is then:
Note that you get excellent support in VS 2017 for defining such CSS rules! Also check out the license terms for the different web fonts you download. Some fonts is not free to use in commercial applications or other production. The WOFF format is not supported in IE browsers predating IE 8. Internet Explorer may also not work with uppercase letters in the url attribute of src. More info about @font-face on the following w3schools page:

@font-face CSS rule
Note that you should provide a fallback to the places in your CSS rules where you make use of the web font, such as fallback to Arial and so on. Mozilla Firefox might also deactivate web fonts intially as a security measure. Tip how to disable in Google Chrome and Mozilla Firefox:
Disable web fonts tip

Monday, 21 August 2017

Trigonometric functions and integrals with Js and Canvas

This article will look into displaying trigonometric functions with Javascript and HTML5 Canvas.

A plunk is availble so you can test out different trigonometric functions in Javascript yourself. The following link gives you access to the demo:

Plunk Integral of functions using HTML 5 Canvas and Js
The form input of the demo first asks for an equation to display. Supported here is the format that the Math.Js library supports. You can use for example f(x) = sin(x). I have tested it out with 2D functions supporting one variable x. The drop down lets you choose some prefilled equations for you to test out. The different trigonometric functions supported are the usual ones, also the hyperbolic and arc hyperbolic ones can be tested out, plus some polynomial functions and so on. The Math.Js library will build up a function delegate that can be used in the calculation of the integral and the calculation of the function curve itself.



Method for drawing the equations

The javascript code below is used to draw the equations. We use Math.Js to draw the function, since Math.Js got an excellent parser to build functions that allow different plots of trigonometric functions. But also polynomial equations and so on is supported. Note the math.eval(..) line!

    Graph.prototype.drawEquation = function(polynomialequation, increment, 
     isIntegral, color, thickness, startx, endx){

        var totalArea = 0.0;

        var context = this.context;
        context.save();
        context.save();
        this.transformContext();
        
        //debugger;
        
        var parsedFunc = math.eval(polynomialequation);
        var cury = 0;

        context.beginPath();
     
        cury = parsedFunc(this.minX);
        
        context.moveTo(this.minX, cury);
        
        for(var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
   
          cury = parsedFunc(x);
          
          context.lineTo(x, cury);
        }

        context.restore();
        context.lineJoin = 'round';
        context.lineWidth = thickness;
        context.strokeStyle = color;
        context.stroke();
        context.restore();

        if (isIntegral){
            var context = this.context;
            context.save();
            this.transformContext();

            var currentY = 0.0;

            context.lineWidth = 0.1;
            context.strokeStyle = 'red';

            for(var x = startx; x < endx; x += increment) {
              context.beginPath();
              currentY = parsedFunc(x+increment/2.0);
              context.rect(x, 0, increment, currentY);
              totalArea += Math.abs(increment * currentY);
              context.stroke();
            }           
      
        }

        return totalArea.toFixed(2);

      };


Further issues around asymptotic behavior

One thing I have seen is that the calculation of the integral fails to detect asymptotic boundary conditions. For example, the tangens function $$ f(x) = tan(x) $$ has got several asymptotes vertically. These asymptotes occur at the following x-values: $$ \frac{\pi}{2} * (2n+1) $$ for the natural numbers $$ \mathbb{N} $$. Detecting such asymptotes can be very hard, since you have to first decide when a function becomes asymptotic, and you also have to test the function at specific intervals and narrow it down. The Riemann sum as an approximation of the integral will fail for such as asymptotic functions. I use the Midpoint rule in an easy manner here by using the average or middle point of the incrment and look at the function value right there. You could also calculate $$ f(x) $$ at the minimum and maximum part of the increment and average the two function values instead of calculating the function value at the middle point. One other way is to set the increment at a very low value.
You can also test this out yourself! Try setting the increment to a very low value, like 0.00001! You will see that the integral keeps growing as you lower the increment value. This is because small increments for the Riemann sum will more and more find the true integral of the tagens function in this case.
If you are a math student and have good tips here, I would be happy to know more about the strategy around integrals and Riemann sums to deal with asymptotes!

Saturday, 19 August 2017

Integrals in math with Javascript

This article will describe a demo how to calculate and display definite integrals in a web browser using the HTML 5 <Canvas> element and demonstrate an approximation of integrals using the method of summing up the rectangles between a function curve and the x-axis, that is the equation under consideration to do the calculation of the definite integral on. The integral is defined as the area between the function curve and the x-axis.
Note that we in this demo will consider equations on the form of polynomial curves.
The picture reads integration, it should be integrals! Lets first look some math of how to do the integral of our example, we consider polynomials here, which will be defined as:
$$ y = f(x) = ax^3 + bx^2 + cx + d $$ The integral will be the areal between the function f(x) between startx and endx. Consider the following definition of the indefinite integral: $$\int f(x)\ dx $$ The definite area is then between startx s and endx e is then: $$\int_s^e f(x)dx $$ Some math ensues of to check the calculation of the integral (area), consider this following example :
$$ a = 0.05, b = 0.05, c = 0.05, d = 1 $$. We consider x to be between 1 and 4. Manually calculating the area results in the calculated area of 7.614 (the image shows 7.62, but a check showed it to be 7.614).
Calculation of the integral uses in the hand written calculation the start and end x-values and subtracting the end value of the integral formula with the start value. We consider x here to be between [1..4]. As the screen shot of the demo displays, we approximate this integral to the value 7.60 by calculating the integral as the sum of the midpoint rectangles.

The difference in the specific example between the hand written calculation of 7.62 (exact integral) and approximation of 7.60 is because of the fact that we approximate the integral by summing up the rectangles below the curve. Actually in some cases part of the rectangles are above the curve, there is some discrepancy between the approximate rectangle shape and the true shape of the integral. To get an even more exact value, reducing the increment from 0.5 to 0.25 will get a closer value to the exact one. Reducing the increments will result in smaller rectangles (thinner) following the curve more exact.



Now that we see that our math is sound, we can look at a Plunk with a demo displaying this.
Math integral demo - Plunk
In the sample the graph is displayed with Canvas in HTML 5. The following function in Javascript is used to display the integral and the midpoint rectangles:



   Graph.prototype.drawPolynomial = function(polynomialequation, a, b, c, d,
 increment, isIntegral, color, thickness, startx, endx){


        var totalArea = 0.0;

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

        context.beginPath();
        context.moveTo(this.minX, polynomialequation(a, b, c, d, this.minX));

        for(var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
          context.lineTo(x, polynomialequation(a, b, c, d, x));
        }

        context.restore();
        context.lineJoin = 'round';
        context.lineWidth = thickness;
        context.strokeStyle = color;
        context.stroke();
        context.restore();

        if (isIntegral){
            var context = this.context;
            context.save();
            this.transformContext();

            var currentY = 0.0;

            context.lineWidth = 0.1;
            context.strokeStyle = 'red';

            for(var x = startx; x < endx; x += increment) {
              context.beginPath();
              currentY = polynomialequation(a, b, c, d, (x+increment/2.0));
              context.rect(x, 0, increment, currentY);
              totalArea += increment * currentY;
              context.stroke();
            }           
      
        }

        return totalArea.toFixed(2);

      }


The following code is used to get the values for the coefficients of the polynomial equation and draw the polynomial function and the corresponding approximation rectangles for the integral.


  
     $(document).ready(function(){

      $("#btnDemo").click(function(){

        $("#a").val("0.05");
        $("#b").val("0.05");
        $("#c").val("0.05");
        $("#d").val("1");
        $("#increment").val("0.25"); 
        $("#startx").val("1.0"); 
        $("#endx").val("4.0"); 


        $("#btnGraph").click();

      });
     
      $("#btnGraph").click(function(){

        var a,b,c,d,increment,startx,endx = 0;

        a = parseFloat($("#a").val());
        b = parseFloat($("#b").val());
        c = parseFloat($("#c").val());
        d = parseFloat($("#d").val());
        increment = parseFloat($("#increment").val());
        startx = parseFloat($("#startx").val());
        endx = parseFloat($("#endx").val());
       
        var myGraph = new Graph({
         canvasId: 'Graph',
         minX: -10,
         minY: -10,
         maxX: 10,
         maxY: 10,
         unitsPerTick: 1
        });  

          var totalArea = myGraph.drawPolynomial(function(a,b,c,d,x){ 
           return ((a*x*x*x) + (b * x*x) +  c*x + d * 1.0).toFixed(2); 
           }, a, b, c, d, increment, true, 'blue', 1.0,  startx, endx);   

         $("#detailsInfo").append("Total area under graph: " + totalArea);

      

     
      });
     
     });
     


There is a lot of code to digest here, see through the code in the Plunk the article points to. The key points here is that we pass in a function as a delegate to be our Polynomial equation. We also approximate the integral (area) by summing up the rectangles below it.

Note that this demo also supports calculating the integral when it dips below the positive y axis!


Fix of reloading functionality

One issue with Canvas and a central one is the fact that the Canvas in HTML 5 is a rasterized grid. It is more like a single layer Photoshop image than a vectorized canvas like Illustrator. With that fact in mind, clearing the Canvas for a new redrawing functionality proved hard. In addition, I also use a transformation here from View-Coordinates to Object-Coordinates. A brute force redrawing is therefore preferred. The following ReloadCanvas method will fix this!

     function ReloadCanvas(canvasId){
        //debugger;

        var oldCanvas = document.getElementById(canvasId);
        console.log("Old canvas: " + oldCanvas);
        var newCanvas = document.createElement('canvas');
        var oldWidth = 500;
        var oldHeight = 500;
        if (oldCanvas){
          oldWidth = oldCanvas.width;
          oldHeight = oldCanvas.height;
          oldCanvas.parentNode.removeChild(oldCanvas);
        }
        newCanvas.id = 'Graph';
        newCanvas.width = oldHeight;
        newCanvas.height = oldWidth;
        document.body.appendChild(newCanvas);
      }



We detach the old canvas and insert a new one into the DOM (Document Object Model). I use here old api methods, you could also resort to more use of jQuery of course. Note that I try to get the old Canvas width and height and copy this to the new blank Canvas that I insert. You must use parentNode here to to the appendChild and removeChild methods to do the replacement of Canvas. This way, we can paint the Canvas again with a fresh new Canvas and have a simpler demo! I have updated the Plunk with a fixed Fork below:
Plunk - Integral math demo app

This demo also supports not only a convenient reload method to make the demo easier to test out, but also supports "negative integrals", i.e. sections where the integral dips below the x-axis as shown in the following image:

Note about accuracy

The total area calculated uses some rounding here. I used the .toFixed(2) to stick to a precision of 0.01. You can try out .toFixed(3) to test out a better precision. That will calculate even more precise the calculated area. The increments should of course be small and you will also see that some small values are still imprecise. We calculate the y value to be the midpoint of the polynomial f(x) and the midpoint should follow the curve as good as possible.

Actually this integral demo app can support other equations that just polynomials. We could support for example trigonometric functions and so on also. I will look at this in a future demo+article!
So there you have it, Canvas and Js can tutor kids and students math concepts in Calculus quite elegant in a web browser. We are seeing that Javascript and HTML 5 are now just as powerful as Java applets in the good old days to describe different concepts and prove that once again Math is fun, especially when computers also come into play!

Note for students


What we have used in this demo is the calculation of definite integrals using the Midpoint Rule and Riemann sum. You can read more about it here. This is standard 1st year Calculus syllabus.
Riemann Sums (Wikipedia)

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: