Search code examples
javascriptjqueryhtml5-videohtml5-audiojquery-waypoints

Increasing/decreasing audio on a video element, triggered via jQuery Waypoints


I have a page with a series of (HTML 5) videos whose audio needs to fade in or out depending on your position on the page (and it may be different for each video). I'm using jQuery Waypoints with the InView plugin to detect when an element is in the viewport. I'm not sure how to do it consistently, so that you don't cause unexpected behavior when you trip a waypoint while the volume is still decreasing or increasing.

var waypoint = new Waypoint.Inview({
  element: $('#element')[0],
  enter: function() {
    $('#element')[0].volume = 0;
    $('#ielement')[0].play();
    incVol($('#element')[0]);
  },
  entered: function() {},
  exit: function() {},
  exited: function() {
    decVol($('#element')[0]);
  }
});

function incVol(e) {
  setTimeout(function() {
    if ((e.volume + .05) < 1) {
      e.volume += .05;
      incVol(e);
    } else {
      e.vol = 1;
    }
  }, 100)
}

function decVol(e) {
  setTimeout(function() {
    if ((e.volume - .05) > 0) {
      e.volume -= .05;
      decVol(e);
    } else {
      e.volume = 0;
      e.pause();
    }
  }, 100)
}

This is an inconsistent attempt, if you trigger 'enter' while 'decVol' is still running you lose volume completely and have to trigger an 'exit', wait, and then trigger 'enter' again.

I've also tried something with jQuery's animate on volume. But that doesn't seem consistent either.

var waypoint = new Waypoint.Inview({
  element: $('#element')[0],
  enter: function() {
    $('#element')[0].volume = 0;
    $('#element')[0].play();
    $('#element').animate({
      volume: 1
    }, 1000);
  },
  entered: function() {},
  exit: function() {},
  exited: function() {
    $('#element').animate({
      volume: 0
    }, 1000, function() {
      $('#element')[0].pause();
    });
  }
});

If I scroll up and down too fast, especially if I have multiple waypoints of this type in the page, then the queue of events becomes extensive and I have fade ins/outs happening far after the events have triggered (though, I prefer this implementation for the moment).

Any suggestions on how to achieve what I want a little better?


Solution

  • Prefacing the animate() function with stop() is the answer. Something like:

    $('#element').stop(true, false).animate({
      volume: 1
    }, 1000);