javascripthtmltypeerrorundefined

Cannot Read Properties of undefined in a 2-Dimensional Matrix, HTML & Javascript


I'm working on creating a pixel-based light in the dark simulation with JavaScript to improve my coding skills. The goal is to create a bubble of light around the cursor as it moves. I'm only rendering a small portion around the cursor to ensure real-time results. I tried to create this code as scalable and friendly as possible, as even the light of the cursor and resolution of the pixels and be customized. Here is my code:

var Canvas = {
  Element: document.createElement("canvas"),
  Width: 500,
  Height: 500,
  Style: "border: 1px solid black;",
  Resolution: 10,
  Matrix: [],
  Context: null,
};

var Light = {
  Intensity: 20,
};

document.body.appendChild(Canvas.Element);
Canvas.Element.style = Canvas.Style;
Canvas.Element.width = Canvas.Width;
Canvas.Element.height = Canvas.Height;

Canvas.Matrix = new Array(Canvas.Height / Canvas.Resolution).fill().map(() =>
  new Array(Canvas.Width / Canvas.Resolution).fill({
    Intensity: 0,
  })
);
console.log(Canvas.Matrix);

Canvas.Context = Canvas.Element.getContext("2d");

Canvas.Element.addEventListener("mousemove", function (event) {
  var Rect = Canvas.Element.getBoundingClientRect();

  var Mouse = {
    X: event.clientX - Rect.left,
    Y: event.clientY - Rect.top,
  };

  Canvas.Context.fillRect(0, 0, Canvas.Width, Canvas.Height);
  Canvas.Context.clearRect(
    Mouse.X - (Light.Intensity / 2) * Canvas.Resolution,
    Mouse.Y - (Light.Intensity / 2) * Canvas.Resolution,
    Light.Intensity * Canvas.Resolution,
    Light.Intensity * Canvas.Resolution
  );

  for (
    var x = Mouse.X / Canvas.Resolution - Light.Intensity / 2;
    x < Mouse.X / Canvas.Resolution + Light.Intensity / 2;
    x++
  ) {
    for (
      var y = Mouse.Y / Canvas.Resolution - Light.Intensity / 2;
      y < Mouse.Y / Canvas.Resolution + Light.Intensity / 2;
      y++
    ) {
      if (x || y <= 0) {
        CellDistance = Math.sqrt(
          Math.pow(Mouse.X - Light.Intensity / 2, 2) +
            Math.pow(Mouse.X - Light.Intensity / 2, 2)
        );
        Canvas.Matrix[x][y].Intensity = CellDistance;
      }
    }
  }
});

As you can see, I receive the following error:

Uncaught TypeError: Cannot read properties of 
undefined

I'm sure I've lost brain cells looking through this code as I'm positive I've defined Canvas.Matrix. I'm fairly new to coding a this is probably a stupid mistake. Any help is helpful. Thank you!


Solution

  • You are trying to access elements in your .Matrix that are outside it's 0 to 49 boundaries. This caused by your if() statement. You need to change it to ensure that your x and y values are between 0 to 49 before you use them to index into your .Matrix.

    There is also the need for Math.floor() around your x and y's as already pointed out by @egorgrushin.

    I suggest you take a closer look at your x, y values in your for() statements, to see if you are really getting what you expect. Since depending on where your mouse is, you are getting a lot of negative values, which can't use to index your matrix.

    See the snippet for edited if() statement.

    var Canvas = {
    
      Element: document.createElement("canvas"),
      Width: 500,
      Height: 500,
      Style: "border: 1px solid black;",
      Resolution: 10,
      Matrix: [],
      Context: null,
    
    };
    
    var Light = {
    
        Intensity: 20
    
    }
    
    document.body.appendChild(Canvas.Element);
    Canvas.Element.style = Canvas.Style;
    Canvas.Element.width = Canvas.Width;
    Canvas.Element.height = Canvas.Height;
    
    Canvas.Matrix = new Array(Canvas.Height / Canvas.Resolution).fill().map(() => new Array(Canvas.Width / Canvas.Resolution).fill({Intensity: 0}));
    // console.log(Canvas.Matrix);
    
    Canvas.Context = Canvas.Element.getContext("2d");
    
        Canvas.Element.addEventListener('mousemove', function(event){
    
          var Rect = Canvas.Element.getBoundingClientRect();
    
          var Mouse = {
    
                X: event.clientX - Rect.left,
                Y: event.clientY - Rect.top,
    
          }
    
          Canvas.Context.fillRect(0, 0, Canvas.Width, Canvas.Height);
          Canvas.Context.clearRect(Mouse.X - (Light.Intensity / 2) * Canvas.Resolution, Mouse.Y - (Light.Intensity / 2) * Canvas.Resolution, Light.Intensity * Canvas.Resolution, Light.Intensity * Canvas.Resolution)
    
          for(var x = Mouse.X / Canvas.Resolution - (Light.Intensity / 2); x < Mouse.X / Canvas.Resolution + (Light.Intensity / 2); x++){
    
            for(var y = Mouse.Y / Canvas.Resolution - (Light.Intensity / 2); y < Mouse.Y / Canvas.Resolution + (Light.Intensity / 2); y++){
    
                // EDIT This if() is letting you try to access your Matrix bounds
                // if(x || y <= 0){
                if( x >= 0 && x < Canvas.Matrix.length && y >= 0 && y < Canvas.Matrix[0].length ){
    
                    CellDistance = Math.sqrt(Math.pow(Mouse.X - (Light.Intensity / 2), 2) + Math.pow(Mouse.X - (Light.Intensity / 2), 2));
                    // EDIT Deal with fractional x and y values
                    // Canvas.Matrix[x][y].Intensity = CellDistance
                    Canvas.Matrix[Math.floor(x)][Math.floor(y)].Intensity = CellDistance
    
                }
            
            }
            
          }
    
        });
    <html>
    </html>