[quote=“Grnadpa, post:8, topic:230220, full:true”]
Following code show dot exactly once. Had to alter interface to add the arguments of course.[/quote]
Okay, let’s follow things through to find out what’s happening.
var interval = window.setInterval(showSpots(ctx, x,y,r,i),200);
setInterval is assigned the return value of the showSpots function. The showSpots function shows one spot, as it’s supposed to, and returns nothing. That undefined return is what gets given to the setInterval function.
That is different from what you want to achieve. What you want to achieve is to have a function assigned to setInterval, so that it is that function (which we’ll call a wrapper) that gets called every 200 milliseconds.
That wrapper function will then call showSpots, with the appropriate arguments, so that wrapper function will also need access to those variables. Because setInterval is called at some later time, there is no access to those previously defined variables, unless we involve horrible globals. What can we do instead to give the wrapper function access to those variables?
Closure, is a technique that lets us give a function access to local variables. When a function is created, it retains access to the local scope. For example:
function wrapper(foo) {
var bar = "bar";
return function closure() {
console.log(foo, bar);
};
}
var func = wrapper("foo");
func(); // "foo", "bar"
The closure function gets assigned to the func
variable. That closure function (in the guise of func
) retains access to the function arguments, and other variables within that scope. See this closure documentation for more.
What we want, is to give that closure function to setInterval, so that setInterval will run that closure function and the closure function can then call showSpots for us.
We are then faced with another problem where the updated variables for x, y, and i are not being updated. This is because they are function arguments that have been passed by value. Only if they are an object that has been passed by reference will such changes remain in place.
There are two different ways to deal with this. One is to place the variables that will change in to a object, so that you can retrieve the values and change the values in that object. Another solution is to not pass the variables to the function so that the function will instead find those variables from the outer scope. That second solution seems to be a good fit for what’s happening here.
Lastly, the interval variable cannot be found, so we’ll place it as a property on the ctx object instead.
We end up with the following code:
function showSpotsWrapper(ctx, x, y, r) {
var i = 0;
return function showSpots() {
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
x = x + 10;
y = y + 5;
i += 1;
if (i === 5) {
window.clearInterval(ctx.interval);
}
};
}
...
ctx.interval = window.setInterval(showSpotsWrapper(ctx, x, y, r), 200);
And in case you’re interested in the technique where you pass an object, that would work like this:
function showSpots(spotInfo) {
spotInfo.ctx.arc(spotInfo.x, spotInfo.y, spotInfo.r, 0, 2 * Math.PI);
spotInfo.ctx.fill();
spotInfo.x += 10;
spotInfo.y += 5;
spotInfo.i += 1;
if (spotInfo.i === 5) {
window.clearInterval(spotInfo.ctx.interval);
}
}
function showSpotsWrapper(ctx, x, y, r) {
var spotInfo = {ctx: ctx, x: x, y: y, r: r, i: 0};
return function closure() {
showSpots(spotInfo);
};
}
...
ctx.interval = window.setInterval(showSpotsWrapper(ctx, x, y, r), 200);