Kristian Vitozev
Kristian Vitozev

Reputation: 5971

Recursively call function returned as object

I have the following piece of code:

// Core Zoom Logic, independent of event listeners.
$.zoom = function(target, source, img) {
    var outerWidth,
        outerHeight,
        xRatio,
        yRatio,
        offset,
        position = $(target).css('position');

    // This part of code is omitted

    return {
        init: function() {
            outerWidth = $(target).outerWidth();
            outerHeight = $(target).outerHeight();
            xRatio = (img.width - outerWidth) / $(source).outerWidth();
            yRatio = (img.height - outerHeight) / $(source).outerHeight();
            offset = $(source).offset();
        },
        move: function (e) {
            var left = (e.pageX - offset.left),
                top = (e.pageY - offset.top);

            top = Math.max(Math.min(top, outerHeight), 0);
            left = Math.max(Math.min(left, outerWidth), 0);

            img.style.left = (left * -xRatio) + 'px';
            img.style.top = (top * -yRatio) + 'px';
        }, 
        automove: function() { 

          // can I recall this?

        }

    };
};

What I want to achieve is to add the following effect in automove() function:

$(img).animate({
  top: newTop,
  left: newLeft,
  }, 1000, function() {
    automove(); /* recall */
  });

But how to call automove again from it's body? Maybe I should completely change the way functions are declared in $.zoom function?

Upvotes: 0

Views: 123

Answers (2)

slebetman
slebetman

Reputation: 113866

If you want to recursively call automove() from inside itself the traditional method would be to use arguments.callee. So the code would look something like:

return {

    /* ... */

    automove: function() { 

      $(img).animate({
          top: newTop,
          left: newLeft,
        }, 1000,
        arguments.callee /* recall */
      );

    }
}

But in HTML5 this is deprecated and is actually illegal in strict mode. Instead you can simply give the function a name:

return {

    /* ... */

    automove: function myAutomove () { // <-- give it a name

      $(img).animate({
          top: newTop,
          left: newLeft,
        }, 1000,
        myAutomove /* recall */
      );

    }
}

Named function expression works in all browsers old and new and is much easier to read.


note:

If a function does not require parameters you can simply pass a reference to it as a callback instead of wrapping it in an anonymous function:

setTimeout(function(){ foo() },100); // <-- this is completely unnecessary

setTimeout(foo,100); // <-- just need to do this instead

Upvotes: 1

Arun P Johny
Arun P Johny

Reputation: 388316

Try

$.zoom = function(target, source, img) {
    var outerWidth,
        outerHeight,
        xRatio,
        yRatio,
        offset,
        position = $(target).css('position');

    // This part of code is omitted

    var fnInit = function() {
        outerWidth = $(target).outerWidth();
        outerHeight = $(target).outerHeight();
        xRatio = (img.width - outerWidth) / $(source).outerWidth();
        yRatio = (img.height - outerHeight) / $(source).outerHeight();
        offset = $(source).offset();
    };
    var fnMove = function (e) {
        var left = (e.pageX - offset.left),
            top = (e.pageY - offset.top);

        top = Math.max(Math.min(top, outerHeight), 0);
        left = Math.max(Math.min(left, outerWidth), 0);

        img.style.left = (left * -xRatio) + 'px';
        img.style.top = (top * -yRatio) + 'px';
    };
    var fnAutomove = function() { 
        $(img).animate({
            top: newTop,
            left: newLeft,
        }, 1000, function() {
            fnAutomove(); /* recall */
        });        
    }

    return {
        init: fnInit,
        move: fnMove, 
        automove: fnAutomove
    };
};

Upvotes: 1

Related Questions