Prevent jumping to first frame when video source changes - javascript

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.

Related

How to remove the overlay image on only the selected lazyloaded video?

In the script below, I'm lazyloading two videos. My script is designed to remove the overlay image from the selected video when clicked. However, it's also removing the overlay image from the second video and placing it above it. Another click removes the duplicate image, and a third click plays the video.
How do I remove only the image for the selected video in a way that doesn't affect a second video on the page?
const getVideoId = (wistia_vid) => {
const classes = Array.from(wistia_vid.querySelector(".wistia_embed").classList);
const idClass = classes.find((cls) => cls.startsWith("wistia_async_"));
const id = idClass.replace("wistia_async_", "");
return id;
};
const removeElems = (wistia_vid) => {
const toRemove = Array.from(
wistia_vid.querySelectorAll(".wistia__overlay, .embed-youtube__play, .embed-video__play")
);
toRemove.forEach((node) => node.remove());
};
Array.from(document.querySelectorAll(".wistia")).forEach((node) => {
node.addEventListener("click", () => {
const videoId = getVideoId(node);
let wistiaSupportScripts = [
//adds jsonp file to provide security over requests
`https://fast.wistia.com/embed/medias/${videoId}.jsonp`
];
removeElems(node);
//Checks if above scripts are already loaded, and if they are... they won't be loaded again
const id = 'script-ev1';
if (!document.getElementById(id)) {
// const id = 'script-ev1';
var script = document.createElement('script');
script.id = id;
script.onload = () => {
console.log('Ev-1.js loaded and ready to go!');
};
script.src = `https://fast.wistia.com/assets/external/E-v1.js` ;
document.getElementsByTagName('head')[0].appendChild(script);
} else {
console.log(`Ev-1.js script with id: ${videoId} already loaded.`);
}
//loads supporting scripts into head
for (var i = 0; i < wistiaSupportScripts.length; i++) {
let wistiaSupportScript = document.createElement("script");
wistiaSupportScript.src = wistiaSupportScripts[i];
let complete = false;
if (
!complete &&
(!this.readyState ||
this.readyState == "loaded" ||
this.readyState == "complete")
) {
complete = true;
console.log(`JSONP script was added.`);
}
let wistiaContainers = document.querySelector(".wistia");
wistiaContainers ? document.getElementsByTagName("head")[0].appendChild(wistiaSupportScript) : console.log("No Wistia videos here.");
}
window._wq = window._wq || [];
_wq.push({
//globally scoped
id: videoId,
options: {
autoPlay: true,
volume: 0.5
},
onReady: function (video) {
playedOnce = true;
video.popover.show();
video.play();
}
});
});
});
.wistia {
position: relative;
display: block;
width: 100%;
max-width: 500px;
padding: 0;
overflow: hidden;
cursor: pointer;
}
.wistia__overlay {
width: 100%;
height: auto;
}
.wistia::before {
display: block;
content: "";
}
.wistia button.embed-youtube__play {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, rgba(33, 33, 33, 0.8);
background-size: 40%;
background-position: 55%;
border: 0;
border-radius: 50%;
position: absolute;
transition: all 0.2s ease;
-webkit-transition: background 0.2s;
width: 10%;
aspect-ratio: 1/1;
max-height: 15%;
cursor: pointer;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
.wistia:hover button.embed-youtube__play,
.wistia button.embed-youtube__play:focus-visible,
.wistia button.embed-youtube__play:focus {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, #005fec;
background-size: 40%;
background-position: 55%;
}
.wistia_embed,
.wistia embed,
.wistia iframe {
width: 100%;
max-height: 100%;
}
<div class="wistia">
<picture>
<source srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=640" media="(min-width: 1200px)">
<source srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310" media="(min-width: 768px)">
<img src="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310" alt="some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_vhkqhqhzyq videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
<div class="wistia">
<picture>
<source srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=640" media="(min-width: 1200px)">
<source srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310" media="(min-width: 768px)">
<img src="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310" alt="Some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_8ei13wuby7 videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
Put this in your CSS:
.wistia_embed {
display: none;
}
.wistia.shown .wistia_embed {
display: block;
}
Then, put this in your JS:
if (!node.classList.contains("shown")) {
node.classList.add("shown");
} else {
return;
}
Right in the beginning of the event listener function.
Explanation
The E-v1.js script shows all the videos at once, when you load this script by the first click with this piece of code:
const id = 'script-ev1';
if (!document.getElementById(id)) {
// const id = 'script-ev1';
var script = document.createElement('script');
script.id = id;
script.onload = () => {
console.log('Ev-1.js loaded and ready to go!');
};
script.src = `https://fast.wistia.com/assets/external/E-v1.js`;
document.getElementsByTagName('head')[0].appendChild(script);
} else {
console.log(`Ev-1.js script with id: ${videoId} already loaded.`);
}
Before you load this script, there are no videos as is, just the <source> elements. You never indicate with you CSS that videos should be invisible; henceforth, they are visible by default, once the E-v1.js script loads them.
Now, when you add this CSS snippet above, you indicate that .wistia_embed elements, which are basically the loaded videos, have to be invisible from the beginning.
With this single line of JS code, only one video will be revealed on click (setting .shown class, which contains display: block; attribute for the .wistia_embed).
Undefined video.popover
I don't know Wistia API that much, but the browser tells that there is no video.popover.show() function. Remove this from your code as well, otherwise the second video won't auto-play by clicking on it.
onReady: function (video) {
playedOnce = true;
video.popover.show(); // remove
video.play();
}
Full working code
const getVideoId = (wistia_vid) => {
const classes = Array.from(wistia_vid.querySelector(".wistia_embed").classList);
const idClass = classes.find((cls) => cls.startsWith("wistia_async_"));
const id = idClass.replace("wistia_async_", "");
return id;
};
const removeElems = (wistia_vid) => {
const toRemove = Array.from(
wistia_vid.querySelectorAll(".wistia__overlay, .embed-youtube__play, .embed-video__play")
);
toRemove.forEach((node) => node.remove());
};
Array.from(document.querySelectorAll(".wistia")).forEach((node) => {
node.addEventListener("click", () => {
if (!node.classList.contains("shown")) {
node.classList.add("shown");
} else {
return;
}
const videoId = getVideoId(node);
let wistiaSupportScripts = [
//adds jsonp file to provide security over requests
`https://fast.wistia.com/embed/medias/${videoId}.jsonp`
];
removeElems(node);
//Checks if above scripts are already loaded, and if they are... they won't be loaded again
const id = 'script-ev1';
if (!document.getElementById(id)) {
// const id = 'script-ev1';
var script = document.createElement('script');
script.id = id;
script.onload = () => {
console.log('Ev-1.js loaded and ready to go!');
};
script.src = `https://fast.wistia.com/assets/external/E-v1.js`;
document.getElementsByTagName('head')[0].appendChild(script);
} else {
console.log(`Ev-1.js script with id: ${videoId} already loaded.`);
}
//loads supporting scripts into head
for (var i = 0; i < wistiaSupportScripts.length; i++) {
let wistiaSupportScript = document.createElement("script");
wistiaSupportScript.src = wistiaSupportScripts[i];
let complete = false;
if (
!complete &&
(!this.readyState ||
this.readyState == "loaded" ||
this.readyState == "complete")
) {
complete = true;
console.log(`JSONP script was added.`);
}
let wistiaContainers = document.querySelector(".wistia");
wistiaContainers ? document.getElementsByTagName("head")[0].appendChild(wistiaSupportScript) : console.log("No Wistia videos here.");
}
window._wq = window._wq || [];
_wq.push({
//globally scoped
id: videoId,
options: {
autoPlay: true,
volume: 0.5
},
onReady: function (video) {
playedOnce = true;
video.play();
}
});
});
});
.wistia {
position: relative;
display: block;
width: 100%;
max-width: 500px;
padding: 0;
overflow: hidden;
cursor: pointer;
}
.wistia__overlay {
width: 100%;
height: auto;
}
.wistia::before {
display: block;
content: "";
}
.wistia button.embed-youtube__play {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, rgba(33, 33, 33, 0.8);
background-size: 40%;
background-position: 55%;
border: 0;
border-radius: 50%;
position: absolute;
transition: all 0.2s ease;
-webkit-transition: background 0.2s;
width: 10%;
aspect-ratio: 1/1;
max-height: 15%;
cursor: pointer;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
.wistia:hover button.embed-youtube__play,
.wistia button.embed-youtube__play:focus-visible,
.wistia button.embed-youtube__play:focus {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, #005fec;
background-size: 40%;
background-position: 55%;
}
.wistia_embed,
.wistia embed,
.wistia iframe {
width: 100%;
max-height: 100%;
}
.wistia_embed {
display: none;
}
.wistia.shown .wistia_embed {
display: block;
}
<div class="wistia">
<picture>
<source
srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=640"
media="(min-width: 1200px)">
<source
srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310"
media="(min-width: 768px)">
<img src="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310"
alt="some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_vhkqhqhzyq videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
<div class="wistia">
<picture>
<source
srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=640"
media="(min-width: 1200px)">
<source
srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310"
media="(min-width: 768px)">
<img src="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310"
alt="Some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_8ei13wuby7 videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>

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>

Javascript - Play audio when div is display=block

I'm trying to play audio when the div .deley change to display: block, but something does not work. The online audio clips are correct, it's not the problem. My problem is in my script, but I can not find it. Maybe .pause is not a function?
What could be wrong?
function see() {
var x = document.getElementById("deley");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
};
// === Scrip for audio play ====
$(document).ready(function(){
$(".deley").hide();
// if sound is currently playing, stop it and reset
if(!$("#notify").paused) {
$("#notify").pause();
$("#notify").currentTime = 0;
}
setTimeout(function () {
$(".deley").show();
$("#notify").play();
}, 0);
});
#cont {
width:200px;
margin:0 auto
}
.deley {
display:none;
width:96px;
height:40px;
background:red;
margin:20px 0;
text-align:center;
line-height:40px;
font-family:Arial, sans-serif;
color:#fff
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="cont">
<div class="deley" id="deley">Deley</div>
<audio id="notify">
<source src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.ogg" type="audio/ogg">
<source src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.mp3" type="audio/mpeg">
</audio>
<button onclick="see()">Open / Close</button>
</cont>
jQuery Objects✱ and JavaScript Objects🞳 are different. They do not recognize one another which is why the following statements do not work:
if (!$(".notify").paused) {
$(".notify").pause();
$(".notify").currentTime = 0;
...
$(".notify").play();
The MediaElement API is Plain JavaScript only. Any methods/properties/events from said API is not recognized by jQuery -- Plain JavaScript Objects are needed to use methods .pause() and .play(), and properties .paused and .currentTime.
Solutions
Reference a Plain JavaScript Object🞳
document.querySelector(selector)
Dereference a jQuery Object✱
$(selector)[0]
OR
$(selector).get(0)
There are a couple of other important things to remember about jQuery:
Never use onevent attributes: <buttononclick='func();'</button>
Assign .class attributes to elements avoid #id attributes.
The versatility jQuery affords to us makes such antiquated practices unnecessary and wasteful. Also, the function see() is no longer needed -- functionality of see() is now integrated into function audioSwitch().
$('button').on('click', audioSwitch);
function audioSwitch(e) {
if (!$(".notify")[0].paused || $('.delay').is(':visible')) {
$(".notify")[0].pause();
$(".notify")[0].currentTime = 0;
$(".delay").hide();
} else {
setTimeout(function() {
$(".notify")[0].play();
$(".delay").show();
}, 750);
}
}
.cont {
width: 200px;
margin: 0 auto
}
.delay {
display: none;
width: 96px;
height: 40px;
line-height: 40px;
background: red;
color: #fff;
margin: 20px 0;
text-align: center;
font-family: Arial, sans-serif;
}
<section class="cont">
<figure class="delay">
<figcaption>Delay</figcaption>
</figure>
<audio class="notify" src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.mp3">
</audio>
<button>Open / Close</button>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Here is a working example.
function see() {
var x = document.getElementById("deley");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
};
// === Scrip for audio play ====
$(document).ready(function(){
$(".deley").hide();
// if sound is currently playing, stop it and reset
if(!$("#notify")[0].paused) {
$("#notify")[0].pause();
$("#notify")[0].currentTime = 0;
}
setTimeout(function () {
$(".deley").show();
$("#notify")[0].play();
}, 0);
});
#cont {
width:200px;
margin:0 auto
}
.deley {
display:none;
width:96px;
height:40px;
background:red;
margin:20px 0;
text-align:center;
line-height:40px;
font-family:Arial, sans-serif;
color:#fff
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="cont">
<div class="deley" id="deley">Deley</div>
<audio id="notify">
<source src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.ogg" type="audio/ogg">
<source src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.mp3" type="audio/mpeg">
</audio>
<button onclick="see()">Open / Close</button>
</cont>
Jq object dose not have play, pause events. you will have to change it to a simple javascript to access those events.
emphasized text
Have a look below and i also simplified the function fot you
function see() {
$(".deley").toggle("fast", function(){
var player= $("#notify")[0];
// is the player hidden then pause and reset
if($(this).is("hidden")) {
player.pause();
player.currentTime = 0;
}else
player.play();
});
};
#cont {
width:200px;
margin:0 auto
}
.deley {
display:none;
width:96px;
height:40px;
background:red;
margin:20px 0;
text-align:center;
line-height:40px;
font-family:Arial, sans-serif;
color:#fff
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="cont">
<div class="deley" id="deley">Deley</div>
<audio id="notify">
<source src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.ogg" type="audio/ogg">
<source src="https://notificationsounds.com/soundfiles/8b16ebc056e613024c057be590b542eb/file-sounds-1113-unconvinced.mp3" type="audio/mpeg">
</audio>
<button onclick="see()">Open / Close</button>
</cont>
$(document).ready(function(){
$(".deley").hide();
// if sound is currently playing, stop it and reset
if(!$("#notify")[0].paused) {
$("#notify")[0].pause();
$("#notify")[0].currentTime = 0;
}
setTimeout(function () {
$(".deley").show();
$("#notify")[0].play();
}, 0);
});
https://stackoverflow.com/a/16093819/11343720
Or
document.getElementById('notify').play();

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>

Full screen background video that covers all available space

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;
}

Categories