1

Brief explanation:

I've made a requestAnimation which alternatively has 2 callbacks depending on counter;

one of the callbacks will increment counter and the other will decrease it (always looping inside a certain range 0 // arr.length).

Everything works as expected until stopping and restarting the animation,
this is the code that activates and should store the requestAnimationFrame ( click() ):

function start() {
        if (!spiral) {
            spiral = window.requestAnimationFrame(animation);
        }
    }

function click() {
        if (spiral) {
            var trackSpiral = spiral;
            spiral = undefined;
            window.cancelAnimationFrame(spiral);

         } else {

          spiral = trackSpiral;
    /* (count > precedingCount || count == 0 ) ?
                    spiral = requestAnimationFrame(animation) :
                    spiral = requestAnimationFrame(animationReverse);*/              
         }
   }
        window.addEventListener('load', start)

        window.addEventListener('click', click)

As a workaround I've used a precidingCount var and depending on whether if it's increasing or not it can decide which requestAnimationFrame callback to fire;

Questions:

Can somebody explain why just storing and recalling the var assigned to requestAnimation doesn't work as I'd expect?

Is there a better pattern to stop-restart requestAnimation?

here's a working pen (to see the issue comment lines from 180 to 182)_

maioman
  • 18,154
  • 4
  • 36
  • 42
  • 3
    `requestAnimationFrame` gets you exactly one frame. It's more like `setTimeout` than `setInterval`. To get the next one, you have to ask for it again. Cancelling is only for the rare case where you want to cancel it before it executes, which will usually be a few dozen of milliseconds after the request. –  Aug 13 '15 at 10:20
  • Shouldn't you first `cancelAnimationFrame(spiral)`, only then `spiral = undefined`? – raina77ow Aug 13 '15 at 10:20
  • @raina77ow I agree; but it will also work the other way around.. – maioman Aug 13 '15 at 10:25
  • Somehow you're calling a `requestAnimationFrame` inside a setTimeout callback, not sure why you want to merge them this way, I think `requestAnimationFrame` inside a `setTimeout` will lose its ability to make the animation smooth. – fuyushimoya Aug 13 '15 at 10:32
  • What does `animation` do? –  Aug 13 '15 at 10:32
  • @torazaburo `animation` draws new elements – maioman Aug 13 '15 at 10:36
  • @fuyushimoya I'm using setTimeout to slow down animation – maioman Aug 13 '15 at 10:43

3 Answers3

1

After each tick, you must re-request the animation frame. requestAnimationFrame is not something like setInterval that you need to cancel.

var animating = false;

function tick() {
    if (!animating) return;
    animate();                          // do one step of animation
    window.requestAnimationFrame(tick); // request next frame
}

function click() { if (animating = !animating) tick(); }

window.addEventListener('load',  click);
window.addEventListener('click', click);
  • you're example looks like an elegant way to have a flag telling us whether `animating` is true , and eventually stop recursion when false ( I'm imagining this is what you meant because it's not in the code - [fiddle](http://jsfiddle.net/daxeuwuL/) ); more or less what I'm doing assigning requestAnimation to a variable and 'undefining' it when I stop; is this correct or am I missing something? – maioman Aug 13 '15 at 15:34
  • SOrry, I left out an important line to exit early from `tick` when `animating` is `false`. –  Aug 13 '15 at 16:44
  • Not exactly. The return value from RAF is pretty much useless, it provides nothing more than a way to prematurely cancel the currently pending request. You don't want to set and unset that variable. You want to have a flag which determines whether succeeding RAF calls are made. –  Aug 13 '15 at 16:45
  • Actually the [return from RAF](http://jsfiddle.net/maio/daxeuwuL/2/) is just the number of recursions ; I made question because I thought that there could be a method of window for actually accessing the method itself.. if i log `window.requestAnimationFrame.toString()` the console responds `"function () { [native code] }"` , what does it mean? – maioman Aug 13 '15 at 17:06
  • No, the return value from RAF is a fairly useless "request ID". `window.requestAnimationFrame.toString()` returns what it does because that's what it is, it's a function. –  Aug 13 '15 at 17:22
  • FYI my working code doesn't rely on return value, this is just the (naive) attempt I was making.. – maioman Aug 13 '15 at 17:29
0

Can somebody explain why just storing and recalling the var assigned to requestAnimation doesn't work as I'd expect?

You need to declare var out side of the functions, if the var is only declared in a function then it is restricted to that scope.

Is there a better pattern to stop-restart requestAnimation?

You cont need to stop/start, just don't request the next frame. for instances where there is an infinite loop you might want to use cancelAnimationFrame;

(function rAF(){
    // animate .... call again
    rAF_id = window.requestAnimationFrame(rAF)
}();
// .. wait ... cancel
setTimeout( window.cancelAnimationFrame(rAF_id), 5000)

The following code should start forwardAnimation, stop forwardAnimation, start reverseAnimation, stop reverseAnimation and repeat.

(function(callback1, callback2, animating) {

  callback = callback1;

  function click() {
    if (animating = !animating) {
      callback = callback !== callback1 ? callback1 : callback2;
      (function loop() {
        rAF = window.requestAnimationFrame(loop);
        callback();
      })();
    } else {
      window.cancelAnimationFrame(rAF);
    }
  }

  window.addEventListener("load", function load() {
    click();
    window.removeEventListener("load", load);
    window.addEventListener('click', click);
  });
}(forwardAnimation, reverseAnimation));

Working Example

SVG Vertigo(unfinished)

TarranJones
  • 4,084
  • 2
  • 38
  • 55
0

I think your approach is different from common usage. I recommend to call it when needed instead of start/stop.

I learned this lesson when I have created a animation library , which is very simple and small

https://github.com/allenhwkim/jsanimation

Usage

import {slideInRight} from 'jsanimation';
slideInRight(el);
allenhwkim
  • 27,270
  • 18
  • 89
  • 122