views:

819

answers:

2

Ok so I don't understand why Firefox is saying that the $("#canvas")[0].getContext('2d'); is undefined. I put it out of the function so that all of the function can access it but here the ctx is still undefined.

(function($) {
        // Undefined
     var ctx = $('#canvas')[0].getContext("2d");
     var x = 150;
     var y = 150;
     var dx = 2;
     var dy = 4;
     $(function() {
      setInterval(draw, 10);
     })
     function draw() {
      ctx.clearRect(0,0,300,300);
      ctx.beginPath();
      ctx.arc(x,y,10,0,Math.PI*2,true);
      ctx.closePath();
      ctx.fill();
      x+=dx;
      y+=dy;
     }
    })(jQuery);

However when I transferred the location of ctx to the unnamed function, the ctx is not undefined:

(function($) {
     var ctx;
     var x = 150;
     var y = 150;
     var dx = 2;
     var dy = 4;
     $(function() {
              //Not Undefined
      ctx = $("#canvas")[0].getContext('2d');
      setInterval(draw, 10);
     })
     function draw() {
      ctx.clearRect(0,0,300,300);
      ctx.beginPath();
      ctx.arc(x,y,10,0,Math.PI*2,true);
      ctx.closePath();
      ctx.fill();
      x+=dx;
      y+=dy;
     }
    })(jQuery);

Whats wrong with the first code? I mean var ctx is declared on the top. So that would make it a global variable. Hmm the error that I got was $("#canvas")[0] is undefined. Means that it can't access the #canvas.. Why??

+3  A: 

This is because in your first call you're actually creating a Function object which will be processed only after the DOM has loaded, in another context.

That anonymous function will be called when all the elements in the page have already loaded, so the caller will be a jQuery core function and its context is completely different from the one you're coding here.

I'd suggest wrapping everything inside the $() call, so this should work:

(function($) {
        $(function() {
            var ctx = $("#canvas")[0].getContext('2d');
            var x = 150;
            var y = 150;
            var dx = 2;
            var dy = 4;

            setInterval(draw, 10);

            function draw() {
                    ctx.clearRect(0,0,300,300);
                    ctx.beginPath();
                    ctx.arc(x,y,10,0,Math.PI*2,true);
                    ctx.closePath();
                    ctx.fill();
                    x+=dx;
                    y+=dy;
            }
        });
})(jQuery);
Seb
What Seb says is correct. the first one doesn't work because at the time that you try to get your canvas object it hasn't actually been loaded yet.
Darko Z
While you're right about wrapping the code inside the callback, you are *wrong* about the context issue. The problem is probably that the javascript code is being run before the canvas tag is declared. I've demonstrated this in my answer.
brianpeiris
Thanks. I was just experimenting with the way this thing works. I understand it now.
rymn
@Seb Sorry if I'm nagging you about this but please consider editing your answer to correct or remove the remarks about context. Unless I'm completely mistaken they are simply incorrect and misleading. Thanks.
brianpeiris
@brian I'm really not sure about the context issue; I believed I was right but now I doubt it and should test it.@Rymn, can you tell us if the real problem was that you were trying to access the canvas before it was actually created? If so, please mark brian answer as correct instead of mine. Thanks.
Seb
+3  A: 

I think you've mistaken the problem. It is not that you have misunderstood your variable context but probably that you are running the javascript before your canvas tag has been declared.

The following code demonstrates the problem. It will display the message "canvasOne is undefined!" because we are trying to access canvasOne before it is declared (Note the placement of the <canvas> tags).

I've created a hosted demo here: http://jsbin.com/afuju (Editable via http://jsbin.com/afuju/edit)

<html>
  <head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;
  </head>
  <body>
    <script>
      /* 
        The following line of code is run as soon as the browser sees it.
        Since the "canvasOne" tag is not declared yet, the variable will be undefined.
      */
      var canvasOne = $('#canvasOne')[0];

      $(function() {
        // The following code is run after the whole document has finished loading.
        if (canvasOne === undefined) {
          alert('canvasOne is undefined!');
        }
        else {
          canvasOne.getContext("2d").fillRect(5, 5, 15, 15);
        }
      });
    </script>
    <canvas id="canvasOne"></canvas>



    <canvas id="canvasTwo"></canvas>

    <script>
      /* 
        The following line of code is run as soon as the browser sees it.
        But since the "canvasTwo" tag *is* declared above, the variable will *not* be undefined.
      */
      var canvasTwo = $('#canvasTwo')[0];

      $(function() {
        // The following code is run after the whole document has finished loading.
        if (canvasTwo === undefined) {
          alert('canvasTwo is undefined!');
        }
        else {
          canvasTwo.getContext("2d").fillRect(5, 5, 15, 15);
        }
      });
    </script>



    <script>
      $(function() {
        /*
          The following code is run after the whole document has finished loading.
          Hence, the variable will *not* be undefined even though the "canvasThree" tag appears after the code.
        */
        var canvasThree = $('#canvasThree')[0];
        if (canvasThree === undefined) {
          alert('canvasThree is undefined!');
        }
        else {
          canvasThree.getContext("2d").fillRect(5, 5, 15, 15);
        }
      });
    </script>

    <canvas id="canvasThree"></canvas>
  </body>
</html>
brianpeiris
Thanks Brian Peiris!
rymn
+1 for demo deployed
Seb