Full screen background video that covers all available space - javascript

Basically I want the video to behave the same way background-size:cover works - covering all available space - example here: http://www.aaronvanderzwan.com/maximage/examples/html5video.html. I got it resizing proportionally and centering - but it still doesn't cover all available space.
Javascript:
$(document).ready(function(e){
var $item = $(".video");
var proportions = $item.width() / $item.height()
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
// usage:
// instead of setInterval(render, 16) ....
(function animloop(){
requestAnimFrame(animloop);
resize();
})();
function resize(){
// center the item
$item.css({"top": "50%", "margin-top":-parseInt($item.height()/2)})
$item.css({"left": "50%", "margin-left":-parseInt($item.width()/2)})
// scale it
if($(window).width() / $(window).height() < proportions){
scaleProportionalByHeight($(window).height())
}else{
scaleProportionalByWidth( $(window).width() )
}
}
function scaleProportionalByWidth ( newWidth ) {
$item.width(newWidth);
$item.height(newWidth / proportions);
}
function scaleProportionalByHeight ( newHeight ) {
$item.height(newHeight);
$item.width(newHeight * proportions);
}
})
html:
<video class="video" loop autoplay muted autobuffer="autobuffer">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
</video>

Can't you just use CSS ?
like this:
HTML
<video loop autoplay muted autobuffer="autobuffer" id="myVideo">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
</video>
CSS
video#myVideo{
position: fixed; right: 0; bottom: 0;
width: auto; height: auto; z-index: -100;
min-width: 100%; min-height: 100%;
background-size: cover;
}

Related

Automatically play / pause video if they are in the viewport / not in the viewport

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/
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>

Prevent jumping to first frame when video source changes

My code is as follows
"use strict";
console.clear();
((d,w) => {
const cloneVideo = vid => {
const clone = vid.cloneNode(true);
clone.id += '-'
clone.style.display = 'none'
vid.parentElement.insertBefore(clone, vid);
return clone;
}
const getVideoSources = el => Array.from(el.querySelectorAll(":scope > source"));
const isTypeSupported = type => d.createElement("video").canPlayType(type);
const isMatchMedia = media => w.matchMedia(media).matches;
const onLoadeddata = (vid, clone) => e => {
const t = vid.currentTime;
vid.remove()
clone.currentTime = t;
clone.style.display = ''
clone.removeEventListener('loadeddata', onLoadeddata(vid, clone))
clone.play();
}
const updateVideoSources = vid => {
let changes = getVideoSources(vid).findIndex(src => isMatchMedia(src.media))
if (changes > 0) {
const clone = cloneVideo(vid);
let changes = getVideoSources(clone).filter(src => isMatchMedia(src.media))
changes.reverse().forEach(src => clone.prepend(src))
const id = vid.id
clone.addEventListener('loadeddata', onLoadeddata(vid, clone))
clone.load();
clone.id = id
return clone
}
return vid
};
const checkMedia = (video) => {
return (e) => {
// console.log(e)
video = updateVideoSources(video);
// console.log(39, video, video.parentElement)
}
}
w.checkMedia = checkMedia;
})(document,window);
{
const delay = 250;
const video = document.getElementById("vid");
const check = checkMedia(video)
window.addEventListener("DOMContentLoaded", check);
window.addEventListener("resize", debounce(check, delay));
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
}
.container {
max-width: 925px;
margin: auto;
}
.clip {
position: relative;
width: 50%;
overflow: hidden;
display: -webkit-box;
display: flex;
}
.clip:before {
content: '';
padding-bottom: calc(100% * 506 / 448);
visibility: hidden;
pointer-events: none;
flex-basis: 0;
}
.clip:after {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #c3a88c;
background: #8a5d2f;
background: #ca935a;
background: #af8457;
mix-blend-mode: soft-light;
-webkit-clip-path: circle(farthest-side at 56.4% 50%);
clip-path: circle(farthest-side at 56.4% 50%);
}
#vid {
-webkit-clip-path: circle(farthest-side at 56.4% 50%);
clip-path: circle(farthest-side at 56.4% 50%);
-o-object-fit: cover;
object-fit: cover;
-o-object-position: 56.4% 50%;
object-position: 56.4% 50%;
}
#vid {
line-height: 0;
display: inline-block;
width: 100%;
}
body {
margin: 0;
padding: 0;
}
<div class="container">
<div class="clip">
<video id="vid" autoplay muted loop playsinline preload="auto" width="100%" height="auto">
<source data-number="1" src="https://assets.codepen.io/96344/pleyces-landing-page-video_240p.webm" type="video/webm" media="(max-width:527px)">
<source data-number="2" src="https://assets.codepen.io/96344/pleyces-landing-page-video_240p.ogv" type="video/ogg" media="(max-width:527px)">
<source data-number="3" src="https://assets.codepen.io/96344/pleyces-landing-page-video_240p.mp4" type="video/mp4" media="(max-width:527px)">
<source data-number="4" src="https://assets.codepen.io/96344/pleyces-landing-page-video_360p.webm" type="video/webm" media="(max-width: 719px) and (min-width:528px)">
<source data-number="5" src="https://assets.codepen.io/96344/pleyces-landing-page-video_360p.ogv" type="video/ogg" media="(max-width: 719px) and (min-width:528px)">
<source data-number="6" src="https://assets.codepen.io/96344/pleyces-landing-page-video_360p.mp4" type="video/webm" media="(max-width: 719px) and (min-width:528px)">
<source data-number="7" src="https://assets.codepen.io/96344/pleyces-landing-page-video_480p.webm" type="video/webm" media="(max-width: 899px) and (min-width:720px)">
<source data-number="8" src="https://assets.codepen.io/96344/pleyces-landing-page-video_480p.ogv" type="video/ogg" media="(max-width: 899px) and (min-width:720px)">
<source data-number="9" src="https://assets.codepen.io/96344/pleyces-landing-page-video_480p.mp4" type="video/mp4" media="(max-width: 899px) and (min-width:720px)">
<source data-number="10" src="https://assets.codepen.io/96344/pleyces-landing-page-video_600p.webm" type="video/webm" media="(min-width:900px)">
<source data-number="11" src="https://assets.codepen.io/96344/pleyces-landing-page-video_600p.ogv" type="video/ogg" media="(min-width:900px)">
<source data-number="12" src="https://assets.codepen.io/96344/pleyces-landing-page-video_600p.mp4" type="video/mp4" media="(min-width:900px)">
</video>
</div>
</div>
What this code does?
Since there is no support for media attributes of <source> elements inside <video> elements (See MDN), I needed to code a workaround. What I coded is: Listen to resize events (debounced) and check the media queries of each source, if it matches with window matchMedia. If some sources match, I change the order of the <source> tags and move the matches to be first children of the <video> elements.
After that I load the video again and jump to the memorized time.
Because this had the disadvantage of flickering when the sources changed (video disappeared and then appeared again), I needed a workaround. For this I clone the video before sorting and loading and then remove the original video after the clone has loaded (event loadeddata).
This prevents the flickering, but has another slight unpleasant behavior. The video jumps to the first video frame and then immediately to the time frame I memorized earlier.
Why does it do that? I set the currentTime before the play() action.
For this issue to show you need to test this in Full page mode and change the window width: I have three break points defined, where the video source should change: 528, 720 and 900 pixels. You can check that it's working by inspecting the Network tab in your Browser's Developer Tools.

Waiting event not firing

I can't understand why the waiting event is not firing.
Basically I want the animation in the container to work whenever the video buffers.
Is there any other event that I need to look out for?
function play() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<video onwaiting="play()" controls autoplay>
<source src = "bleach-cool-mp3.webm" type="video/webm" >
</video>
<div id="container">
<div id="animate"></div>
</div>
Two important things:
First: You can't name your function play(), because is a reserved keyword for the video api, you have to rename it
Second: Your onwaiting event is working fine, but it only triggers when your video has to buff the next frames (like slow connection problems). If you want it to trigger when the video is searching for the data to show, like the first loading, use onloadstart event:
Bellow, your working snippet:
function PlayAnimation() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<video onwaiting="PlayAnimation()" onloadstart="PlayAnimation()" controls autoplay>
<source src = "https://www.w3schools.com/tags/mov_bbb.mp4" type="video/mp4" >
</video>
<div id="container">
<div id="animate"></div>
</div>

html5 video buffer indicator

Im trying to add a buffer loader for all of my videos. All of my videos have got the id="video" but only one out of my 6 videos seems to display it. keep in mind i am using chromes network throttle "slow 3g" so i can force a slow buffer. anyone know why only one video will display the loader and none others will? heres the code:
var video = document.getElementById("video");
var placeholder = document.getElementById("placeholder");
placeholder.style.top = video.offsetTop + "px";
placeholder.style.left = video.offsetLeft + "px";
video.onwaiting = function() {
showPlaceholder(placeholder, this);
};
video.onplaying = function() {
hidePlaceholder(placeholder, this);
};
function showPlaceholder(img, vid) {
img.style.height = vid.scrollHeight + "px";
img.style.width = vid.scrollWidth + "px";
img.style.display = "block";
}
function hidePlaceholder(img, vid) {
img.style.display = "none";
}
.placeholder {
display: none;
position: absolute;
background-size: cover;
text-align: center;
z-index: 300000;
}
.THG-video {
width: 100% !important;
height: auto !important;
max-height: 380px;
max-width: 512px;
}
<div id="placeholder" class="placeholder"><img src="https://thg-graphics.com/media/DualRing.gif"></div>
<video class="THG-video" id="video" poster="Images/Rita.jpg" controls controlsList="nodownload noaudio" preload="none">
<source src="videos/Rita.mp4" type="video/mp4"> Your browser does not support the video tag.
</video>
<video class="THG-video" id="video" poster="Images/nat.jpg" controls controlsList="nodownload noaudio" preload="none">
<source src="videos/nat_x264.mp4" id="video" type="video/mp4"> Your browser does not support the video tag.
</video>
<video class="THG-video" id="video" poster="Images/ora.jpg" controls controlsList="nodownload noaudio" preload="none">
<source src="videos/Ora209_x264.mp4" type="video/mp4"> Your browser does not support the video tag.
</video>
<video class="THG-video" id="video" poster="Images/Arff-custom.jpg" controls controlsList="nodownload noaudio" preload="none">
<source src="videos/ARFF-Custom-3_x264.mp4" type="video/mp4"> Your browser does not support the video tag.
</video>
<video class="THG-video" id="video" poster="Images/THG-Green.jpg" controls controlsList="nodownload noaudio" preload="none">
<source src="videos/THG-Green.mp4" type="video/mp4"> Your browser does not support the video tag.
</video>
<video class="THG-video" id="video" poster="Images/mgd.jpg" controls controlsList="nodownload noaudio" preload="none">
<source src="videos/MGD_x264.mp4" type="video/mp4"> Your browser does not support the video tag.
</video>
I have made a working loader that can be used for as many videos as you like. Just edit the ids, video and placeholder tags to a unique word for each video. Here is a Jsfiddle
var video = document.getElementById("video_1");
var placeholder = document.getElementById("placeholder_1");
placeholder_1.style.top = video_1.offsetTop + "px";
placeholder_1.style.left = video_1.offsetLeft + "px";
video_1.onwaiting = function() {
showPlaceholder(placeholder_1, this);
};
video_1.onplaying = function() {
hidePlaceholder(placeholder_1, this);
};
function showPlaceholder(img, vid) {
img.style.height = vid.scrollHeight + "px";
img.style.width = vid.scrollWidth + "px";
img.style.display = "block";
}
function hidePlaceholder(img, vid) {
img.style.display = "none";
}
var video = document.getElementById("video_2");
var placeholder = document.getElementById("placeholder_2");
placeholder_2.style.top = video_2.offsetTop + "px";
placeholder_2.style.left = video_2.offsetLeft + "px";
video_2.onwaiting = function() {
showPlaceholder(placeholder_2, this);
};
video_2.onplaying = function() {
hidePlaceholder(placeholder_2, this);
};
function showPlaceholder(img, vid) {
img.style.height = vid.scrollHeight + "px";
img.style.width = vid.scrollWidth + "px";
img.style.display = "block";
}
function hidePlaceholder(img, vid) {
img.style.display = "none";
}
var video = document.getElementById("video_3");
var placeholder = document.getElementById("placeholder_3");
placeholder_3.style.top = video_3.offsetTop + "px";
placeholder_3.style.left = video_3.offsetLeft + "px";
video_3.onwaiting = function() {
showPlaceholder(placeholder_3, this);
};
video_3.onplaying = function() {
hidePlaceholder(placeholder_3, this);
};
function showPlaceholder(img, vid) {
img.style.height = vid.scrollHeight + "px";
img.style.width = vid.scrollWidth + "px";
img.style.display = "block";
}
function hidePlaceholder(img, vid) {
img.style.display = "none";
}
var video = document.getElementById("video_4");
var placeholder = document.getElementById("placeholder_4");
placeholder_4.style.top = video_4.offsetTop + "px";
placeholder_4.style.left = video_4.offsetLeft + "px";
video_4.onwaiting = function() {
showPlaceholder(placeholder_4, this);
};
video_4.onplaying = function() {
hidePlaceholder(placeholder_4, this);
};
function showPlaceholder(img, vid) {
img.style.height = vid.scrollHeight + "px";
img.style.width = vid.scrollWidth + "px";
img.style.display = "block";
}
function hidePlaceholder(img, vid) {
img.style.display = "none";
}
.placeholder {
display: none;
position: absolute;
background-size: cover;
text-align: center;
float: left;
z-index: 300000;
}
.loader,
.loader:before,
.loader:after {
background: #ff8000;
-webkit-animation: load1 1s infinite ease-in-out;
animation: load1 1s infinite ease-in-out;
width: 1em;
height: 4em;
}
.loader {
color: #ff8000;
text-indent: -9999em;
margin: 88px auto;
position: relative;
font-size: 11px;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
.loader:before,
.loader:after {
position: absolute;
top: 0;
content: '';
}
.loader:before {
left: -1.5em;
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.loader:after {
left: 1.5em;
}
#-webkit-keyframes load1 {
0%,
80%,
100% {
box-shadow: 0 0;
height: 4em;
}
40% {
box-shadow: 0 -2em;
height: 5em;
}
}
#keyframes load1 {
0%,
80%,
100% {
box-shadow: 0 0;
height: 4em;
}
40% {
box-shadow: 0 -2em;
height: 5em;
}
}
<video id="video_1" controls preload="none">
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4" />
</video>
<div id="placeholder_1" class="placeholder">
<div class="loader">Loading...</div>
</div>
<video id="video_2" controls preload="none">
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4" />
</video>
<div id="placeholder_2" class="placeholder">
<div class="loader">Loading...</div>
</div>
<video id="video_3" controls preload="none">
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4" />
</video>
<div id="placeholder_3" class="placeholder">
<div class="loader">Loading...</div>
</div>
<video id="video_4" controls preload="none">
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4" />
</video>
<div id="placeholder_4" class="placeholder">
<div class="loader">Loading...</div>
</div>

Javascript responsive video height/width

I want to make a fullscreen-video responsive landing page. I have a video (1920x1080) which is centered. But when I resize the window, it's not resizing properly. Javascript solution only please.
Example how it should look like: http://www.welcometofillory.com/
I appreciate any help.
Javascript so far:
var $vid = $('.full-screen-video');
updateSize();
$(window).resize(function() {
updateSize();
});
function updateSize() {
var $eWidth = window.innerWidth;
var $AspectRatio = 1080 / 1920;
var $newHeight = $eWidth * $AspectRatio;
$vid.css({"width": $eWidth, "height": $newHeight});
};
Your code is true. Use console to see the process:
function updateSize() {
var $eWidth = window.innerWidth;
var $AspectRatio = 1080 / 1920;
var $newHeight = $eWidth * $AspectRatio;
console.log('eWidth: ' + eWidth);
console.log('newHeight: ' + newHeight);
$vid.css({"width": $eWidth, "height": $newHeight});
console.log('real width' + $('.full-screen-video').width());
console.log('real height' + $('.full-screen-video').height());
};
And you can test this css rule:
.full-screen-video {
width: 100vw;
height: calc(100vw / 1.7); /* 1.7 is 1920/1080 */
}
works using css only:
<div class="fullsize-container">
<video autoplay id="landing-video" class="full-screen-video" width="100%" height="100%" preload="auto" loop="loop">
<source src="assets/landing-video.mp4" type="video/mp4">
</video>
</div>
.fullsize-container {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
}
.full-screen-video {
width: 1920px;
height: 1080px;
max-width: 1920px;
max-height: 1080px;
position: absolute;
left: 50%;
top: 50%;
-ms-transform: translate(-50%,-50%);
-webkit-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
}

Categories