Javascript/jQuery - replace a video iframe with a placeholder image - javascript

I've had one question involving this piece of code answered by the very helpful people here, but now I have another one which is slightly different. I have a placeholder image which sits in a carousel slide, which when clicked on gets replaced by a youtube video using the default youtube iframe embed.
What I would like to do is, after a user has clicked on the image and has played the video, when they click away from the carousel slide the video is embedded in (for example, by clicking on a carousel arrow or pagination dot) it resets it back to how it was before the video was displayed.
I hope that makes sense. Basically, I need help reverse engineering this code so that the video gets replaced again by it's placeholder image on a click of another element/div.
Here is the HTML:
<div class="youtube_video">
<img src="img/video_poster_carousel.jpg" width="986" height="308">
<!-- <iframe width="986" height="555" src="https://www.youtube.com/embed/Wt_Ruy_ejPY?enablejsapi=1&list=PL027E2B6D9900A88F&showinfo=0&controls=1" frameborder="0" allowfullscreen></iframe> -->
</div>
And the CSS:
/* video */
.youtube_video { position: relative; padding-bottom: 31.65%; height:0; }
.youtube_video img { position: absolute; display: block; top: 0; left: 0; /*width: 100%; height: 100%;*/ z-index: 20; cursor: pointer; }
.youtube_video:after { content: ""; position: absolute; display: block;
background: url(play-button.png) no-repeat 0 0;
top: 45%; left: 45%; width: 46px; height: 36px; z-index: 30; cursor: pointer; }
.youtube_video iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/* image poster clicked, player class added using js */
.youtube_video.player img { display: none; }
.youtube_video.player:after { display: none; }
And the Javascript:
$(function() {
var videos = $(".youtube_video");
videos.on("click", function(){
var elm = $(this),
conts = elm.contents(),
le = conts.length,
ifr = null;
for(var i = 0; i<le; i++){
if(conts[i].nodeType == 8) ifr = conts[i].textContent;
}
elm.addClass("player").html(ifr);
elm.off("click");
});
});

This below line actually does a innerHTML which means your img tag is lost
you may have to move the IMG tag out of the youtube_video container and do a hide and show toggle mechanism for the youtube_video container and the IMG tag
elm.addClass("player").html(ifr);

Related

Horizontally scrollable gallery of videos that play on hover

I'm trying to create a gallery of images that, when hovered upon, the image disappears and a video begins playing, similar to Netflix. I was able to create a gallery that did what I want here:
.container {
display: flex;
overflow-x: auto;
width: 600px;
margin-left: 300px;
}
.container img {
margin-right: 15px;
width: 150px
}
<div class="container">
<img src=https://image.shutterstock.com/image-vector/check-back-soon-hand-lettering-600w-1379832464.jpg>
and the image disappearing and video playing on hover that I want here:
const videos = document.querySelectorAll(".polystar");
for (const video of videos) {
video.addEventListener('mouseover', function() {
video.play()
}, false);
video.addEventListener('mouseout', function() {
video.pause()
}, false);
}
.gallery-cv {
display: flex;
z-index: 1;
overflow-x: auto;
width: 1200px;
margin: 0;
}
.polystar {
width: 300px;
z-index: 2;
opacity: 0;
}
.top-img {
position: absolute;
width: 300px;
height: 535px;
z-index: 1;
}
.polystar:hover {
opacity: 1;
}
.second {
margin-left: 150px;
position: absolute;
z-index: 3;
}
<h1> headline </h1>
<div class="gallery-cv">
<img class="top-img first" src="https://source.unsplash.com/random">
<video class='polystar' muted src="https://player.vimeo.com/external/432406907.hd.mp4?s=f35b5f202d573efa75d9293d213fc3be0927fd85&profile_id=172&oauth2_token_id=57447761" type="video/mp4">
<img class="top-img second" src="https://source.unsplash.com/random">
<img class="top-img third" src="https://source.unsplash.com/random">
</div>
But when I try to combine these (as I've attempted in the above codepen), my gallery disappears and I'm left with only one image, despite having others present in the html. I'm guessing this has something to do with me losing my gallery when I try to have the images inside it absolutely positioned, but I'm not sure how else to achieve my hover effect without absolutely positioning them.
There are multiple problems we have to solve. Lets start with the image that should be displayed by default and disappear for the video on hover:
We need a wrapping element that contains the video and the image like a <div>.
We apply position: relative; to the parent element (wrapper)
We apply position: absolute; inset: 0; (inset: 0 = top + right + bottom + left: 0;) to have the image span the entire wrapping element and elevate it layer-wise above the video with a positive z-index: z-index: 1;
to hide the image on hover we use: div:hover img { display: none; }
The next issue is to start playing the video on hover. For that we need JS which we also can do with the onmouseover-attribute: onmouseover="element.play();"
To pause the video when you not hovering we can use JS or the onmouseout-attribute: onmouseout="element.pause();"
Both the onmouseover and onmouseout trigger/attribute must be added to the wrapping parent element.
div {
position: relative;
}
video {
width: 100%;
}
img {
width: 100%;
object-fit: cover;
position: absolute;
inset: 0;
z-index: 1;
}
div:hover img {
display: none;
}
<div onmouseover="document.querySelector('video').play();" onmouseout="document.querySelector('video').pause();">
<video>
<source src="https://www.tacoshy.de/stackoverflow/testvideo.mp4" type="video/mp4">
</video>
<img src="https://via.placeholder.com/1920x1080.jpg">
</div>

Change picture when I hover over the picture's overlay

I want to change the specific picture that I hover over. However, each pictures is underneath an overlay.
I found a solution to change the picture when I hover over the picture itself.
However, I only can hover over the overlay (parent div to the picture).
<script type='text/javascript'>
$(document).ready(function(){
$(".overlaydiv").hover(
function() {$(this).attr("src","images/aboutR.png");},
function() {$(this).attr("src","images/about.png");
});
});
</script>
I'm new with Javascript and very thankful any help.
Well, if your picture is in the said overlay, here's the code:
$(document).ready(function(){
$(".overlaydiv").hover(
function() {$(this).find('img').attr("src","images/aboutR.png");},
function() {$(this).find('img').attr("src","images/about.png");
});
});
This should update all <img> tags src attributes that are within the .overlaydiv.
If you have multiple image in your overlay, and each should have a specific "new" image on hover, you can add new src as attribute on each image tag, and change your JS to use this new url contained in your attribute to change the img src (instead of hardcoding new URL in your JS).
Example:
<div class="overlaydiv">
<img src="img1.jpg" default-src="img1.jpg" hover-src="img1-2.jpg>
<img src="img2.jpg" default-src="img2.jpg" hover-src="img2-2.jpg>
</div>
Javascript:
$(document).ready(function(){
$(".overlaydiv").hover(
function() {
$(this).find('img').each(function( index ) {
$(this).attr('src', $(this).attr('hover-src'));
});
},
function() {
$(this).find('img').each(function( index ) {
$(this).attr('src', $(this).attr('default-src'));
});
});
});
This is a bit more flexible, and prevent hardcoding URL in your JS. It's also make it compatible with multiple image, having different version on overlay hover.
Note that we need default-src attribute to be able to "remember" the original src to set back on hover leave (after hover callback, when user moving out). You could achieve the same using .data() to remember the default-src.
You can do it with pure CSS in multiple ways:
Using img elements:
div {
display: inline-block; /* or "inline-flex", "inline-grid" */
position: relative;
}
div:after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: Aqua;
opacity: .5;
}
.hidden, div:hover .shown {display: none}
.shown, div:hover .hidden {display: block}
<div>
<img class="shown" src="https://placehold.it/200x200" alt="">
<img class="hidden" src="https://dummyimage.com/200x200" alt="">
</div>
Using background: url():
div {
position: relative;
width: 200px;
height: 200px;
background: url(https://placehold.it/200x200), url(https://dummyimage.com/200x200) no-repeat;
}
div:after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: Aqua;
opacity: .5;
}
div:hover {
background-size: 0, cover;
}
<div></div>
Mix of both:
div {
width: 200px;
height: 200px;
position: relative;
}
div:after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: Aqua;
opacity: .5;
}
img {display: block}
div:hover img {display: none}
div:hover {background: url('https://dummyimage.com/200x200') no-repeat}
<div>
<img src="https://placehold.it/200x200" alt="">
</div>

Video is not getting displayed as per the position set in CSS

I need to display video full screen initially and if user presses 'm' key, Need to display a div with a text and immediately down the text, I need to display the video. when I press 'm', even though I am setting width and height, Video is not getting displayed in the full width and height I have set and event the text is not getting displayed in side the div. Below is the code.
html:
<!DOCTYPE html>
<html>
<head>
<title>VOD</title>
<script src='lib/hls.js'></script>
<script src='js/index.js'></script>
<style>
html, body
{
height:100%;
width: 100%;
overflow: hidden;
background-color: dimgray;
}
#header {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 50px;
background-color: black;
color: white;
}
#vid.full {
position: fixed;
top: 50%;
left: 50%;
z-index: 3;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
transform: translate(-50%, -50%);
}
#vid.pip {
position: fixed;
left: 50px;
top: 50px;
width: 320px;
height: 256px;
margin: 0;
padding: 0;
border: 0;
}
</style>
</head>
<body>
<div id='header' style="display:none">
<h2>DVR</h2>
</div>
<video id='vid' src='textMotion.mp4'class='full' autoplay></video>
</body>
</html>
javascript:
function displayMenu() {
// If already menu is visible, hide it
let vid = document.getElementById('vid');
let hid = document.getElementById('header');
if(vid.classList.contains('pip') == true) {
hid.style.display = 'none';
vid.classList.add('full');
vid.classList.remove('pip');
return;
}
hid.style.display = 'block';
vid.classList.add('pip');
vid.classList.remove('full');
}
function processKeyPress(e) {
console.log('received keyEvent : ' + e.keyCode);
let keyCode = e.keyCode;
// Menu button or key 'm'
if((keyCode == 77) || (keyCode == 462)) {
displayMenu();
}
}
document.addEventListener('keydown', processKeyPress);
Screenshot:
When user selects 'm', video pip should be displayed immediately under 'header' element. But as per the screenshot, there is lot of gap visible between video and header. When I inspect the element video element is right under header. But it is not visible. I think it is because of aspect ratio. Can any one please let me know how to fix this issue. How can we make sure that video should be fully displayed in the given width and height.

Responsive YouTube embed not displaying in Firefox

This embed method appears to be working on all browsers except Firefox; I signed up for a free trial at crossbrowsertesting.com to check. I’m not doing a direct iFrame embed, and all the questions and answers I’ve found relate to that. I’m using this method: A Better Method for Embedding YouTube Videos on your Website. This method:
embeds the thumbnail image of a YouTube video and the actual video player is loaded only when the user manually clicks the thumbnail
The closest issue I could find on Stack Overflow was YouTube embed not working in Firefox. But this does not apply.
Here are screenshots of it displaying properly in Chrome:
And not displaying in Firefox:
In the Firefox image you can see the margin showing up in the inspector as I hover that <div>.
When I set an explicit height value this thumbnail does show up in Firefox, but it negates the responsiveness of the method.
document.addEventListener("DOMContentLoaded",
function() {
var div, n,
v = document.getElementsByClassName("youtube-player");
for (n = 0; n < v.length; n++) {
div = document.createElement("div");
div.setAttribute("data-id", v[n].dataset.id);
div.innerHTML = labnolThumb(v[n].dataset.id);
div.onclick = labnolIframe;
v[n].appendChild(div);
}
});
function labnolThumb(id) {
var thumb = '<img src="https://i.ytimg.com/vi/ID/hqdefault.jpg">',
play = '<div class="play"></div>';
return thumb.replace("ID", id) + play;
}
function labnolIframe() {
var iframe = document.createElement("iframe");
var embed = "https://www.youtube.com/embed/ID?autoplay=1";
iframe.setAttribute("src", embed.replace("ID", this.dataset.id));
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("allowfullscreen", "1");
this.parentNode.replaceChild(iframe, this);
}
.youtube-player {
position: relative;
padding-bottom: 56.23%;
/* Use 75% for 4:3 videos */
height: 0;
overflow: hidden;
max-width: 100%;
background: #000;
margin: 5px;
}
.youtube-player iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
background: transparent;
}
.youtube-player img {
bottom: 0;
display: block;
left: 0;
margin: auto;
max-width: 100%;
width: 100%;
position: absolute;
right: 0;
top: 0;
border: none;
height: auto;
cursor: pointer;
-webkit-transition: .4s all;
-moz-transition: .4s all;
transition: .4s all;
}
.youtube-player img:hover {
-webkit-filter: brightness(75%);
}
.youtube-player .play {
height: 72px;
width: 72px;
left: 50%;
top: 50%;
margin-left: -36px;
margin-top: -36px;
position: absolute;
background: url("//i.imgur.com/TxzC70f.png") no-repeat;
cursor: pointer;
}
<div class="youtube-player" data-id="VIDEO_ID"></div>
I solved this by removing redundant flexbox classes from the parent div. Specifically:
frow direction-column
(these are from the nice flexbox grid framework FrowCSS)
I don't fully understand why, but these must have been interfering with the requried styles in FireFox. Glad I figured it out, I had been wrestling with this 2-3 hours before I posted on SO. Hope this helps someone else in future.
I wrapped a div around the youtube-player and set that to display block and added a width of 100%. That solved the problem. Adding those to the youtube-player itself didn't work though.

Preloading a youtube embed

I want to have an embedded chromeless youtube video preload its video WITHOUT playing when the page loads. Right now I'm using an awkward "play then quickly pause" script which causes small problems (half-second audio leaks and fails quite a bit). For this seemingly simple functionality, is there a better/more elegant way to preload?
I had the same question and came across this question. After some research, I think I found a cleaner, albeit similar, answer.
When the JavaScript API calls OnYouTubePlayerReady, you press play and add an event listener to onStateChange that will be called every time the player changes from buffering to play.
For example, inside the function you listen for state 3, which is buffering, and as soon as it's called, you pause the video.
You can see this technique in action in this jsFiddle.
Side note: I refrained from using a JavaScript framework in my example, but you could easily put one into place here.
Also, I was unable to abstract the script tag out of the body of the HTML using jsFiddle, but an external script.js file works just fine on my own server.
If we view this: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
Preloading the Iframe may help:
<link rel="preload" href="https://www.youtube.com/embed/dQw4w9WgXcQ" as="document">
Call
player.cueVideoById(videoId:String);
Instead of
player.loadVideoById(videoId:String);
I was looking for a solution to this problem and ran across this article:
Embed YouTube Videos Responsively without Increasing Load Time
The summary states: This method will reduce the size of your webpages by 300-400 KB while making your site mobile friendly.
Paste this on the page:
<div class="youtube-container">
<div class="youtube-player" data-id="VIDEOID"></div>
</div>
The javascript:
<script>
(function() {
var v = document.getElementsByClassName("youtube-player");
for (var n = 0; n < v.length; n++) {
var p = document.createElement("div");
p.innerHTML = labnolThumb(v[n].dataset.id);
p.onclick = labnolIframe;
v[n].appendChild(p);
}
})();
function labnolThumb(id) {
return '<img class="youtube-thumb" src="//i.ytimg.com/vi/' + id + '/hqdefault.jpg"><div class="play-button"></div>';
}
function labnolIframe() {
var iframe = document.createElement("iframe");
iframe.setAttribute("src", "//www.youtube.com/embed/" +
this.parentNode.dataset.id + "? autoplay=1&autohide=2&border=0&wmode=opaque&enablejsapi=1&controls=0&showinfo=0");
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("id", "youtube-iframe");
this.parentNode.replaceChild(iframe, this);
}
</script>
The CSS:
<style>
.youtube-container {
display: block;
margin: 20px auto;
width: 100%;
max-width: 600px;
}
.youtube-player {
display: block;
width: 100%;
/* assuming that the video has a 16:9 ratio */
padding-bottom: 56.25%;
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
cursor: hand;
cursor: pointer;
display: block;
}
img.youtube-thumb {
bottom: 0;
display: block;
left: 0;
margin: auto;
max-width: 100%;
width: 100%;
position: absolute;
right: 0;
top: 0;
height: auto
}
div.play-button {
height: 72px;
width: 72px;
left: 50%;
top: 50%;
margin-left: -36px;
margin-top: -36px;
position: absolute;
background: url("http://i.imgur.com/TxzC70f.png") no-repeat;
}
#youtube-iframe {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>
Refer to the original article comments for additional modification suggestions and improvements.

Categories