skip to Main Content

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!

2

Answers


  1. This is because your Canvas.Matrix object contains only integer keys (0, 1, …, 49), but your x and y are real numbers (9.1, 6.7 etc).

    So, you have to floor or ceil x and y using Math.floor or Math.ceil or Math.round before. Math.floor rounds down, Math.ceil rounds up, Math.round rounds up or down depending on division mod.

    Login or Signup to reply.
  2. 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.

    See the snippet for edited if() parameters.

    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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search