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>



Share this article on LinkedIn.

No comments:

Post a Comment