i had a html5 video box with only one video inside. in this video their is a animated figure with different moves. as an example: second 1-5 the figure walks inside, second 5-7 the figure say "hello", ... i would like to control these animations with js and i would like to loop the main animation.
this is the html5 videoplayer:
<video id="vidplayer">
<source src="animation.mp4" type="video/mp4"</source>
</video>
i have tested following code to loop the video between the second 7-9 and it doesnt work:
var vid = $("#vidplayer").get(0);
vid.ontimeupdate = function(e) {
if(this.currentTime = 9) {
vid.currentTime = 7;
}
};
it works only with
(this.currentTime >= 9)
but with this ">=" i cant use animations above 9 seconds (like 21-29 seconds).
can you please help me? Thx!
you will need to check for both the start/stop of the fragments you want to loop within in order to constrain the test.
In the example below it will loop from the 15s mark (or greater) back to 10s; from the 9s mark back to 7; from the 5s mark back to 1.
For a production version I'd probably create an array of the jump points and use that to avoid having to type the times as an upper/lower, but this should give you a framework to go on from:
<video preload="auto" controls id="vidplayer">
<source src="BigBuck.m4v" type='video/mp4;'"></source></video>
<script>
var vid = document.getElementById("vidplayer")
vid.addEventListener('timeupdate', timeupdate, false);
function timeupdate() {
if (vid.currentTime >= 15) {
vid.currentTime = 10;
} else if (vid.currentTime >= 9 && vid.currentTime < 10) {
vid.currentTime = 7;
} else if (vid.currentTime >= 5 && vid.currentTime < 7) {
vid.currentTime = 1;
}
}
</script>
I had the same problem and wrote a plugin to solve it. See https://github.com/phhu/videojs-abloop . This allows javascript commands to be used to control looping of section of video. The example shows how you might control switching different sections of video using callbacks or otherwise.
Related
The videos all play when called. In search, addEventListener was suggested. Alas, no help. Perhaps I'm wording it wrong, but how to get the next button to go back to the first video in the array after the last video has played. JavaScript I am still learning to figure out its logic, and it is not a clean beast. Messy life is my outlook with JS. I have removed the videos as they are adult in nature (18+++), and do not want to offend anyone. The noted out are what I have tried that have no impact or negative impact on how the current setup functions.
let vids = [".mp4", ".mp4", ".mp4"]
// videoCount = vids.length;does nothing
// const found = vids.find(element => element < 3); does nothing
//Adultvideo.addEventListener('ended', next, false); does nothing
let i = 0;
let src=vids[i];
function next(e) {
i++;
if (i > 3){
// return src; does nothing
//return i; //does nothing
//const found = vids.find(element => element === 0); does nothing
// Adultvideo.load(); does nothing
//Adultvideo.play(vids[i]); does nothing
// return AdultVideo.trigger('loadstart');
}
document.getElementById("Adultvideo").src=vids[i];
}
// document.getElementById('Adultvideo').reset(src); does nothing
//src.Adultvideo.play(i);does nothing
//playVideo(i);
<body>
<header>
<h1>Adult Male Video 18 Plus !</h1></header>
<main>
<section class="vidcontainer">
<!-- Don't put control into element unless you are an adult 18+ for the vid could offend and disturb you. Likewise, do not push play either as the video could offend and disturb you -->
<!-- had to add height to control poster -->
<video id="Adultvideo" muted width="500" height="340" poster="">
<source id="Adultvideo" muted src="" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="Vcontrol">
<div class="Vpanel">Control Panel</div>
<button onclick="playVideo();">▷</button>
<button onclick="pauseVideo();">‖</button>
<button onclick="stopVideo();">⬜</button>
<button onclick="rewindVideo();">
⟲</button>
<button onclick="next();"><span class="reduce">▷▷</span> 𝄀</button>
</div>
</section></main>
<!-- I wish there was better instruction on this script here as copy and paste is not very good instruction -->
<script>
const Adultvideo=document.querySelector("#Adultvideo");
function playVideo() {
Adultvideo.play();
}
function pauseVideo() {
Adultvideo.pause();
}
function stopVideo() {
Adultvideo.load();
}
function rewindVideo() {
Adultvideo.currentTime= 0;
<!-- this function does not work, and unable to locate how to correct. All the extra JS does not help. The teaching sucks for this course. It does work, but still not perfect -->
function next() {
Adultvideo.next();
}
// Adultvideo.addEventListener('ended', next, false); affects nothing
}
// Adultvideo.addEventListener('ended', next, false); //affects nothing
</script>
</body>
The main question you asked is "how [do I] get the next button to go back to the first video"...
To answer that, the answer is fairly straightforward: Use the remainder operator. This is a common programming practice for wrapping a value.
For example:
// Go to the next video (and wrap)
i = (i + 1) % vids.length;
// Load the new video selection
videoSrcEl.src = vids[i];
videoEl.load();
EDIT:
The reason this works is because i++ is equivalent to i = i + 1 and the remainder after division will always be between 0 and n - 1. That second part sounds more complicated than it is, so let's just look at i % 3 as i changes (for n = 3):
If i = 0, then i % 3 = 0
If i = 1, then i % 3 = 1
If i = 2, then i % 3 = 2
If i = 3, then i % 3 = 0
If i = 4, then i % 3 = 1
If i = 5, then i % 3 = 2
If i = 6, then i % 3 = 0
...notice the pattern?
An alternative would be to use an if statement:
// Go to the next video (and wrap)
i++;
if (i > vids.length - 1) {
i = 0;
}
// Load the new video selection
videoSrcEl.src = vids[i];
videoEl.load();
Beyond that question, though, I'd like to propose a few changes to the rest of your code:
Don't use id="Adultvideo" on both the <video> and the nested <source>. IDs are expected to be unique.
Don't use inline JS like onclick="playVideo();". This requires a global function, which is rarely what you really want. The better way is to use playButton.addEventListener('click', playVideo) in the JS somewhere (and I add an IIFE to make sure nothing is global by accident)
I made a working example below, which uses a lot of newer JS syntax, but I hope you can make sense of it. These may be just my preference but note that:
arrow functions do have some differences from regular functions but they're mostly equivalent. I use them because they're shorter
I find it easier to just use classes and avoid IDs in almost all cases. I do separate CSS classes from JS classes, though
const prevents certain changes (re-assignment), but otherwise works like let
// IIFE
;(() => {
// Create a couple reusable functions (DRY up the code below)
const el = s => document.querySelector(`.js-${s}`)
const click = (s, fn) => el(s).addEventListener('click', fn)
// Get references to DOM elements (see HTML)
const videoEl = el('video')
const videoSrcEl = el('video-src')
// List of videos (I found a few random ones from across the web)
const vids = [
'https://i.imgur.com/tTaZyQC.mp4',
'https://i.imgur.com/WHifiaH.mp4',
'http://giant.gfycat.com/FineDangerousFruitbat.mp4'
]
let i = 0 // <-- which video is currently selected
// Handle clicks
click('play', () => { videoEl.play() })
click('pause', () => { videoEl.pause() })
click('stop', () => { videoEl.load() })
click('rewind', () => { videoEl.currentTime = 0 })
click('next', () => {
// Go to the next video (and wrap)
i = (i + 1) % vids.length
// Load the new video selection
videoSrcEl.src = vids[i]
videoEl.load()
})
// Load the first video
videoSrcEl.src = vids[i]
})()
<header>
<h1>Title Here</h1>
</header>
<main>
<section class="video">
<video class="js-video" muted width="500" height="340" poster="">
<source class="js-video-src" muted src="" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="video-control">
<div class="video-panel">Control Panel</div>
<button class="js-play">▷</button>
<button class="js-pause">‖</button>
<button class="js-stop">⬜</button>
<button class="js-rewind">⟲</button>
<button class="js-next">
<span class="reduce">▷▷</span>𝄀
</button>
</div>
</section>
</main>
"How to get the next button to go back to the first video in the array after the last video..."
Positions in Array start from zero as first item, so an array with 3 items has positions (index) of:
array[0], array[1], array[2]
As you can see the last item's index is 2, which is just minus 1 from a total array length of 3 items. In other words, last item pos can be calculated from array.length - 1 (eg: 3 - 1 = 2).
Try something like this:
<script>
var i = 0;
var vids = ["first.mp4", "second.mp4", "third.mp4"]; //has positions [0, 1, 2]
var videoCount = vids.length; //is 3
var myPlayer = document.getElementById("Adultvideo");
function playVideo() { myPlayer.play(); }
function pauseVideo() { myPlayer.pause(); }
function stopVideo() { myPlayer.currentTime = 0; myPlayer.pause(); }
function rewindVideo() { myPlayer.currentTime = 0; }
function next()
{
i++; //# count range is from 0 up to 2 (since total is 3 items)
if (i == 2) { i = 0; } //reset after third count
//if (i == (vids.length - 1) ) { i = 0; } //or auto-detect total items then reset
myPlayer.src = vids[i];
myPlayer.play();
}
</script>
I have to play a short fragment of bigger audio. I use currentTime to set starting point in time, and timeupdate event to stop audio when required.
I noticed that on few early timeupdate events sometimes currentTime is less than its initial value, despite there is (obviously) no "rewind" actions.
Here is code example:
var start = 1;
var end = 1.3;
var audio = document.getElementById('audio');
audio.addEventListener('timeupdate', function () {
console.log(audio.currentTime);
if (audio.currentTime < start || audio.currentTime > end) {
audio.pause();
}
});
audio.currentTime = start;
audio.play();
For example, output of console log can be this:
1
0.85
0.85
1
1.02
...
Here's an example.
Tested on iPad with iOS 11.4.1. This problem appears only on very short time ranges ~0.3sec.
At first you have a wrong question because you want that your script works on iOS. And because of this your question in title is irrelevant. We have a lot of bugs on iOS and the iOS developers do not want to correct them. It is a bug. Write to support from iOS and ask there "How is it possible?".
At second you have two questions in your post because your script does not work on iOS like you it want.
I wrote for you the solution. Make sure you are not trying to call the audio before the audio element has metadata loaded (first mistake). Then you have the second mistake: instead of:
if(audio.currentTime < start || audio.currentTime > end) //your mistake
you have to write:
if(audio.currentTime >= end)
The solution (it works on iOS too)
var start = 1,
end = 1.3,
audio = document.getElementById('audio'),
button = document.getElementById('button'),
log = document.getElementById('log');
audio.addEventListener('timeupdate', function()
{
writeLog(audio.currentTime);
//your mistake: if(audio.currentTime < start || audio.currentTime > end)
if(audio.currentTime >= end)
{
audio.pause();
}
});
function writeLog(value)
{
var div = document.createElement('div');
div.innerHTML = value;
log.insertBefore(div, log.firstChild);
}
audio.addEventListener('loadedmetadata', function()
{
audio.pause();
button.removeAttribute('disabled');
});
button.addEventListener('click', function()
{
log.insertBefore(log.lastChild.cloneNode(!0), log.firstChild);
audio.currentTime = start;
audio.play();
});
#log
{
width:100%;
height:18em;
overflow-y:auto;
font:3em 'Courier New';
background:#069;
color:#7e0
}
#log div:last-child{display:none}
<!--
For this link from your example (on jsfiddle.net) is only a download is possible, but not using as source:
http://techslides.com/demos/samples/sample.m4a
-->
<audio id="audio" preload="auto">
<source src="http://techslides.com/demos/samples/sample.mp3" type="audio/mpeg"/>
<source src="http://techslides.com/demos/samples/sample.ogg" type="audio/ogg"/>
<source src="http://techslides.com/demos/samples/sample.aac" type="audio/aac"/>
</audio>
<button id="button" disabled style="width:9em;height:3em;font-size:3em">Play</button>
<br><br>
<div id="log"><div><hr></div></div>
The snippet on SO does not work because it is in sandbox.
See this working example on codepen.io.
I have designed an i-phone-like screen on a web browser where I am testing this application I am in the process of building. It works great up until the point where I want to call out another set of videos.
What works
The application is structured so that when the user sees the screen she is directed to a channel that has a vertical video.
The buttons on the top left and top right advance to the next and the previous video.
<div id="topVid" class="videoContainer">
<div class="topHorizontalButtonRow">
</div>
<video class="topVid" loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/ParisisBurning_660x370_I_went_to_a_ball.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
There is a "channel" button that shows the user a smaller window if pressed, where the user can view other channels by clicking on a second set of buttons next and previous buttons.
<div id="bottomVid" class="videoContainerTwo hiddenElement">
<div class="topHorizontalButtonRow">
<div class="buttonLeftTriangleBlue"></div>
<div class="buttonRightTriangleBlue"></div>
</div>
<video loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/Politics_Refugee_Sign.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
jquery show/hide smaller window:
$(".buttonTeardropChannelBlue").click( function (){
if( $("#bottomVid").is(':visible') ) {
$("#bottomVid").hide();
} else {
$("#bottomVid").show();
}
});
If the user wants to watch this specific channel, she can click on the smaller window, which hides the current window and advances to the other channel. The video can be clicked on, and once that happens, the user will be directed to the next channel.
Below is the code that works perfectly to advance the video of the current selection, and it contains the videos in arranged in an array.
var Vids = (function() {
var _currentId = -1;
var _urls =
["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
What does not work
The issue: showing and hiding multiple video lists
However, the problem starts when I want to select a different class of videos, which has the exact same code except for different videos. I have changed the name of the function to say, VidsTwo but the problem remains.
var VidsTwo = (function() {
var _currentId = -1;
var _urls = ["videos/Politics_Atl_We_are_the_people.mp4","videos/Politics_Atlanta_Whose_Streets.mp4", "videos/Politics_Womens_March_Washington_CBS_VERT.mp4",
"videos/Politics_No_bans_no_walls_America_is_home_to_all_VERT.mp4",
"videos/Politics_Let_them_in_VERT.mp4",
"videos/Politics_Tear it Down_JFK_VERT.mp4",
"videos/Politics_This_is_What_America_Looks_Like_embrace.mp4",
"videos/Politics_This_land_was_made_VERT.mp4", "videos/Politics_We_need_an_independent_investigation_town_hall.mp4",
"videos/Politics_Just say no_town_hall_VERT.mp4", ]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
The issue remains: the buttons will continue to play the videos of the current channel in addition to the ones of the new channel, and it will not hide the current video. I understand it happens because in the javascript code, it uses the select element by tag which is "video". and all the array lists have "video" so it is playing all of them.
What is the best solution to this problem, given that I want to be able to separate the videos into categories "channels" that will have similar thematic content, and that this categories will be called by users as they look at a second smaller window of videos?
Core questions
Is there a way to have it NOT play a selection of arrays? What can I change in the Javascript code that will indicate that these separate video arrays do not belong to the same class? How can I make it clear in the code that these videos, although they are all videos, belong to different categories and therefore can only be played if their specific category is called?
Brainstorming solutions:
I am thinking I would probably need a second div that will have a
second row of buttons that call out the second function, since the
prev and next indicate a separate variable that was declared for each
class of videos...but this is getting a bit complicated for my newbie
skills:)
Or perhaps each video on a parent class should be saved on the
html itself as a hidden div and should be called by using "show
next child of parent div", as opposed to being saved as an array on
the javascript code?
The next step is adding marquee text to each video so maybe having
separate hidden divs on the html itself is a better solution than
having the videos stored as javascript arrays?
This is basically a prototype/beta for something that will become an
app so there is no database yet, (which will make it easier to
store this info eventually once I begin more in-depth user tests).
This complication is for testing only:)
UPDATE: I am still curious as to what the best solution would be, however I have decided, in this case, to add divs directly to the html and use jquery's next sibling selectors. Because I will have some text specific to some videos, they won't be properly connected to the javascript arrays anyway. I find the javascript array solution "cooler" but it is perhaps not the best in the end.
make Vids like this:
var Vids = function(vidArray=[]) {
var _currentId = -1;
var _urls = vidArray;
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
};
then prepare your url array and call Vids:
var urls =["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"];
Vids(urlf).play(3); //Replace 3 with any id
Is there any way to play a video in html5, stop and execute javascript at known points within the video?
Yes, try this. You have to use the currentTime property. Start with that and start your javascript functions from there. Is that what you're looking for?
var vid = document.getElementById("video");
//Add a timeupdate listener
video.addEventListener("timeupdate", function(){
//Check for video properties from within the function
if (this.currentTime == 5)
this.pause();
//cal javascript
}
}
Looking at the accepted answer over here it looks like it is possible.
To pause the video you just do this:
var mediaElement = document.getElementById("video"); // create a reference to your HTML5 video
mediaElement.pause(); // pauses the video
If you want to play the video, do this:
mediaElement.play(); // plays the video
To get the current time in the video, do this:
mediaElement.currentTime; // gets the current time
Here's an example linking them all up:
var mediaElement = document.getElementById("video");
if(mediaElement.currentTime == 35){
mediaElement.pause();
// do whatever else you would like
mediaElement.play();
}
The MDL documentation is here, there are plenty of other properties you might find helpful.
Hope this helps!
Yes, by doing like this you can.
Note that you have to look for a time using bigger than > bigger than (as the chance to match an exact millisecond is almost zero), and have a variable in one way or the other to know which ones is done.
window.addEventListener('load', function() {
var cur = document.querySelector('#cur'),
vid = document.querySelector('#vid')
})
var appDone = {"done7":false,"done4":false}
vid.addEventListener('timeupdate', function(e) {
if (e.target.currentTime > 7 && !appDone.done7) {
appDone.done7 = true;
e.target.pause();
//do something
cur.textContent += ", " + "done7 once";
e.target.play();
}
if (e.target.currentTime > 4 && !appDone.done4) {
appDone.done4 = true;
e.target.pause();
//do something
cur.textContent += ", " + "done4 once";
e.target.play();
}
})
<video id="vid" width="320" height="176" controls>
<source src="http://www.w3schools.com/tags/mov_bbb.mp4" type="video/mp4">
<source src="http://www.w3schools.com/tags/mov_bbb.ogg" type="video/ogg">
Your browser does not support HTML5 video.
</video>
<p id="cur"></p>
Here's my jsfiddle for review: http://jsfiddle.net/Z2Nq8/81/
The code works perfect in Chrome on my Mac. Firefox and Safari don't. I had another contributor who did the code edits, and he says everything is working on Windows. Please review and let me know if you see something that I'm doing wrong. Thanks!
js:
$(function () {
var $videos = $('.video'),
numVideos = $videos.length,
counter = 0;
setInterval(function () {
++counter;
var $currentVideo = $('.video[data-state="playing"]'),
$nextVideo = $currentVideo.next();
$currentVideo.attr('data-state', '');
if (counter == numVideos) {
counter = 0;
$nextVideo = $videos.first();
}
$nextVideo.attr('data-state', 'playing');
$currentVideo.toggleClass('hidden');
$nextVideo.toggleClass('hidden');
$currentVideo.find('video')[0].pause();
$currentVideo.find('video')[0].currentTime = 0;
$nextVideo.find('video')[0].play();
}, 3000); // do this every 3 seconds
});
And for some reason my HTML and CSS code won't display here (i've added 4 spaces and tried quotations) so, you'll have to look at jsfiddle (see above).
Thanks for helping this noob!
S
I have tested your fiddle and I can see straight away that on Firefox won't work because you are using mp4. You can embed an alternative format for the video and you can use .ogg for firefox and opera.
Check this MDN resource: https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats?redirectlocale=en-US&redirectslug=Media_formats_supported_by_the_audio_and_video_elements
<video controls>
<source src="somevideo.webm" type="video/webm">
<source src="somevideo.mp4" type="video/mp4">
I'm sorry; your browser doesn't support HTML5 video in WebM with VP8 or MP4 with H.264.
<!-- You can embed a Flash player here, to play your mp4 video in older browsers -->
</video>
Modified the fiddle a bit. It works on Safari, but to get more support you also need to include webm & ogg.
http://jsfiddle.net/me2loveit2/Z2Nq8/82/
var content = [
['http://bwpcommunications.com/videobg/001.mp4','Let\'s get together and discuss your brand.'],
['http://bwpcommunications.com/videobg/002.mp4','Let\'s build a strategy together face to face.'],
['http://bwpcommunications.com/videobg/003.mp4','Let\'s create a compelling campaign and tell your story.']
];
var numVideos = content.length,
counter = 0,
$video = $('#bgvid');
$title = $('#title');
setInterval(function () {
++counter;
if (counter == numVideos) {
counter = 0;
}
$video.attr('src',content[counter][0]);
$title.html(content[counter][1]);
}, 5000); // do this every 3 seconds