Alecg_O
Alecg_O

Reputation: 1041

Can't call Javascript function twice

I'm trying to write a function to slowly move an image around the screen. The relevant html is as follows:

var dom, timer;

    function initImage() {
        dom = document.getElementById('animate').style;
        dom.position = 'absolute';
        dom.top = "165px";
        dom.left = "767px";
        regulate(1115,165);
        regulate(1115,540);
        regulate(767,540);
        regulate(767, 165);
    }
    
    function regulate(xfinal, yfinal) {
        var timer = setInterval(function() {moveImage(xfinal,yfinal)}, 1);
        return true;
    }

    function moveImage(xfinal, yfinal) {
        var x = parseInt(dom.left.match(/\d+/));
        var y = parseInt(dom.top.match(/\d+/));
        
        if ((x == xfinal) && (y== yfinal)) {clearInterval(timer);}
        else {
            if (x != xfinal) {
                if (x < xfinal) {x++;}
                else {x--;};
                dom.left = x + "px";}
            else {
                if (y < yfinal) {y++;}
                else {y--;};
                dom.top = y + "px";};
            };
        return true;
    }
<img src='http://placehold.it/200' alt='Sir Victor' width=50 height=50
     id='animate' onload='initImage();' style='position:absolute;'/>

This algorithm works fine for the first function call to regulate(), but when I uncomment one of the other three and try to run it, the image either doesn't move at all, or it moves faster than normal, but only along the first path. Is there some reason the function won't act as expected the second time?

I'm new to javascript, so feel free to point out anything else that seems dumb or over-complicated as well.

Upvotes: 0

Views: 900

Answers (2)

Miguel
Miguel

Reputation: 20633

Instead of calling all the regulate functions at once; set up a queue.

var dom;
var timer;
var queueIndex = 0;
var positions = [
    [300, 0],
    [300, 100],
    [0, 100],
    [0, 0]
];

function initImage() {
    dom = document.getElementById('animate').style;
    dom.position = 'absolute';
    dom.top = "0px";
    dom.left = "0px";
    regulate.apply(null, positions[queueIndex]);
}

function regulate(xfinal, yfinal) {
    timer = setInterval(moveImage, 1, xfinal, yfinal);
    return true;
}

function moveImage(xfinal, yfinal) {
    var x = parseInt(/\d+/.exec(dom.left) || 0);
    var y = parseInt(/\d+/.exec(dom.top) || 0);

    if ((x == xfinal) && (y == yfinal)) {
        clearInterval(timer);
        queueIndex++;
        if (positions[queueIndex]) {
            regulate.apply(null, positions[queueIndex]);
        }
    } else {
        if (x != xfinal) {
            if (x < xfinal) {
                x++;
            } else {
                x--;
            };
            dom.left = x + "px";
        } else {
            if (y < yfinal) {
                y++;
            } else {
                y--;
            };
            dom.top = y + "px";
        };
    };
    return true;
}
<img src='https://libcom.org/files/images/library/black-square.jpg' alt='Sir Victor' width=50 height=50 id='animate' onload='initImage();' style='position:absolute;' />

Upvotes: 0

jfriend00
jfriend00

Reputation: 707158

One problem is that you can't pass the contents of the timer variable to setInterval() in this line:

 var timer = setInterval(moveImage, 1, xfinal, yfinal, timer);

because the value of timer is not available until after setInterval() returns.

Thus, you will just be passing undefined for that value so your clearInterval() in moveImage() will not work properly.

The usual way to solve this problem is to declare the timer variable in some higher level shared scope so it will be available as needed.

Upvotes: 2

Related Questions