Question

I'm trying to create a basic strobe light in the browser using the canvas element. I'm expecting setInterval to keep calling the changeBG function to change to a random background color. This function works fine on its own, but not when called by setInterval. I tried pulling up this page in firebug and it told me that colors was undefined. Here's the problematic code.

<html>
<head>
    <title>Strobe!</title>
    <link rel="stylesheet" type="text/css" href="reset.css" />
    <script type="text/javascript">
        function changeBG(colors,ctx,canvas) {                
            ctx.fillStyle = colors[Math.floor(Math.random()*colors.length)]
            ctx.fillRect(0,0,canvas.width,canvas.height)
        }

        function eventLoop() {
            var colors = ['#000000','#ff0000','#00ff00','#0000ff','#ffff00','#ff00ff','#00ffff']
            var canvas = document.getElementById('mainCanvas')
            var ctx = canvas.getContext('2d')
            canvas.width = window.innerWidth
            canvas.height = window.innerHeight
            //changeBG(colors,ctx,canvas)
            setInterval("changeBG(colors,ctx,canvas)", 1000);               
        }
    </script>
</head>
<body onload="eventLoop()">
    <canvas id="mainCanvas" width="800" height="600">
    </canvas>
</body>

I'm new to javascript so any insight what so ever would be highly appreciated.

Was it helpful?

Solution

You code would work if you weren't passing a string to setInterval. Because it is in a string, it can't create a closure on the variables you are trying to use.

Try this instead:

setInterval(function() {
    changeBG(colors,ctx,canvas);
}, 1000)​;​

Using this method, you are passing an anonymous function to setInterval. It will call this function once per interval, which is 1000 miliseconds in this example.

The function can use the colors, ctx, and canvas variables because they exist in the scope where the function is declared. This creates a closure so that those variables still exist (as far as our anonymous function is concerned) when it is called over and over again.

For now, you can probably just use this code. For further understanding, I suggest researching anonymous functions and closures.

OTHER TIPS

You can pass directly a function, instead of a string to evaluate, as

setInterval(function(){changeBG(colors,ctx,canvas)}, 1000);

Good luck provoking epilepsy to someone

The root problem is variable scope when the interval code is executed, colors and the other variables are not in scope.

Try this:

<html>
<head>
<title>Strobe!</title>
<link rel="stylesheet" type="text/css" href="reset.css" />
<script type="text/javascript">           
    function eventLoop() {
        var colors = ['#000000','#ff0000','#00ff00','#0000ff','#ffff00','#ff00ff','#00ffff']
        var canvas = document.getElementById('mainCanvas')
        var ctx = canvas.getContext('2d')
        canvas.width = window.innerWidth
        canvas.height = window.innerHeight            
        setInterval(function() {                
            ctx.fillStyle = colors[Math.floor(Math.random()*colors.length)]
            ctx.fillRect(0,0,canvas.width,canvas.height)
        }, 1000);               
    }    
</script>
</head>
<body onload="eventLoop()">
    <canvas id="mainCanvas" width="800" height="600">
    </canvas>
</body>

try this UPDATED setInterval(function(){changeBG(colors,ctx,canvas)}, 1000);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top