0

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!

1
  • 1
    JS programming note: don't use capital letters for variables or property names (also don't use var, use let for reassignable and const for fixed assignment). By convention, those are reserved for class/prototype names. Same for new Array: this code looks like "someone used JS syntax to write a completely different language". Commented Oct 20, 2024 at 2:07

2 Answers 2

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.

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>

Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.