Search code examples
javascriptpaperjsrequestanimationframe

Paper.js scale transform continues outside the onFrame event


I'm running into a bit of an odd issue with Paper.js - I'm using the library to scale the "petals" of a randomly generated flower while audio plays.

The issue crops up if the flower is "growing" and the user navigates to a different tab in the browser. Even though it appears that the onFrame event is not firing when the window is out of view, whichever petal is currently scaling at the time will continue to scale indefinitely.

I even tried using a special js library to determine if the window is in view and still wasn't able to get the petals to stop scaling.

You can view a demo here, as I was not even able to replicate this in a Paper sketch: https://demos2.paperbeatsscissors.com/

Also including my onFrame code here in case the problem is obvious to someone:

view.onFrame = function(event) {
    
    // See if something is playing
    if (playing > -1) {

      // Get the active flower
      var activeFlower = garden[playing],
          activeData = activeFlower.data;

      // Active layer and petal
      var activeLayer = getEl(activeFlower, activeData.lIndex),
          activePetal = getEl(activeLayer, activeData.pIndex);

      // Variables
      var time = activeData.audio.seek(),
          scaleAmount = (1 / (activeData.timing / event.delta.toFixed(3))) * 2;

      // Petal progression
      if (!activeData.completed) {
        if (activePetal.scaling.x < 1 && activePetal.scaling.y < 1) {
          activePetal.pivot = {x: 0, y: activePetal.height / 2};
          activePetal.scaling.x = activePetal.scaling.x + scaleAmount;
          activePetal.scaling.y = activePetal.scaling.y + scaleAmount;
        } else {
          if (activeData.pIndex < (activeLayer.children.length - 1)) {
            // If the petal is scaled, jump to a new petal
            activeData.pIndex += 1;
          } else {
            if (activeData.lIndex > 0) {
              // When all petals are bloomed, jump to a new layer
              activeData.pIndex = 0;
              activeData.lIndex -= 1;
            } else {
              // Set the flower as completed
              activeData.completed = true;
            }
          }
        }
      }

      activeFlower.rotate(.125, activeData.center);

      // Reset the playing variable if the audio clip is complete and the flower has completed
      if (!activeData.audio.playing() && time === 0 && activeData.completed) {
        playing = -1;
      }
    }
  }

Really stumped on this one so any help is greatly appreciated!


Solution

  • I think that your problem is coming from the fact that you base your scaling calculation on event.delta which represents the time elapsed since the last event fired.
    The thing is that, if I'm not mistaken, under the hood, Paper.js onFrame event relies on requestAnimationFrame which does not fire when the tab if inactive.
    So when you switch tab, wait for a while and get back to your tab event.delta value is big and your scaling value too, hence the size of your petals. This basic sketch showcase this behavior.

    So in my opinion, you should simply check event.delta value and limit it if it's too high.