Search code examples
javascripthtml5-canvas

why am i getting Uncaught TypeError: this.ctx.beginPath is not a function error with ImageData?


I am trying to draw a simple line in a javascript class.

import Draw from "./draw.js";
//import Database from "./database.js";
import Values from "./values.js";
import Calculate from "./calculate.js";

document.querySelector("#myBtn").addEventListener("click", updateCanvas);

function updateCanvas() {
    var startTime = performance.now();
    const values = new Values();
    const calculate = new Calculate(values.start,values.end,values.byuk,values.syuk,values.tekilyuk,values.tekilyukyeri,400);
    calculate.calculateSupport();
    const myDrawing = new Draw(values.ctx,values.canvasData);
    myDrawing.drawMyLine(1,200,399,200);
    
    //const cizgi = new Draw(startx, starty,endX, endY,canvasData,ctx);
}
body {
    background-color: #F7B054;
  }
  
  h1 {
    color: white;
    text-align: center;
  }
  
  p {
    font-family: verdana;
    font-size: 20px;
  }

  #canvas{
    border: 0px;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <link rel="stylesheet" href="./css/cizim.css" />
        <title>Line</title>
        
    
    </head>
    <body>
<table align="center" width="1200" border="0">
  <tbody>
    <tr>
      <td width="500"><div align="center"><canvas width ="400" height="400" id="canvas" style="border:1px solid #d3d3d3;">Your browser does not support the HTML5 canvas tag.
          
        </canvas>
           
          </td>
      <td><table>
          <tbody>
              <tr>
                <td><label for="fname">Başlangıç Mesneti:</label></td>
                <td>
                    <input type="radio" id="msm" name="first" value="msm" checked="checked">
                    <label for="css">Mafsallı Sabit Mesnet</label>
                    <input type="radio" id="mhm" name="first" value="mhm">
                    <label for="javascript">Mafsallı Hareketli Mesnet</label>
                    <input type="radio" id="ank" name="first" value="ank">
                    <label for="html">Ankastre Mesnet</label>
                </td>
              </tr>
                <tr>
                <td><label for="fname">Bitiş Mesneti:</label></td>
                <td>
                    <input type="radio" id="msm" name="second" value="msm" checked="checked">
                    <label for="css">Mafsallı Sabit Mesnet</label>
                    <input type="radio" id="mhm" name="second" value="mhm">
                    <label for="javascript">Mafsallı Hareketli Mesnet</label>
                    <input type="radio" id="ank" name="second" value="ank">
                    <label for="html">Ankastre Mesnet</label>
                </td>
                </td>
              </tr>
              <tr>
                <td><label for="fname">Başlangıç:</label></td>
                <td><input type="text" id="start" name="fname"></td>
              </tr>
              <tr>
                <td><label for="fname">Bitiş:</label></td>
                <td><input type="text" id="end" name="sname"></td>
              </tr>
                <tr>
                <td><label for="fname">Başlangıç Yükü:</label></td>
                <td><input type="text" id="byuk" name="sname"></td>
              </tr>
                  </tr>
                <tr>
                <td><label for="fname">Bitiş Yükü:</label></td>
                <td><input type="text" id="syuk" name="sname"></td>
              </tr>
      <tr>
                <td><label for="fname">Tekil Yük:</label></td>
                <td><input type="text" id="singleLoad" name="sname"></td>
              </tr>
      <tr>
                <td><label for="fname">Tekil Yük Yeri:</label></td>
                <td><input type="text" id="singleLoadPlace" name="sname"></td>
              </tr>
              <tr>
                <td>&nbsp;</td>
                <td><button id="myBtn">Hesapla</button></td>
              </tr>
          
          
          
          </tbody>
          </table>
    </td>
    </tr>
    
  </tbody>
</table>
<script type="module" src="js/canvas.js"></script>
    </body>
</html>

As you can see canvas.js file works with 3 other .js files values.js get information from html inputs, calculate.js makes calculations and returns them and finally draw.js file makes the drawing however i am having problem with drawing part.

export default class Draw {
  constructor(canvasData,ctx) {
    this.canvasData = canvasData;
    this.ctx = ctx;
  }
  drawMyLine(startx, starty,endX, endY){
    //console.log(this.ctx);
    this.ctx.beginPath();
    this.ctx.lineWidth = 1;
    this.ctx.strokeStyle = 'red';
    this.ctx.moveTo(startx, starty);
    this.ctx.lineTo(endX,endY);
    this.ctx.stroke();    
  }
  drawPixel (x, y, r, g, b, a) {
    var index = (x + y * canvasWidth) * 4;
    //pixelDensity(1);
    canvasData.data[index + 0] = r;
    canvasData.data[index + 1] = g;
    canvasData.data[index + 2] = b;
    canvasData.data[index + 3] = a;
  }
}

My values.js file is:

export default class Values {
  constructor() {
    this.first = document.querySelector('input[name="first"]:checked').value;
    this.second = document.querySelector('input[name="second"]:checked').value;
    this.canvas = document.getElementById("canvas");
    //this.canvas_n = document.getElementById("canvas-n");
    //this.canvas_v = document.getElementById("canvas-v");
    //this.canvas_m = document.getElementById("canvas-m");
    this.start = isNaN(parseInt(document.getElementById("start").value)) ? 0: parseInt(document.getElementById("start").value);
    this.end = isNaN(parseInt(document.getElementById("end").value))? 0 : parseInt(document.getElementById("end").value);
    this.byuk = isNaN(parseInt(document.getElementById("byuk").value))? 0 : parseInt(document.getElementById("byuk").value);
    this.syuk = isNaN(parseInt(document.getElementById("syuk").value))? 0 : parseInt(document.getElementById("syuk").value);
    if(isNaN(parseInt(document.getElementById("singleLoad").value))){
        this.tekilyuk = 0;
        this.tekilyukyeri = 1;
    }else{
        this.tekilyuk = parseInt(document.getElementById("singleLoad").value);
    }
    if(isNaN(parseInt(document.getElementById("singleLoadPlace").value))){
        this.tekilyuk = 0;
        this.tekilyukyeri = 1;
    }else{
        this.tekilyukyeri = parseInt(document.getElementById("singleLoadPlace").value);
    }
    this.canvasWidth = canvas.width;
    this.canvasHeight = canvas.height;
    this.ctx = canvas.getContext("2d"); 
    this.canvasData = this.ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight);
  }
}

My calculate.js file:

export default class Calculate {
    constructor(start=0,end=0,byuk=0,syuk=0,tekilyuk=0,tekilyukyeri=0,beam=400) {
        this.start=start;
        this.end=end;
        this.byuk=byuk;
        this.syuk=syuk;
        this.supportLeft =0;
        this.supportRight =0;
        this.distrubutedLoad=0;
        this.supportTotal=0;
        this.tekilyuk = tekilyuk;
        this.tekilyukyeri=tekilyukyeri;
        this.beam=beam;
    }
    calculateSupport() {
        switch(this.byuk==this.syuk){
            case true:
                var a =this.byuk;
                var b =this.syuk;
                if(a==0 && b==0){
                    this.supportTotal=this.tekilyuk;
                    this.supportLeft = this.tekilyuk*(this.beam-this.tekilyukyeri)/this.beam;
                    this.supportRight = this.supportTotal-this.supportLeft;
                }else{
                    this.distrubutedLoad = ((this.end-this.start)*a);
                    this.supportTotal=this.distrubutedLoad+this.tekilyuk;
                    this.supportLeft = (this.distrubutedLoad *(this.beam-((this.end+this.start)/2))+(this.tekilyuk*(this.beam-this.tekilyukyeri)))/this.beam;
                    this.supportRight = this.supportTotal-this.supportLeft;
                }
                console.log("byuk: "+this.byuk+" syuk: "+this.syuk+" Toplam yük: "+this.supportTotal+" Sol mesnet: "+this.supportLeft+" Sağ mesnet: "+this.supportRight);
                break;
            case false:
                var a =this.byuk;
                var b =this.syuk;
                var distance = (this.end)-(this.start);
                if(a==0 && b==0){
                    var mGravity = 0;
                    this.distrubutedLoad = 0;
                }else{
                    var mGravity = distance*(2*b+a)/(3*(b+a));
                    this.distrubutedLoad = ((this.end-this.start)*(a+b)/2);
                }
                this.supportTotal=this.distrubutedLoad+this.tekilyuk;
                
                var startToGravity = this.start+mGravity;
                this.supportLeft = ((this.distrubutedLoad*(this.beam-startToGravity))+(this.tekilyuk*(this.beam-this.tekilyukyeri)))/this.beam;
                this.supportRight = this.supportTotal-this.supportLeft;
                console.log('a: '+a+' b: '+b+' yukler eşit değil, total: '+this.supportTotal+' ağırlık merkezi: '+startToGravity+'A mesnedi: '+this.supportLeft+' B mesnedi: '+this.supportRight);
                break;
            default:
                console.log("default");
               }
    }
}

Before this i was doing all my work in a single javascript file and it was getting too big to handle so i decided to put codes in different javascript files in classes. However now i am getting problem with my draw.js file which i made to handle drawings according to incoming data. When i try to draw a line with the drawMyLine function in this class i am getting

Uncaught TypeError: this.ctx.beginPath is not a function at Draw.drawMyLine (draw.js:8:11)

error.

So decided to log the ctx with console.log(this.ctx) and get the fallowing info show belown

Imagedate

So my question is am i doing something wrong with class or getting wrong data for beginPath() function?

PS: Sorry i dont know how to add 2 javascript files in 1 snippet

Thanks in advance


Solution

  • Thanks to @obscure i realised i was instanting the class wrong after changing the constructor of draw.js from constructor(canvasData,ctx) to constructor(ctx,canvasData) it worked.