Note that there are some explanatory texts on larger screens.

plurals
  1. POJQuery animate - any way to "stall" the complete trigger?
    primarykey
    data
    text
    <p>Imagine I have a viewport with a defined width and height. I clone an element out of view on the right side, and fly it across the viewport at a random <code>y</code> position with code like this:</p> <pre><code> ... .css({ 'left': BASE_NODE_INIT_LEFT_PX, 'top' : rand(BASE_NODE_INIT_TOP_MIN_PX, BASE_NODE_INIT_TOP_MAX_PX) + 'px', 'width': _width + 'px', 'height': _height + 'px', }) .animate({ left: BASE_NODE_ANIMATE_DISTANCE_X_PX } ... </code></pre> <p>Simple enough animation. Here's the fun part: on each step I would like to apply some physics to this element. </p> <p>Something like this: </p> <pre><code> ... step:function(currentStep){ if($(this).data('animating-wind') !== true) { $(this).data('animating-wind',true); var wind = (rand(1,2) == 2) ? '+=' + rand(1, 100) + 'px' : '-=' + rand(1, 100) + 'px'; $(this).animate({ 'top': wind, 'text-indent': wind, },{ duration: 500, complete: function(){ $(this).data('animating-wind',false); }, queue: false }); } } ... </code></pre> <p>Basically what happens is instead of flying straight across from right to left, it slows down, speeds up, and raises and dips randomly, just as I'm intending. </p> <p>The problem I am facing is that sometimes the "wind" is strong enough so that the element is still visible on the viewport when the number of steps has reached the total calculated steps, and it'll just disappear (which happens in my <code>complete:function(){ ...$(this).remove(); ...}</code></p> <p>Obviously what's happening is that JQuery thinks the animation is complete because it calculated the steps and said "I'm animating this object this many pixels over this many milliseconds over this many steps - it's there". But the wind animation is <strong>outside the animation queue</strong> so this animation process is none-the-wiser.</p> <p>What I would like is to begin the animation and just keep animating until the element has exited the viewport in any direction - once it is no longer visible, either from its initial flight path or from the wind blowing it off screen, I'll detect it and trigger the <code>onComplete</code> callback. The only thing I can think of is to put this animation inside a function and in the <code>complete:function(){}</code> make a recursive call to itself, then inside the <code>step:function(){}</code> I'd do the "visible in the viewport" check and call <code>stop(true,false)</code> if <code>true</code>. This just seems like a very expensive check - running that calculation 100+ times in 400-1200ms might make the animation choppy so I'm looking for a more elegant solution.</p> <p><strong>TL;DR:</strong> How do I keep animating something so long as it hasn't reached its destination yet due to additional animations being set on it?</p> <p><strong>UPDATE:</strong> I applied <a href="https://stackoverflow.com/questions/6969218/jquery-animate-any-way-to-stall-the-complete-trigger/6971055#6971055">@mu is too short's idea</a> and came up with this: </p> <pre><code>/** * Create a new clone of the master div for user interaction. Position it * randomly off the canvas, and animate it across at a random speed. */ function spawn_target() { spawn_timeout = setTimeout(function() { var bonus = (rand(1, BONUS_ODDS) == BONUS_ODDS) ? ' ' + BONUS_CLASS : ''; var _img_src = (bonus.length &gt; 0) ? BONUS_NODE_IMG_SRC : BASE_NODE_IMG_SRC; var _width = $('#' + BASE_NODE_ID).width(); _width = Math.floor(rand(_width / 3, _width)); var _height = _width; var _framerate = 10 - Math.floor(_height/10); var _clone = $('#' + BASE_NODE_ID).clone().addClass(CLONE_CLASS + bonus).attr('id', CLONE_ID).appendTo('#' + CANVAS_ID).css({ 'left': BASE_NODE_INIT_LEFT_PX, 'top': rand(BASE_NODE_INIT_TOP_MIN_PX, BASE_NODE_INIT_TOP_MAX_PX) + 'px', 'width': _width + 'px', 'height': _height + 'px', }) $(_clone).children('img').attr('src', _img_src); /** * Handle the actual flight across the viewport * @param object _this The clone we are animating manually * @return object pointer This contains the interval so we can clear it later */ function fly(_this) { var animating_wind = false; var pointer = { timer_id: null }; pointer.timer_id = setInterval(function() { // Get rid of the node if it is no longer visible in the viewport if (!$(_this).is(':onviewport')) { clearInterval(pointer.timer_id); $(_this).remove(); adj_game_data(GAME_DATA_LIVES_ID, -1); check_lives(); spawn_target(); } // Move node along with slight realism var distance = rand(FLY_DISTANCE_MIN, FLY_DISTANCE_MAX); $(_this).css('left', '-=' + distance + 'px'); // Only trigger the wind animation when it is idle if (animating_wind !== true) { animating_wind = true; // Setup the wind physics var _wind_power = rand(WIND_POWER_MIN, WIND_POWER_MAX); var _wind_dir = (rand(1, 2) == 2) ? '+=' : '-='; // Override wind direction to keep node inside viewport if(($(_this).offset().top + $(_this).height() + _wind_power) &gt; CANVAS_HEIGHT) { _wind_dir = '-='; } if(($(_this).offset().top - _wind_power) &lt; CANVAS_TOP_BUFFER_PX) { _wind_dir = '+='; } var _wind = _wind_dir + _wind_power + 'px'; // Apply the wind physics and don't let the node break the top or bottom // boundaries of the viewport $(_this).animate({ 'top': _wind }, { duration: WIND_ANIMATION_DURATION, complete: function() { animating_wind = false; }, queue: false }); } }, _framerate); return pointer; } $(_clone).data('interval', fly(_clone)); }, rand(SPAWN_TARGET_TIMEOUT_MIN, SPAWN_TARGET_TIMEOUT_MAX)); } </code></pre> <p>Here's what I have so far: <a href="http://jsfiddle.net/AlienWebguy/DmtQ7/embedded/result/" rel="nofollow noreferrer">http://jsfiddle.net/AlienWebguy/DmtQ7/embedded/result/</a></p> <p>I like this idea though it seems like JQuery should have something built-in, which is what I was hoping for. Now, instead of <code>$(obj).stop()</code> I have to <code>clearInterval($(obj).data('interval').timer_id);</code>. *scratches head...</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload