Multiple audio players but only first working - javascript

The problem is that when i have 2 or more players on html page i can only play music in the first player and the rest wont work.
my customized HTML5 audio player:
<audio id="music" preload="true">
<source src="music/interlude.mp3">
</audio>
<div id="wrapper">
<div id="audioplayer">
<button id="pButton" class="play"></button>
<div id="timeline">
<div id="playhead"></div>
</div>
</div>
</div>
and js for this:
document.addEventListener("DOMContentLoaded", function(event) {
var music = document.getElementById('music'); // id for audio element
var duration; // Duration of audio clip
var pButton = document.getElementById('pButton'); // play button
var playhead = document.getElementById('playhead'); // playhead
var timeline = document.getElementById('timeline'); // timeline
// timeline width adjusted for playhead
var timelineWidth = timeline.offsetWidth - playhead.offsetWidth;
// play button event listenter
pButton.addEventListener("click", play);
// timeupdate event listener
music.addEventListener("timeupdate", timeUpdate, false);
// makes timeline clickable
timeline.addEventListener("click", function(event) {
moveplayhead(event);
music.currentTime = duration * clickPercent(event);
}, false);
// returns click as decimal (.77) of the total timelineWidth
function clickPercent(event) {
return (event.clientX - getPosition(timeline)) / timelineWidth;
}
// makes playhead draggable
playhead.addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
// Boolean value so that audio position is updated only when the playhead is released
var onplayhead = false;
// mouseDown EventListener
function mouseDown() {
onplayhead = true;
window.addEventListener('mousemove', moveplayhead, true);
music.removeEventListener('timeupdate', timeUpdate, false);
}
// mouseUp EventListener
// getting input from all mouse clicks
function mouseUp(event) {
if (onplayhead == true) {
moveplayhead(event);
window.removeEventListener('mousemove', moveplayhead, true);
// change current time
music.currentTime = duration * clickPercent(event);
music.addEventListener('timeupdate', timeUpdate, false);
}
onplayhead = false;
}
// mousemove EventListener
// Moves playhead as user drags
function moveplayhead(event) {
var newMargLeft = event.clientX - getPosition(timeline);
if (newMargLeft >= 0 && newMargLeft <= timelineWidth) {
playhead.style.marginLeft = newMargLeft + "px";
}
if (newMargLeft < 0) {
playhead.style.marginLeft = "0px";
}
if (newMargLeft > timelineWidth) {
playhead.style.marginLeft = timelineWidth + "px";
}
}
// timeUpdate
// Synchronizes playhead position with current point in audio
function timeUpdate() {
var playPercent = timelineWidth * (music.currentTime / duration);
playhead.style.marginLeft = playPercent + "px";
if (music.currentTime == duration) {
pButton.className = "";
pButton.className = "play";
}
}
//Play and Pause
function play() {
// start music
if (music.paused) {
music.play();
// remove play, add pause
pButton.className = "";
pButton.className = "pause";
} else { // pause music
music.pause();
// remove pause, add play
pButton.className = "";
pButton.className = "play";
}
}
// Gets audio file duration
music.addEventListener("canplaythrough", function() {
duration = music.duration;
}, false);
// getPosition
// Returns elements left position relative to top-left of viewport
function getPosition(el) {
return el.getBoundingClientRect().left;
}
/* DOMContentLoaded*/
});
i belive the problem is somewhere in the js code but i cant figure out where.
i took the code form here

I notice that you're using a lot of IDs. When the "first of something" works on a page, usually it's IDs that are causing the issue.
Change all of your IDs for your <audio> players to class attributes. You will also need to update your JavaScript as well, from something like this:
var music = document.getElementById('music');
music.addEventListener(...
To something more like this:
var music = document.querySelectorAll(".music"); // class="music"
for (var i = 0; i < music.length; i++) {
music[i].addEventListener(...
You should find that this will work for you.

Related

Run canvas animation and video synchronously

I want to animate stuff on a canvas using the window.requestanimationframe() method on top of two video (e.g. for highlighting important stuff in both videos). Currently, the animation runs and after that, the videos start playing together. So how can I execute everything (both videos and canvas animation) simultaneously?
class Animation {
constructor(canvas, data) {
this.canvas = document.getElementById(canvas);
this.ctx = this.canvas.getContext('2d');
this.data = data;
this.start = 0;
this.counter = 0;
this.running = false;
this.draw = function(){
console.log(this);
console.log("Draw");
if(!document.querySelector('video').playing){
// init
this.ctx.clearRect(0, 0, 300, 300); // clear canvas
// get data
var in_video_data = this.data['in_video'];
// draw CircleLineTimeSeries
for (var i=0; i<in_video_data.length; i++){
var item = in_video_data[i];
// if counter in phase intervall
if (this.counter >= item['start'] && this.counter <= item['end']){
console.log(item);
if (item['object'] == 'CircleLineTimeSeries'){
this.visualizeCircleLine(item['raw_kps'][0][this.counter],
item['raw_kps'][1][this.counter]);
}
}
}
// Increase time variable
this.counter += 1;
}
if (this.running){
window.requestAnimationFrame(this.draw.bind(this));
}
}
}
visualizeCircleLine(kps0, kps1){
this.ctx.beginPath();
this.ctx.moveTo(kps0[0], kps0[1]);
this.ctx.lineTo(kps1[0], kps1[1]);
this.ctx.stroke();
}
play(){
this.running = true;
window.requestAnimationFrame(this.draw.bind(this));
}
pause(){
this.running = false;
}
}
The code for running the video and the canvas animation:
/**
* Event handler for play button
*/
function playPause(){
if (running){
running = false;
animation.pause();
video0.pause();
video1.pause();
} else {
running = true;
animation.play();
video0.play();
video1.play();
}
}
Thank you in advance :)
As #Kaiido noted, you have to listen for updates in current time of the video. There is respective media event - timeupdate. Furthermore you should have a list of key frames of the video when to show your animation. Whenever timeupdate event fires, check the current time for reaching some key frame and, if so, notify your requestanimationframe callback to run animation via some shared variable.

Stopping more than one instance of a function running at a time

I am fairly new to JavaScript and have searched everywhere for an answer to my question and cant seem to find anything related at all. This tells me that I'm missing something with my understanding of how my program works.
I have written a small game where the player navigates through a randomly generated maze using a gameloop that checks keydown events every x milliseconds. The game has a difficulty dropdown menu and then the game is started my clicking a button that calls a function to create a canvas where the game is drawn.
My problem is that when the button is clicked again to create a new maze without reloading the page, the gameloop for the original maze is still running and so key events are registered twice. This is causing some unexpected behavior. It's as though every time the button is clicked, a new instance of the function is running. Is there some way that each time the button is clicked I can set it to stop the previous game function?
var canvas;
var div;
var mazeGenButton;
$(document).ready(function () {
canvas = null;
div = document.getElementById('canvascontainer');;
mazeGenButton = document.getElementById("mazeGenButton");
mazeGenButton.onclick = createInstance;
});
function createInstance() {
if (canvas != null) {
div.removeChild(document.getElementById("myCanvas"));
}
canvas = document.createElement('canvas');
canvas.id = "myCanvas";
canvas.width = 1000;
canvas.height = 1000;
div.appendChild(canvas);
drawMaze();
};
var drawMaze = function () {
//code here to create the game(not posted)
//here is the Key listener - not sure if it's related
var keyState = {};
window.addEventListener('keydown', function (e) {
keyState[e.keyCode || e.which] = true;
}, true);
window.addEventListener('keyup', function (e) {
keyState[e.keyCode || e.which] = false;
}, true);
function gameLoop() {
//left
if (keyState[37] || keyState[65]) {
if (isLegalMove(playerXPos - 1, playerYPos)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerXPos -= 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
//right
if (keyState[39] || keyState[68]) {
if (isLegalMove(playerXPos + 1, playerYPos)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerXPos += 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
//up
if (keyState[38] || keyState[87]) {
if (isLegalMove(playerXPos, playerYPos - 1)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerYPos -= 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
//down
if (keyState[40] || keyState[83]) {
if (isLegalMove(playerXPos, playerYPos + 1)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerYPos += 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
drawSurroundingCells();
setTimeout(gameLoop, 50);
}
}

Can't set video.currentTime by setting video.currentTime = {value}

In this piece of code I have video.currentTime = {value}
And it works fine.
But when I'm trying to reload the page by pressing Crtl+Shift+R it sets video.currentTime to 0, no matter when on the progress bar I clicked.
Why is that?
window.addEventListener('load', function(){
var video = document.getElementById('video');
var playButton = document.getElementById('play-button');
var pbar = document.getElementById('pbar');
var update;
var pbarContainer = document.getElementById('pbar-container');
video.load();
video.addEventListener('canplay', function(){
playButton.addEventListener('click', playOrPause, false);
pbarContainer.addEventListener('click', skip, false);
}, false);
var skip = function(ev) {
var mouseX = ev.pageX - pbarContainer.offsetLeft;
var width = window.getComputedStyle(pbarContainer).getPropertyValue('width');
width = parseFloat(width.substr(0, width.length - 2));
video.currentTime = (mouseX/width)*video.duration;
};
var updatePlayer = function() {
var percentage = (video.currentTime/video.duration)*100;
pbar.style.width = percentage + '%';
if(video.ended) {
window.clearInterval(update);
playButton.src = 'images/replay.png';
}
};
var playOrPause = function(){
if(video.paused) {
video.play();
playButton.src = 'images/pause.png';
update = setInterval(updatePlayer, 30);
} else {
video.pause();
playButton.src = 'images/play.png';
window.clearInterval(update);
}
};
//video.addEventListener('click', playOrPause(playButton), false);
}, false);
Refreshing your page stops all execution of your code and resets all your variables, basically starting you from the beginning.
If you want variables to remain even after refreshing the page then set the localStorage and your values will be saved on the browser. You can find them if you open your developer tools in the Resources section under localStorage:
localStorage.setItem(video.currentTime,value)
To retrieve it, you'll have to use
localStorage.getItem(video.currentTime,value)

html5 video: play/pause custom button issue

I am using an HTML5 Video on my website, with certain other codes that basically makes usability more customized.
The video is intended to play when in view and pause when not in view. Additionally it also has a play and pause button that comes into view when the mouse hovers on the video.
At the end of the video it turns into an image because by default the html5 video would just turn to blank.
The problem is that the image turns up in the end, but the play/pause continue to appear on hover and function as play pause but only audio. You cannot see the video.
I originally wanted it to just show the picture. But would prefer to have the play pause turn into a restart button if the video ends.
I tried looking for something that would fit my existing setup, but I am not sure how to make it happen and which of these codes would I play with.
Here is a link for the site
http://minhasdistillery.com/blumersmoonshine/
<section id="feature">
<div id="trail">
<div id="videocontrol">
<a id="play-pause" class="play"><img src="images/pause.png"/></a>
</div>
<video id="video_background" preload="auto" volume="5"><!--or turn on loop="loop"-->
<source src="videos/video.webm" type="video/webm">
<source src="videos/video.mp4" type="video/mp4">
<source src="videos/video.ogv" type="video/ogg ogv">
</video>
<img id="image_background" src="images/blumer.jpg" width="100%" height="100%" />
</div><!--trail-->
</section><!--feature-->
Javascript that brings up play/pause button
<script>
window.onload = function() {
var video = document.getElementById("video_background");
var playButton = document.getElementById("play-pause");
playButton.addEventListener("click", function() {
if (video.paused == true) {
video.play();
playButton.innerHTML = "<img src='images/pause.png'/>";
} else {
video.pause();
playButton.innerHTML = "<img src='images/play.png'/>";
}
});
}
</script>
The code sets the video to play on when visible and pause otherwise
<script>
//play when video is visible
var videos = document.getElementsByTagName("video"), fraction = 0.8;
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = 0,
y = 0,
w = video.offsetWidth,
h = video.offsetHeight,
r, //right
b, //bottom
visibleX, visibleY, visible,
parent;
parent = video;
while (parent && parent !== document.body) {
x += parent.offsetLeft;
y += parent.offsetTop;
parent = parent.offsetParent;
}
r = x + w;
b = y + h;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
//check at least once so you don't have to wait for scrolling for the video to start
window.addEventListener('load', checkScroll, false);
checkScroll();
</script>
This one adds the photo in the end.
<script>
var video = document.getElementById('video_background');
var wrapper = document.getElementById('wrapper');
var image = document.getElementById('image_background');
video.addEventListener('ended', function() {
video.style.display = 'none';
image.style.display = 'inline';
}, false);
</script>
A JSBin of the same issue is here
JSBin For Issue
as you will see at the end of the video it will continue to show pause and play and will only play audio.
How do I get it to read that the video ended and switch the button to "replay"
Initially video display style is block and image display style is none.
Video ended event handler sets video display to none and image display to inline.
You can check video display style in button click event handler and toggle it:
playButton.addEventListener(
'click',
function(event) {
if (video.style.display === 'none') {
image.style.display = 'none';
video.style.display = 'block';
}
...
},
false
);
As an alternative add boolean flag which is intially set to false, on video ended event set it to true:
var needReplay = false;
video.addEventListener(
'ended',
function() {
...
needReplay = true;
},
false
);
playButton.addEventListener(
'click',
function(event) {
if (needReplay) {
image.style.display = 'none';
video.style.display = 'block';
needReplay = false;
}
...
},
false
);
Demo

Pausing video if currentTime >= 2

I'd like to pause a video when currentTime is >=2 but I have a problem.
When you click on white div, video changes and I want that video to pause at 2 sec. But as you can see on the fiddle, first video pauses at 2 seconds too and I don't want that. I want my eventhandler function to work only with the second video not the first one.
HTML
<video src="videos/loop.webm" id="video" width="100%" autoplay>
</video>
JS
//This code tracks currentTime
$("#video").on(
"timeupdate",
function(event){
onTrackedVideoFrame(this.currentTime);
});
});
function onTrackedVideoFrame(currentTime){
$("#current").text(currentTime);
}
video.addEventListener("timeupdate", function() {
if (this.currentTime >= 2.000 && this.currentTime <= 8.000) {
this.pause();
}
}, false);
//This code tracks currentTime
//this code changes video source
var videoSource = new Array();
videoSource[0]='videos/loop.webm';
videoSource[1]='videos/fullcut.webm';
var videoCount = videoSource.length;
function videoPlay(videoNum)
{
var video = document.getElementById('video');
video.setAttribute("src",videoSource[videoNum]);
video.load();
video.play();
}
//this code changes video source
Here's the fiddle : http://jsfiddle.net/fKfgp/22/
Thanks for reading!
One way would be to set the timeupdate listener to after you set the new source.
$("#video").on(
"timeupdate",
function(event){
onTrackedVideoFrame(this.currentTime);
});
function onTrackedVideoFrame(currentTime){
$("#current").text(currentTime);
}
var videoSource = new Array();
videoSource[0]='http://www.w3schools.com/html/mov_bbb.mp4';
videoSource[1]='http://www.tools4movies.com/trailers/1012/Kill%20Bill%20Vol.3.mp4';
var videoCount = videoSource.length;
function videoPlay(videoNum)
{
var video = document.getElementById('video');
video.setAttribute("src",videoSource[videoNum]);
video.load();
video.play();
video.addEventListener("timeupdate", function() {
if (this.currentTime >= 2.000 && this.currentTime <= 8.000){
this.pause();
}
}, false);
}

Categories