Lazy Loading and Javascript with Reveal.js - javascript

I am making a slideshow with Reveal.js. According to the docs (https://github.com/hakimel/reveal.js/), you are supposed to use data-src for lazy loading. How can I utilize lazy loading and play the audio with JS?
This is what I tried but it didn't play the audio:
<section>
<audio id="audio2" controls><source data-src="http://opengameart.org/sites/default/files/foom_0.wav" type="audio/wav"></audio>
<script>
var x = document.getElementById("audio2");
x.play();
</script>
</section>

Your script is executed at the time the presentation is loaded, at which time presumably the lazy loading hasn't happened yet and so the file cannot be played.
If you want to automatically play the audio file when the slide is shown, you should run your x.play() in the callback of the event emitted by Reveal upon showing the slide:
Reveal.addEventListener( 'slidechanged', function( event ) {
if (event.indexh === mySlideNumberWithAudio) { // might need to check indexv too
document.getElementById("audio2").play();
}
} );

Related

Loading multiple videos in one page

I am getting 40 videos on load of page and using foreach loop for displaying, below is my html code of displaying video
<div id="videosList">
<div class="video" data-id="{{$i}}">
<div class="videoSlate">
<video id="videoDiv{{$i}}" class="thevideo"
preload="metadata"
poster="/{{$postDetails->video_thumbnail}}" loop>
<source src="/{{$postDetails->videos}}">
Your browser does not support the video tag.
</video>
</div>
</div>
</div>
and on mouseover to video i am playing the video and on mouseout i am stopping the video here is the javascript code for play and pause
<script>
var figure = $(".video");
var vid = figure.find("video");
[].forEach.call(figure, function (item) {
item.addEventListener('mouseover', hoverVideo, false);
item.addEventListener('mouseout', hideVideo, false);
});
function hoverVideo(e) {
$('.thevideo')[$(this).attr("data-id")].play();
}
function hideVideo(e) {
$('.thevideo')[$(this).attr("data-id")].pause();
}
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
each video size is not more than 6 mb, now the problem is for loading page it will take around 1 min, and for playing video on hover it will take around 15 to 20 seconds to play, is there any way to reduce the loading time and video playing time. I am using laravel framework, in local its working but in server it giving problem.
I don't know why you need 40 videos in the same page, but I would not at all recommand that:
YOUTUBE:
Youtube doesn't display 20 videos per page, but 20 placeholder images that are used as link to click on in order to display the video. It is pretty UX friendly, since loading time is considerably reduced (images instead of videos) and users can choose what they load.
FACEBOOK, TWITTER, ETC...:
Social networks such as Facebook, Twitter, etc are using a scroll script, which loads videos only when they are visible by the user. This means that if there are 100 videos on the page, only one or two will be loaded and displayed, because this is useless to load stuff that the user can't see (even more if this is a heavy file, such as a video). This can be done with Javascript or jQuery (Here is a pretty cool question which gives you a solution).
I really recommand you to choose one of those two approach, since I can't figure out a case which requires to display 40 videos on one page with one load.

Load new video automatically when VideoJS MP4 ends

In a project I am currently working on, I have a VideoJS player which I want to change the source of when the video ends.
Using the VideoJS API, I am able to get a Javascript script to run when the player has reached an 'ended' state, but I can't find any code in their documentation or on StackOverflow explaining how to do this.
HTML
<video
id="my_video_1"
style="display:block;"
class="video-js vjs-default-skin vjs-nofull vjs-big-play-centered"
controls autoplay preload="none"
width="800px"
poster='res/img/poster.jpg'
data-setup='{ "fluid": true, "sources": [{ "type": "video/mp4", "src": "res/vid/vid1.mp4"}] }'
>
</video>
Is there any way of dynamically changing the src to a new file when the video ends?
The VideoJS has an API of 'player.on' which is then followed by whichever listener is needed - in this case, ('ended').
Where I was falling down was that I was trying to use document.GetElementByID and update the src that way.
By changing the VideoJS code in the HTML to the style above, I was able to run the below listening event to update the src on ended and load a new video.
The next issue I had was the video was looping. When the video ended, the same function was called infinitely.
To counter this, I added a Boolean value of 'executed' which changes to True on the first play.
<script>
var video = videojs('my_video_1').ready(function(){
var player = this;
var executed = false;
player.on('ended', function() {
if (!executed) {
player.src({"type":"video/mp4", "src":"res/vid/vid2.mp4"});
player.play();
executed = true
}
});
});
</script>
The first video now plays, followed by the second one when the first has finished without any user interaction.
I hope this helps anyone else who may experience a similar issue.

Delay loading of html5 video after the rest of the page finished loading

I have a video element being used as the background of a section towards the bottom of a page I'm building. I'm trying to build a sort of 'lazy-load' for it by storing the src as a data-src attribute and using jQuery to apply it to the src attribute after the other assets have loaded (since it's not a hero image or anything, I want to load a poster to save cut load-time and then load the video later). It doesn't seem to be working for me at all. The src attribute is applied correctly but the video doesn't load or autoplay. Am I approaching this from the wrong angle? Is there a better way to accomplish it?
Building on wordpress.
Basic HTML
<video width="100%" loop controls autoplay class="connect-bg">
<source data-src="<?php echo get_template_directory_uri(); ?>/contact_Footer.mp4" type="video/mp4">
</video>
jQuery Function
$(window).load(function(){
footer_lazyloader();
});
function footer_lazyloader() {
var $ = jQuery;
$("video.connect-bg source").each(function(){
var sourceFile = $(this).attr('data-src');
$(this).attr('src',sourceFile);
});
}
You can manually trigger the video to load and play by using '.load()' and '.play()' respectively. Target the parent of the 'source' element using 'parentElement' to accomplish this:
$(function() {
$("video.connect-bg source").each(function() {
var sourceFile = $(this).attr("data-src");
$(this).attr("src", sourceFile);
var video = this.parentElement;
video.load();
video.play();
});
});

Reveal.js html5 video and javascript - restarting video playback from beginning on slide change problems

I'm trying to make a kisok application to show some slides and play 2 videos from a menu using reveal.js. it is all working well and looks great apart from the video playback.
Im using a <video> tag inside the <section> as the data-background-video="something.mp4" didn't seem to restart on slide change either.
If i'm navigating out of the playing video slide and then returning to it, the video resumes where it left off and doesn't restart at the beginning as I require like even though autoplay is set to true.
I have tried to write something that does this with javascript using the api on Reveal.addEventListener after naming the <section> with data-state="something" and it works.. well kind of.. it works successfully for the first video only, well, then only for a while then it seems to break all video playback. the second video plays once then will not restart and i then can not control it via the console either.
here is the relevant html:
<!--*********************************************************Video 1 Page-->
<section id="rene_vid_page" data-state="video1_show" data-transition="fade-in fade-out" data-background="img/Backdrop.svg">
<h1 class="page_title">My page title</h1>
<video id="rene_vidplayer" data-autoplay data-src="Videos/full_edit_portrait.mp4" ></video>
<!--*********************************************************End Of Video 1 Page-->
<!--*********************************************************Video 2 Page-->
<section id="conc_vid_page" data-state="video2_show" data-transition="fade-in fade-out" data-background-color="#c8c8c8">
<h1 class="page_title">My page title</h1>
<video id="conc_vidplayer" data-autoplay data-src="Videos/2 Conclusions.mp4" ></video>
</section>
<!--*********************************************************End Of Video 2 Page-->
Here is the javascript i have cobbled together,
this also advances to the next slide when the video is finished and that bit works..
<script>
var video = document.getElementById("rene_vidplayer");
video.onended = function (e) {
console.log("video_ended slide advance");
Reveal.next();
};
Reveal.addEventListener('video1_show', function (e) {
// Called when "video1_show" slide is made visible
console.log('"rene video show has been called"');
video.currentTime = 0;
console.log('"videotime set to 0"');
video.play();
console.log('"video set to play"');
});
var video2 = document.getElementById("conc_vidplayer");
video2.onended = function (e) {
console.log("video2_ended slide advance");
Reveal.next();
};
Reveal.addEventListener('video2_show', function (e) {
// Called when "video2_show" slide is made visible
console.log('"video2_show has been called"');
video2.currentTime = 0;
console.log('"videotime set to 0"');
video2.play();
console.log('"video2 set to play"')
});
</script>
I can see in the console that the logs i have put in are working in the right places but the video stops behaving :( the second video will run from video2.play() in the console but only if the first one hasn't finished or the second one been played already.
You can tell that my js coding is not great at the moment and there are probably so many errors, and ultimately a much better way of doing this.
Any help or advice is greatly appreciated as it is desperately needed for a show next week!!
Ok, so i got this to work by adding a video.load() and video2.load() into the respective Reveal.addEventListener sections. Not sure if there are any problems associated with doing it this way or whether there is a better way?
However this is now working fine! :)

How to create a frame-accurate video sequencer with HTML5 <video>?

I am attempting to build a video sequencer that is capable of playing back a list of video URLs seamlessly in series. There cannot be a gap between the videos; the playback needs to be as close to frame-accurate as possible.
Attempt #1
I used a fairly obvious and straightforward approach, similar to that mentioned in this thread.
HTML 5 video or audio playlist
The issue with this approach was that each time one video ended and the subsequent video was specified as the new source, that new video still needed to load, resulting in a potentially long gap. If it is possible to force all the videos to preload even before they are named in video.src, this approach could still potentially work.
Attempt #2
I rewrote the script so each video in the list would result in a separate video element being created, but not attached to the document (using createElement). Then as each video ended, I removed the previous node and appended the next element.
Code executed on page load:
for (i in timelinePlay)
if (timelinePlay[i] != null)
{
var element = document.createElement('video');
element.id = 'video1-' + (i);
element.src = timelinePlay[i]['URL'];
element.preload = 'load';
video1Array[i] = element;
}
Code for video 'ended' event:
videoElement.addEventListener("ended", function (event) {
if (this.currentTime > 0)
{
if (player.hasChildNodes())
while (player.childNodes.length > 0)
player.removeChild(player.firstChild);
player = document.getElementById('canvas-player');
player.appendChild(video1Array[timelineCurrent]);
nextVideo = document.getElementById('video1-' + timelineCurrent);
nextVideo.play();
timelineCurrent++;
}
}, false);
(Note that these code examples are partial and somewhat simplified. Also, I do realize that my use of Objects as Associative Arrays is not best practice)
The result of this modification was MUCH closer, because the videos were now loaded by the time they were required to play, but there was still a short and inconsistent gap between the videos.
Attempt #3
I replaced the 'ended' event listener with a 'timeupdate' listener, beginning as follows:
nextVideo.addEventListener("timeupdate", function (event)
{
if (this.currentTime > (this.duration - 0.1) && this.currentTime > 1)
{
this.removeEventListener("timeupdate", function () { return; }, false);
('this.currentTime > 1' is simply to ensure that the previous video actually plays)
My hope was that the gap between videos was close enough to being consistent that starting the next video an arbitrary 0.1 seconds before the previous video ended would correct the gap to an acceptable extent. The result was that the timing was indeed better, but it was skipping videos. I attribute the skipped videos to misfiring of the 'timeupdate' event, but I could be mistaken.
Other alternative options I had also considered:
SMIL Script (seems to be obsolete, and would likely have the same syncing issues anyway)
ffmpeg on the backend to concatenate the videos (my host will not allow shell scripts)
FYI I am developing for Safari 5.0.3 at the moment
I had a similar problem that I managed to solve now thanks to your hints. The result is a possibly dynamic list of video elements that may be played back one after another without gaps.
Instead of a native Video Tag I use jwplayer on several video elements.
On startup all elements begin to play one second, are paused and rewound to zero.
Then one by another is played and made visible with display: block.
<ul class="playlist">
<li>
<video class="playlist" id="vid01" poster="img/preview.jpg">
<source src="vid/v01.mp4" type="video/mp4">
</video>
</li>
<li>
<video class="playlist" id="vid02" poster="img/preview.jpg">
<source src="vid/v02.mp4" type="video/mp4">
</video>
</li>
<li>
<video class="playlist" id="vid03" poster="img/preview.jpg">
<source src="vid/v03.mp4" type="video/mp4">
</video>
</li>
<li>
<video class="playlist" id="vid04" poster="img/preview.jpg">
<source src="vid/v04.mp4" type="video/mp4">
</video>
</li>
</ul>
On added to stage, 'preload' the video one or two seconds:
(Excerpt)
var isPrebuffering = false,
isSeeking = false;
$player = jwplayer(videoId).setup({
width: '800px',
height: '450px',
autoplay: false,
modes: [
{ type: 'html5' }
],
events: {
onReady: function(e) {
prebuffer();
},
// There is a quirk in jwplayer that makes it impossible to pause at the
// new position directly after seeking. So we have to work around that.
onTime: function(e) {
if((e.position > 1.0 && isPrebuffering) || isSeeking) {
finishPrebuffering();
}
}
}
});
function prebuffer() {
isPrebuffering = true;
$player.setMute(true);
$player.play();
};
function finishPrebuffering() {
if(isPrebuffering) {
isPrebuffering = false;
isSeeking = true;
$player.seek(0);
}
if($player.getPosition() === 0) {
isSeeking = false;
$player.pause();
$player.setMute(false);
}
};
The mediaElement interface of HTML5 can be quite confusing sometimes between preload, load and buffered.
But have you tried to put an event on your video to detect for example 3 seconds before the end of your video ?
Then in ajax try to load the next video in a new div.
On the ended event of your video you could switch the div, so your next video will be enough loaded to be played.
And so on for the next videos.
http://www.w3.org/TR/html5/video.html#media-elements
You might be able to do so with http://popcornjs.org/. They provide js hooks, on a frame by frame level into the video using html5 video tag. There are a lot of events etc.

Categories