Search code examples
javascriptjquerysetintervaltiming

Image player issue with jQuery


I've made a jQuery player for images Demo Link.

It changes the screens with provided intervals and draws touches on it. Now, I want to implement pouse, play functionality. When I click on play button to stop screen playing, I call FlowPlaye.stop() method:

FlowPlayer.prototype.stop = function() {
        $(".fp-pause").removeClass("fp-pause").addClass("fp-play");
        clearInterval(this.screenIntervalId);
        clearInterval(this.timeIntervalId);
        clearInterval(this.touchIntervalId);
        $('.fp-progress').stop();
        this.isAnimated = false;
        return false;
    }

And at the second time FlowPlayer.play():

FlowPlayer.prototype.play = function() {
    var fp = this; // Obj refers to the FlowPlayer itself such as "this"
    fp.isAnimated = true;
    console.log(typeof this.screenIndex)
    console.log(this.screenIndex)

    fp.screenIndex = typeof this.screenIndex == 'number' ? this.screenIndex : 0; 
    fp.render(fp.screens[fp.screenIndex]);
    fp.initTimeline(fp.duration);

    fp.screenIntervalId = setInterval(function() {
        if (fp.screenIndex == fp.screens.length - 1) {
            console.log("the end of screens");
            clearInterval(fp.screenIntervalId)
            return;
        }
        ++fp.screenIndex;
        fp.render(fp.screens[fp.screenIndex]);
    }, fp.screens[fp.screenIndex].delay)


}

The problem is that when I do this, the screen playing intervals are messing (try to stop video at 20th second and restore). I need to save state of player, but I don't know how.


Solution

  • I think using 3 different timers is making this unnecessary difficult. If you refactor it into 1 unified timer, pausing (and other playback controls) would be quite easy.

    1. Separate your keyframe events into separate functions:

      function setImage(img) {...}
      function showTouch(x, y) {...}
      function hideTouch() {...}
      
    2. On startup, convert your screens array to something like this:

      var keyframes = [
              { time:0,    func:setImage,  args:['http://...']},
              { time:1000, func:showTouch, args:[10, 30]},
              { time:3000, func:hideTouch, args:[]},
              ...
          ];
      
    3. Set up a single timer for playback:

      var time = 0,
          next = 0,
          isPaused = false,
          interval;
      function timer() {
          if (isPaused) {
              return;
          }
          var nextKeyframe = keyframes[next];
          time += 100;
          if (time >= nextKeyframe.time) {
              nextKeyframe.func.apply(this, nextKeyframe.args);
              next += 1;
              if (next === keyframes.length) {
                  clearInterval(interval);
              }
          }
      }
      
    4. Now, you have an easily controllable playback:

      // play / replay - reset time and next, then start the timer
      time = 0;
      next = 0;
      interval = setInterval(timer, 100);
      
      // seek - just set a new time, and find the next keyframe
      time = 1500;
      for (next = 0; keyframes[next].time < time && next < keyframes.length; next++) {}
      
      // pause - the timer stays on, but won't do anything
      isPaused = true;
      
      // stop
      clearInterval(interval);
      

    Note: The snippets are untested, may have some typos in them. I just wanted to demonstrate the process of making it cleaner / more controllable.