-1

I need to play/pause videos if they are in the viewport/not in the viewport.

It works so far. The problem is, that if the user presses pause, then the video just starts playing again.

// Limitation: Does not work if the element is
// out of view because it is too far right or left
$.fn.isInViewport = function() {
    var elementTop = $(this).offset().top;
    var elementBottom = elementTop + $(this).outerHeight();

    var viewportTop = $(window).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    return elementBottom > viewportTop && elementTop < viewportBottom;
};

setInterval(function() {
    $('video').each(function(){
        if ($(this).isInViewport()) {
            $(this)[0].play();
        } else {
            $(this)[0].pause();
        }
    });
}, 1000);
#right {
  position: absolute;
  top: 2000px;
}
#video1 {
  position: absolute;
  left: 0px;
  top: 1000px;
}
#video2 {
  position: absolute;
  left: 0px;
  top: 2000px;
}

body {
  width: 500px;
  height: 3000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="info"></div>

<div id="down">
  scroll down please...
</div>

<video id="video1" controls muted>
  <source src="https://www.w3schools.com/html/movie.mp4" type="video/mp4">
  <source src="https://www.w3schools.com/html/movie.ogg" type="video/ogg">
  Your browser does not support the video tag.
</video>

<video id="video2" controls muted>
  <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"/>
  <source src="https://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg"/>
  Your browser does not support the video tag.
</video>

I tried to observer the Play/Pause button so I can hook into the event, but the video tag is a shadow dom and I dont know how to deal with it.

https://jsfiddle.net/6agbqjsL/

Black
  • 18,150
  • 39
  • 158
  • 271
  • Does this answer your question? [Youtube video play & pause depend on visibility of the frame with jquery](https://stackoverflow.com/questions/34375655/youtube-video-play-pause-depend-on-visibility-of-the-frame-with-jquery) – kosmos Dec 09 '20 at 14:38
  • 1
    At the point you execute these - `$(this)[0].play();` and `$(this)[0].pause();` you could also set a state of sorts (ie: user interacted with the video, so ignore automatic play/pause). – emerson.marini Dec 09 '20 at 14:39
  • Though it's a duplicate, I strongly recommend to use the Intersection Observer API (https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) – kosmos Dec 09 '20 at 14:40
  • @melancia, how can I observe if the user interacted or if my script interacted? – Black Dec 09 '20 at 14:43
  • 1
    I think to observe whether your script actioned the video would be easier than checking whether a user did so. My previous comment was misleading, sorry. At those points on your code you know that the interaction happened automatically. – emerson.marini Dec 09 '20 at 14:44
  • 1
    Could also be helpful: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onplay and https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onpause – emerson.marini Dec 09 '20 at 14:48
  • 1
    @Black You could always just fire the function on the window scroll event?? If the user stops scrolling they can use the play/pause buttons like normal, if they continue to scroll it will start or stop the video if the video is in or out of view. – Ryan Wilson Dec 09 '20 at 14:54
  • @RyanWilson, then the method is called very often, because if you scroll down to the bottom it is getting called about 50-60 times – Black Dec 09 '20 at 14:58
  • @Black Yes. What's your point? You are using `setInterval` and firing it every second regardless of whether the video is in view or not. There's also a way to stop the scroll event from firing every 100ms if you are that concerned about it - (https://stackoverflow.com/questions/9613594/scroll-event-firing-too-many-times-i-only-want-it-to-fire-a-maximum-of-say-on#:~:text=This%20will%20fire%20the%20first,after%20the%20scrollbar%20stops%20moving.) – Ryan Wilson Dec 09 '20 at 14:58
  • My point is that 1 time in 1 second is better than 20 times in 1 second if the user scrolls fast. Thx for the link – Black Dec 09 '20 at 15:04
  • @Black it fire every 100ms, so that is 10 times in 1 second. But as stated in my comment, you can modify how often the scroll event fires. – Ryan Wilson Dec 09 '20 at 15:08

1 Answers1

2

I figured it out. This way the video only starts playing again if it gets out of the viewport and into the viewport again:

// Limitation: Does not work if the element is
// out of view because it is too far right or left
$.fn.isInViewport = function() {
    var elementTop = $(this).offset().top;
    var elementBottom = elementTop + $(this).outerHeight();

    var viewportTop = $(window).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    return elementBottom > viewportTop && elementTop < viewportBottom;
};

setInterval(function() {
    $('video').each(function(){

        let id = $(this).attr("id");
        let played = $(this).attr("played");

        if ($(this).isInViewport()) {
            if (played == "false") { 
                $(this)[0].play();
                $(this).attr("played", "true");  
            }
        } else {
            if (played == "true") { 
                $(this)[0].pause();
                $(this).attr("played", "false");  
            }
        }
    });
}, 1000);
#right {
  position: absolute;
  top: 2000px;
}
#video1 {
  position: absolute;
  left: 0px;
  top: 1000px;
}
#video2 {
  position: absolute;
  left: 0px;
  top: 2000px;
}

body {
  width: 500px;
  height: 3000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="info"></div>

<div id="down">
  scroll down please...
</div>

<video id="video1" controls muted played="false">
  <source src="https://www.w3schools.com/html/movie.mp4" type="video/mp4">
  <source src="https://www.w3schools.com/html/movie.ogg" type="video/ogg">
  Your browser does not support the video tag.
</video>

<video id="video2" controls muted played="false">
  <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"/>
  <source src="https://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg"/>
  Your browser does not support the video tag.
</video>

This way the video does never play again automatically after it was paused:

// Limitation: Does not work if the element is
// out of view because it is too far right or left
$.fn.isInViewport = function() {
    var elementTop = $(this).offset().top;
    var elementBottom = elementTop + $(this).outerHeight();

    var viewportTop = $(window).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    return elementBottom > viewportTop && elementTop < viewportBottom;
};

setInterval(function() {
    $('video').each(function(){

        var id = $(this).attr("id");
        let played = $(this).attr("played");

        if ($(this).isInViewport()) {
            if (played == "false") { 
                $(this)[0].play();
                $(this).attr("played", "true");
            }
        } else {
            $(this)[0].pause();
        }
    });
}, 1000);
#right {
  position: absolute;
  top: 2000px;
}
#video1 {
  position: absolute;
  left: 0px;
  top: 1000px;
}
#video2 {
  position: absolute;
  left: 0px;
  top: 2000px;
}

body {
  width: 500px;
  height: 3000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="info"></div>

<div id="down">
  scroll down please...
</div>

<video id="video1" controls muted played="false">
  <source src="https://www.w3schools.com/html/movie.mp4" type="video/mp4">
  <source src="https://www.w3schools.com/html/movie.ogg" type="video/ogg">
  Your browser does not support the video tag.
</video>

<video id="video2" controls muted played="false">
  <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"/>
  <source src="https://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg"/>
  Your browser does not support the video tag.
</video>
Black
  • 18,150
  • 39
  • 158
  • 271