HTML + JavaScript custom player for multiple videos on a website page - javascript

EDIT: I have found the solution, posted and marked as the best answer below.
I'm coding a portfolio website for myself using HTML, CSS and JS and I need to add multiple videos on a lot of pages.
I followed some tutorials to learn how to customize the video player, but it only works for one specific video on the page. If I were to add more videos, I'd need to have one .js custom player file for each video and manually select them on the website.
How can I apply this single .js custom video player to all of my videos using purely javascript?
I have found similar topics about the subject here, but all of them uses jQuery and I'm struggling to make it work with javascript.
My HTML for the video player:
<section class="videoplayer">
<div class="c-video">
<div id="video_player">
<video src="./media/portfolio/videos/Show-Reel-2021.mp4" id="main-video"></video>
<div class="progressAreaTime">00:00</div>
<div class="controls">
<div class="progress-area">
<div class="progress-bar">
<span></span>
</div>
<div class="buffered-progress-bar"></div>
</div>
<div class="controls-list">
<div class="controls-left">
<span class="icon">
<i class="material-icons fast-rewind" title="Retroceder 10 segundos">first_page</i>
</span>
<span class="icon">
<i class="material-icons play_pause" title="Reproduzir">play_arrow</i>
</span>
<span class="icon">
<i class="material-icons fast-forward" title="Avançar 10 segundos">last_page</i>
</span>
<span class="icon">
<i class="material-icons volume" title="Sem áudio">volume_up</i>
<input type="range" min="0" max="100" class="volume_range">
</span>
<div class="timer">
<span class="current">00:00</span> / <span class="duration">0:00</span>
</div>
</div>
<div class="controls-right">
<span class="icon">
<i class="material-icons auto-play" title="A repetição automática está desativada"></i>
</span>
<span class="icon">
<i class="material-icons settingsBtn" title="Detalhes">settings</i>
</span>
<span class="icon">
<i class="material-icons picture_in_picture" title="Miniplayer">picture_in_picture_alt</i>
</span>
<span class="icon">
<i class="material-icons fullscreen" title="Tela inteira">fullscreen</i>
</span>
</div>
</div>
</div>
<div id="settings">
<div class="playback">
<span>Velocidade da Reprodução</span>
<ul>
<li data-speed="0.25">0.25</li>
<li data-speed="0.5">0.5</li>
<li data-speed="0.75">0.75</li>
<li data-speed="1" class="active">Normal</li>
<li data-speed="1.25">1.25</li>
<li data-speed="1.5">1.5</li>
<li data-speed="1.75">1.75</li>
<li data-speed="2">2</li>
</ul>
</div>
</div>
</div>
</div>
My JavaScript for the video player:
// Select elements
const vidsrc = document.querySelector('#main-video').src;
const video_player = document.querySelector('#video_player'),
mainVideo = video_player.querySelector('#main-video'),
progressAreaTime = video_player.querySelector('.progressAreaTime'),
controls = video_player.querySelector('.controls'),
progressArea = video_player.querySelector('.progress-area'),
progress_Bar = video_player.querySelector('.progress-bar'),
buffered_Bar = video_player.querySelector('.buffered-progress-bar'),
fast_rewind = video_player.querySelector('.fast-rewind'),
play_pause = video_player.querySelector('.play_pause'),
fast_forward = video_player.querySelector('.fast-forward'),
volume = video_player.querySelector('.volume'),
volume_range = video_player.querySelector('.volume_range'),
current = video_player.querySelector('.current'),
totalDuration = video_player.querySelector('.duration'),
auto_play = video_player.querySelector('.auto-play'),
settingsBtn = video_player.querySelector('.settingsBtn'),
picture_in_picture = video_player.querySelector('.picture_in_picture'),
fullscreen = video_player.querySelector('.fullscreen'),
settings = video_player.querySelector('#settings'),
playback = video_player.querySelectorAll('.playback li');
mainVideo.addEventListener('loadeddata',()=>{
setInterval(() => {
let bufferedTime = mainVideo.buffered.end(0);
let duration = mainVideo.duration;
let width = (bufferedTime / duration) * 100;
buffered_Bar.style.width = `${width}%`
}, 500);
})
// Play
function playVideo() {
play_pause.innerHTML = "pause";
play_pause.title = "Pausar";
video_player.classList.add('paused')
mainVideo.play();
}
// Pause
function pauseVideo() {
play_pause.innerHTML = "play_arrow";
play_pause.title = "Reproduzir";
video_player.classList.remove('paused')
mainVideo.pause();
}
play_pause.addEventListener('click',()=>{
const isVideoPaused = video_player.classList.contains('paused');
isVideoPaused ? pauseVideo() : playVideo();
})
mainVideo.addEventListener('play',()=>{
playVideo();
})
mainVideo.addEventListener('pause',()=>{
pauseVideo();
})
// Rewind
fast_rewind.addEventListener('click',()=>{
mainVideo.currentTime -= 10;
})
// Forward
fast_forward.addEventListener('click',()=>{
mainVideo.currentTime += 10;
})
// Total duration
mainVideo.addEventListener("loadeddata",(e)=>{
let videoDuration = e.target.duration;
let totalMin = Math.floor(videoDuration / 60);
let totalSec = Math.floor(videoDuration % 60);
// Complete with zero at beggining
totalSec < 10 ? totalSec = "0"+totalSec:totalSec;
totalMin < 10 ? totalMin = "0"+totalMin:totalMin;
totalDuration.innerHTML = `${totalMin}:${totalSec}`;
})
// Current duration
mainVideo.addEventListener('timeupdate',(e)=>{
let currentVideoTime = e.target.currentTime;
let currentMin = Math.floor(currentVideoTime / 60);
let currentSec = Math.floor(currentVideoTime % 60);
// Complete with zero at beggining
currentSec < 10 ? currentSec = "0"+currentSec:currentSec;
currentMin < 10 ? currentMin = "0"+currentMin:currentMin;
current.innerHTML = `${currentMin}:${currentSec}`;
let videoDuration = e.target.duration
// Seek bar
let progressWidth = (currentVideoTime / videoDuration) * 100;
progress_Bar.style.width = `${progressWidth}%`;
})
// Update current duration
progressArea.addEventListener('click',(e)=>{
let videoDuration = mainVideo.duration;
let progressWidthval = progressArea.clientWidth;
let ClickOffsetX = e.offsetX;
mainVideo.currentTime = (ClickOffsetX / progressWidthval) * videoDuration;
})
// Volume
function changeVolume() {
mainVideo.volume = volume_range.value / 100;
if (volume_range.value == 0) {
volume.innerHTML = "volume_off";
}else if(volume_range.value < 40){
volume.innerHTML = "volume_down";
}else{
volume.innerHTML = "volume_up";
}
}
function muteVolume() {
if (volume_range.value == 0) {
volume_range.value = 80;
mainVideo.volume = 0.8;
volume.innerHTML = "volume_up";
volume.title = "Sem áudio";
}else{
volume_range.value = 0;
mainVideo.volume = 0;
volume.innerHTML = "volume_off";
volume.title = "Reativar o som";
}
}
volume_range.addEventListener('change',()=>{
changeVolume();
})
volume.addEventListener('click',()=>{
muteVolume();
})
// Update on mouse move
progressArea.addEventListener('mousemove',(e)=>{
let progressWidthval = progressArea.clientWidth;
let x = e.offsetX;
progressAreaTime.style.setProperty('--x',`${x}px`);
progressAreaTime.style.display = "block";
let videoDuration = mainVideo.duration;
let progressTime = Math.floor((x/progressWidthval)*videoDuration);
let currentMin = Math.floor(progressTime / 60);
let currentSec = Math.floor(progressTime % 60);
// Complete with zero at beggining
currentSec < 10 ? currentSec = "0"+currentSec:currentSec;
currentMin < 10 ? currentMin = "0"+currentMin:currentMin;
progressAreaTime.innerHTML = `${currentMin}:${currentSec}`;
})
progressArea.addEventListener('mouseleave',()=>{
progressAreaTime.style.display = "none";
})
// Loop
auto_play.addEventListener('click',()=>{
auto_play.classList.toggle('active')
if(auto_play.classList.contains('active')){
auto_play.title = "A repetição automática está ativada";
}else{
auto_play.title = "A repetição automática está desativada";
}
});
mainVideo.addEventListener("ended",()=>{
if (auto_play.classList.contains('active')) {
playVideo();
}else{
play_pause.innerHTML = "replay";
play_pause.title = "Reproduzir novamente";
}
});
// Picture in picture
picture_in_picture.addEventListener('click',()=>{
mainVideo.requestPictureInPicture();
})
// Full screen
fullscreen.addEventListener('click',()=>{
if (!video_player.classList.contains('openFullScreen')) {
video_player.classList.add('openFullScreen');
fullscreen.innerHTML = "fullscreen_exit";
fullscreen.title = "Sair da tela inteira";
video_player.requestFullscreen();
}else{
video_player.classList.remove('openFullScreen');
fullscreen.innerHTML = "fullscreen";
fullscreen.title = "Tela inteira";
document.exitFullscreen();
}
});
// Settings
settingsBtn.addEventListener('click',()=>{
settings.classList.toggle('active');
settingsBtn.classList.toggle('active');
})
// Speed
playback.forEach((event)=>{
event.addEventListener('click',()=>{
removeActiveClasses();
event.classList.add('active');
let speed = event.getAttribute('data-speed');
mainVideo.playbackRate = speed;
})
})
function removeActiveClasses() {
playback.forEach(event => {
event.classList.remove('active')
});
}
// Get URL
let xhr = new XMLHttpRequest();
xhr.open("GET",vidsrc);
xhr.responseType = "arraybuffer";
xhr.onload = (e)=>{
let blob = new Blob([xhr.response]);
let url = URL.createObjectURL(blob);
mainVideo.src = url;
}
xhr.send();
// Store duration
window.addEventListener('unload',()=>{
let setDuration = localStorage.setItem('duration',`${mainVideo.currentTime}`);
let setSrc = localStorage.setItem('src',`${mainVideo.getAttribute('src')}`);
})
window.addEventListener('load',()=>{
let getDuration = localStorage.getItem('duration');
let getSrc = localStorage.getItem('src');
if (getSrc) {
mainVideo.src = getSrc;
mainVideo.currentTime = getDuration;
}
})
mainVideo.addEventListener('contextmenu',(e)=>{
e.preventDefault();
})
// Hide and show controls (mouse)
video_player.addEventListener('mouseover',()=>{
controls.classList.add('active');
})
video_player.addEventListener('mouseleave',()=>{
if (video_player.classList.contains('paused')) {
if (settingsBtn.classList.contains('active')) {
controls.classList.add('active');
}else{
controls.classList.remove('active')
}
}else{
controls.classList.add('active')
}
})
if (video_player.classList.contains('paused')) {
if (settingsBtn.classList.contains('active')) {
controls.classList.add('active');
}else{
controls.classList.remove('active')
}
}else{
controls.classList.add('active')
}
// Hide and show controls (mobile)
video_player.addEventListener('touchstart',()=>{
controls.classList.add('active');
setTimeout(() => {
controls.classList.remove('active')
}, 8000);
})
video_player.addEventListener('touchmove',()=>{
if (video_player.classList.contains('paused')) {
controls.classList.remove('active')
}else{
controls.classList.add('active')
}
})

Helper function which you can use to write the HTML skeleton once and then have it dynamically created for multiple instances
function renderVideoPlayers() {
const sources = [
'../my-video-src-1',
'../my-video-src-2',
'../my-video-src-3',
'../my-video-src-4',
]
const videoPlayers = sources.map((video) => `
<section class="videoplayer">
<div class="c-video">
<div id="video_player">
<video src="${video}" class="video"></video>
<div class="progressAreaTime">00:00</div>
<div class="controls">
<div class="progress-area">
<div class="progress-bar">
<span></span>
</div>
<div class="buffered-progress-bar"></div>
</div>
<div class="controls-list">
<div class="controls-left">
<span class="icon">
<i class="material-icons fast-rewind" title="Retroceder 10 segundos">first_page</i>
</span>
<span class="icon">
<i class="material-icons play_pause" title="Reproduzir">play_arrow</i>
</span>
<span class="icon">
<i class="material-icons fast-forward" title="Avançar 10 segundos">last_page</i>
</span>
<span class="icon">
<i class="material-icons volume" title="Sem áudio">volume_up</i>
<input type="range" min="0" max="100" class="volume_range">
</span>
<div class="timer">
<span class="current">00:00</span> / <span class="duration">0:00</span>
</div>
</div>
<div class="controls-right">
<span class="icon">
<i class="material-icons auto-play" title="A repetição automática está desativada"></i>
</span>
<span class="icon">
<i class="material-icons settingsBtn" title="Detalhes">settings</i>
</span>
<span class="icon">
<i class="material-icons picture_in_picture" title="Miniplayer">picture_in_picture_alt</i>
</span>
<span class="icon">
<i class="material-icons fullscreen" title="Tela inteira">fullscreen</i>
</span>
</div>
</div>
</div>
<div id="settings">
<div class="playback">
<span>Velocidade da Reprodução</span>
<ul>
<li data-speed="0.25">0.25</li>
<li data-speed="0.5">0.5</li>
<li data-speed="0.75">0.75</li>
<li data-speed="1" class="active">Normal</li>
<li data-speed="1.25">1.25</li>
<li data-speed="1.5">1.5</li>
<li data-speed="1.75">1.75</li>
<li data-speed="2">2</li>
</ul>
</div>
</div>
</div>
</div>
`)
// get an element already on the page add the rendered
// html for each video into that section.
const container = document.getElementById('container')
container.innerHTML = videoPlayers.join("")
}
// call this function when you want it to be displayed
renderVideoPlayers()
<html>
<head>
</head>
<body>
<div id="container">
</div>
</body>
</html>
You will also need to do the same with Javascript as well as ensure that there aren't multiple instance of the same id. This shouldn't be too hard as you can switch similiar styles to class and make the id's something like video-1, video-2, video-3, etc.
A couple notes
sources: this is an array of all video urls you wish to display on the page.
sources.map: will iterate through the array and interpolate a string with the video player HTML and video source
videoPlayers: is now an array of HTML markup
container: will be a parent element on the page where you wish to append all the HTML markup

I HAVE FOUND THE SOLUTION
For anyone in the future seeking for the same solution, I was able to make it work by first selecting every videoplayer div:
const videoContainers = document.querySelectorAll(".video-container")
Then using the .forEach() function so that the code will generate a button for every individual videoplayer:
videoContainers.forEach((container) => {
let playPauseBtn = container.querySelector(".play-pause-btn");
let theaterBtn = container.querySelector(".theater-btn");
let fullScreenBtn = container.querySelector(".full-screen-btn");
...
// The entire code for one videoplayer
}
You can reference "container" for the individual videoplayer or "document" for every videoplayer at once. It just works like magic!

Related

Javascript can not snap val of sensor's data send from local nodemcu to firebase webapp. use append but keep spamming

Hi im doing an project which using nodemcu to collect temperature and relay data state to firebase, this part already been done
DrumStatus:"Stuck"
Relay1Status:"1"
Relay2Status:"1"
Relay3Status:"1"
TemperatureStatus:"27.500"
WaterStatus:"Dirty"
the thing is my snap.value code for relay1 2 3 is good but when i snap the value of TemperatureStatus, DrumStatus & WaterStatus it didn't display on the web app
Here is my code for html page
<script src="scripts/index.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="topnav">
<h1>Sensor Readings App <i class="fas fa-clipboard-list"></i></h1>
</div>
<p></p>
<div class="cards">
<!--TEMPERATURE-->
<div class="card">
<p>
<i class="fas fa-thermometer-half" style="color: #fa5102"></i>
TEMPERATURE
</p>
<p>
<span class="reading"><span id="temp"></span> °C</span>
</p>
</div>
<!--RELAY 1-->
<div class="card">
<p>
<i class="fas fa-sync-alt" style="color: #6c2894"></i>
DRUM
</p>
<p>
<span class="reading"><span id="drumstatus"></span> </span>
</p>
</div>
<!--TANK SIZE-->
<div class="card">
<p>
<i class="fas fa-tint" style="color: #00add6"></i>
WATER LEVEL
</p>
<p>
<span class="reading"><span id="waterstatus"></span> </span>
</p>
</div>
<!-- ADRF POWER-->
<div class="card">
<p>
<i class="fas fa-power-off" style="color: #1dbb32"></i>
SYSTEM POWER
</p>
<p>
<span class="reading"><span id="systempower"></span>OFF - ON</span>
</p>
<p>
<div class="progress">
<div class= "toggle-btn1" id="unact1">
<div class= "inner-circle">
</div>
</div>
<div class= "toggle-btn1 active" id="act1" >
<div class= "inner-circle">
</div>
</div>
</div>
</p>
</div>
<!-- CLEAN DRUM-->
<div class="card">
<p>
<i class="fas fa-shower" style="color: #26adcf"></i>
CLEAN DRUM
</p>
<p>
<span class="reading"><span id="cleandrum"></span>OFF - ON</span>
</p>
<p>
<div class="progress">
<div class= "toggle-btn2" id="unact2">
<div class= "inner-circle">
</div>
</div>
<div class= "toggle-btn2 active" id="act2" >
<div class= "inner-circle">
</div>
</div>
</div>
</p>
</div>
<!-- WATER PUMP-->
<div class="card">
<p>
<i class="fas fa-faucet" style="color: #460ec9"></i>
WATER PUMP
</p>
<p>
<span class="reading"><span id="waterpump"></span>ON - OFF</span>
</p>
<p>
<div class="progress">
<div class= "toggle-btn3" id="unact3">
<div class= "inner-circle">
</div>
</div>
<div class= "toggle-btn3 active" id="act3" >
<div class= "inner-circle">
</div>
</div>
</div>
</p>
</div>
here is the code for script.js
firebase.initializeApp(firebaseConfig);
// Elements for sensor readings
//const tempElement = document.getElementById("temp");
$(document).ready(function () {
var database = firebase.database();
var Relay1Status;
var Relay2Status;
var Relay3Status;
//var Relay4Status;
var TemperatureStatus;
var DrumStatus;
var WaterStatus;
//var tempElement = $("#temp");
//var dbRefTemp = firebase.database().ref().child("temperature");
//document.getElementById("temperature").style.display = "block";
// Update page with new readings
/*
dbRefTemp.on("value", (snap) => {
tempElement.innerText = snap.val();
});
*/
//var temp_val = childSnapshot.val().temperature;
//$("#temp").append(temp_val);
database.ref().on("value", function (snap) {
Relay1Status = snap.val().Relay1Status;
Relay2Status = snap.val().Relay2Status;
Relay3Status = snap.val().Relay3Status;
//Relay4Status = snap.val().Relay4Status;
TemperatureStatus = snap.val().TemperatureStatus;
$("#temp").append(TemperatureStatus);
WaterStatus = snap.val().WaterStatus;
$("#waterstatus").append(WaterStatus);
DrumStatus = snap.val().DrumStatus;
$("#drumstatus").append(DrumStatus);
if (Relay1Status == "1") {
document.getElementById("unact1").style.display = "none";
document.getElementById("act1").style.display = "block";
} else {
document.getElementById("unact1").style.display = "block";
document.getElementById("act1").style.display = "none";
}
if (Relay2Status == "1") {
document.getElementById("unact2").style.display = "none";
document.getElementById("act2").style.display = "block";
} else {
document.getElementById("unact2").style.display = "block";
document.getElementById("act2").style.display = "none";
}
if (Relay3Status == "1") {
document.getElementById("unact3").style.display = "none";
document.getElementById("act3").style.display = "block";
} else {
document.getElementById("unact3").style.display = "block";
document.getElementById("act3").style.display = "none";
}
});
$(".toggle-btn1").click(function () {
var firebaseRef1 = firebase.database().ref().child("Relay1Status");
if (Relay1Status == "1") {
firebaseRef1.set("0");
Relay1Status = "0";
} else {
firebaseRef1.set("1");
Relay1Status = "1";
}
});
$(".toggle-btn2").click(function () {
var firebaseRef2 = firebase.database().ref().child("Relay2Status");
if (Relay2Status == "1") {
firebaseRef2.set("0");
Relay2Status = "0";
} else {
firebaseRef2.set("1");
Relay2Status = "1";
}
});
$(".toggle-btn3").click(function () {
var firebaseRef3 = firebase.database().ref().child("Relay3Status");
if (Relay3Status == "1") {
firebaseRef3.set("0");
Relay3Status = "0";
} else {
firebaseRef3.set("1");
Relay3Status = "1";
}
});
});
Im currently using append to update but it keep spamming more value anytime a new value appears. My question is how to snap the value of those status and display like Relay 1 2 3 or append and update the those status continously without spamming it ?
Best regards.
My full source code can be found at https://github.com/KyleTo132/Autonomous-Rotary-Drum-Filter in Webcode dir
The webapp is currently deploy at domain: https://adrf-relay-control.firebaseapp.com/

Why does the addEventListener property does not work on a dynamic HTMLcollection object?

I am working on a chrome extension and trying to add an event listener to a getElementsByClassName variable, in which elements are added dynamically using template strings.
I have tried a lot of changes in the code, but the code doesn't work.
The code is supposed to delete the targeted element from the array "recipeList", storing the array in localStorage and then render the updated array "recipeList" using template string to the HTML code again.
DELETE BUTTON Function
let delBtn = document.getElementsByClassName("del-btn");
for(let i = 0; i < delBtn.length; i++) {
delBtn[i].addEventListener("click", function() {
recipeList.splice(i, 1);
localStorage.setItem("recipeList", JSON.stringify(recipeList));
recipeList = JSON.parse(localStorage.getItem("recipeList"));
render(recipeList);
if(!recipeList.length) {
tabBtn.style.width = "100%";
delAllBtn.style.display = "none";
}
});
}
RENDER CODE
function render(list) {
let recipeURL = "";
for(let i = 0; i < list.length; i++) {
recipeURL += `
<div class="mb-2 row">
<div class="col-1 num-btn">
${i+1}
</div>
<div class="col-10">
<div class="recipe-url">
<a target="_blank" href="${list[i]}">
${list[i]}
</a>
</div>
</div>
<div class="col-1 del-btn">
<a href="#">
<i class="bi bi-trash-fill"></i>
</a>
</div>
</div>
`
}
urlList.innerHTML = recipeURL;
console.log(delBtn);
}
When you render, you create new .del-btn which are not included in your first let delBtn = document.getElementsByClassName("del-btn");.
Each time you create new .del-btn, you should also add a new listener.
function render(list) {
let recipeURL = "";
for(let i = 0; i < list.length; i++) {
recipeURL += `
<div class="mb-2 row">
<div class="col-1 num-btn">
${i+1}
</div>
<div class="col-10">
<div class="recipe-url">
<a target="_blank" href="${list[i]}">
${list[i]}
</a>
</div>
</div>
<div class="col-1 del-btn">
<a href="#">
<i class="bi bi-trash-fill"></i>
</a>
</div>
</div>
`
}
urlList.innerHTML = recipeURL;
console.log(delBtn);
Array.from(urlList.querySelectorAll('.del-btn')).forEach((btn, i) => {
btn.addEventListener('click', () => console.log('.del-btn index: ' + i))
})
}
}

Progress bar for multiple audio player

I am working on creating a player in a page. In the page there will be multiple players. So progress bar needs to be shown for the current player that is being played. But the issue is when i play the player the progress bar is rendered in some other place because of multiple id's of the progress bar div. How can i target the progress div of the current player that is being played.
I am using javascript to render the progress bar.
Below is the HTML code: There will be multiple html blocks like below in different tabs of the page.
<div class="prabhata-play audio-playlist ">
<div class="d-flex justify-content-between">
<ul class="d-flex list-inline">
<li>
<button class="togglePlay" onclick="togglePlay('1445')" id="toogle1445">
<img src="./play-round.svg" alt="play" class="play-img" id="playImage">
</button>
</li>
<li>
<p class="title">Contentment in professional life</p>
<p class="auth-title">Swami Bhoomananda Tirtha</p>
</li>
</ul>
<div class="d-inline text-end">
<ul class="list-inline d-flex icons-sec">
<li><img src="./video-list.svg" alt="video-list"></li>
<li><img src="./heart.svg" alt="heart"></li>
<li><img src="./download-icon.svg" alt="download"></li>
</ul>
<span class="time-duration">0:39</span>
</div>
</div>
<div class="progress" id="progress1445"></div>
<audio id="audio1445" class="audio-link" src="./AkashavallepaVidooragoham.mp3"></audio>
Javascript Code :
function togglePlay (count, e) {
e = e || window.event;
var btn = e.target;
var timer;
var percent = 0;
var audio1 = document.getElementById("audio"+count);
audio1.addEventListener("playing", function(_event) {
var duration = _event.target.duration;
advance(duration, audio1);
});
audio1.addEventListener("pause", function(_event) {
clearTimeout(timer);
});
var advance = function(duration, element) {
var progress = document.getElementById("progress"+count);
increment = 10/duration
percent = Math.min(increment * element.currentTime * 10, 100);
progress.style.width = percent+'%'
startTimer(duration, element);
}
var startTimer = function(duration, element){
if(percent < 100) {
timer = setTimeout(function (){advance(duration, element)}, 100);
}
}
if (!audio1.paused) {
btn.classList.remove('active');
audio1.pause();
isPlaying = false;
} else {
btn.classList.add('active');
audio1.play();
isPlaying = true;
}
}
Your question is a bit confusing, but I'm assuming the issue is from there being multiple divs with the same id on the page. To fix this, try using document.querySelector() Documentation Here
For example, each player could be like this:
Html:
<div class="prabhata-play audio-playlist " id="player1">
<div class="progress" id="progress1445"></div>
<audio id="audio1445" class="audio-link" src="http://nat.verifinow.in/wp-content/uploads/2021/06/AkashavallepaVidooragoham.mp3"></audio>
</div>
Then in the JS, you could access the progress div using:
document.querySelector("div#player1 > div#progress1445");

How to change the value of a variable depending on a function?

I'm trying to build a small program that shows how long it takes a certain vehicle to orbit a planet. Eg a car at 100mph orbits earth (7917 miles) in 79.17 hours and etc.
To display vehicles I've used icons and to display planets I've used img. I can give values to icons (in this case I've given them their speed values as in mph) But for images I can't give values for some reason which I wanted to use as the radius of the planets.
Currently I have
let icons = [...document.querySelectorAll('.icon-container .fa')];
let answerContainer = document.getElementById("answer-container");
let answerDiv = document.getElementById("answer-div");
let planetImgs = [...document.querySelectorAll(".planet-container img")];
//Function to slide icons User clicks right/left to show next/previous vehicle icon
function adjustActive (adjustment) {
var current = icons.find(it => it.id === 'active');
var currentIndex = icons.indexOf(current);
var nextIndex = (currentIndex + adjustment) % icons.length;
if (nextIndex < 0) nextIndex = icons.length - 1;
current.removeAttribute('id');
icons[nextIndex].id = 'active';
// Action to find Orbital Period
let planet = 7917.5; **(I WANT THIS TO CHANGE DEPENDING ON THE FUNCTION BELOW)**
let nextElement = document.getElementById("active");
let nextElements = nextElement.getAttribute("value")
let orbitalPeriod = planet / nextElements;
answerDiv.innerHTML = orbitalPeriod.toFixed(2);
}
// Function to slide planets - User clicks right/left to show next/previous planet
function adjustActivePlanet (adjustment) {
var current = planetImgs.find(it => it.id === 'active-planet');
var currentIndex = planetImgs.indexOf(current);
var nextIndex = (currentIndex + adjustment) % icons.length;
if (nextIndex < 0) nextIndex = planetImgs.length - 1;
current.removeAttribute('id');
planetImgs[nextIndex].id = 'active-planet';
} // The value of this function needs to be used in the function above for let "planets"
//Arrow Buttons
document.querySelector('#left-arrow').addEventListener('click', e => adjustActive(-1));
document.querySelector('#right-arrow').addEventListener('click', e => adjustActive(1));
document.querySelector('#left-arrow-planet').addEventListener('click', e => adjustActivePlanet(-1));
document.querySelector('#right-arrow-planet').addEventListener('click', e => adjustActivePlanet(1));
<div class="main-container">
<div class="object-container">
<div class="icon-container">
<i class="fa fa-car" id="active" value="100"></i>
<i class="fa fa-bicycle" value="25"></i>
<i class="fa fa-plane" value="500"></i>
<i class="fa fa-ship" value="10"></i>
<i class="fa fa-fighter-jet" value="1000"></i>
<i class="fa fa-space-shuttle" value="3000"></i>
</div>
<div class="arrow-buttons">
</div>
</div>
<div class="answer-container" id="answer-container">
<div id="answer-div"></div>
<h3>Hours to orbit</h3>
</div>
<div class="planet-container">
<img src="images/earth planet.png" alt="" id="active-planet">
<img src="images/saturn planet.png" alt="" class="planet">
<img src="images/neptune planet.png" alt="" class="planet">
<img src="images/mercury planet.png" alt="" class="planet">
<img src="images/sun.png" alt="" class="planet">
<img src="images/mars planet.png" alt="" class="planet">
<div class="arrow-buttons">
</div>
</div>
</div>
</div>
As you can see above, the let planet = 7917.5 is earths radius, so the answer container will output the value of "planet" / the value of the active icons "active". How can I make the value of "planet" change depending on which planet is currently active ("active-planet"). For example neptune is 30,000 so I want the "planet" value to be 30,000 / the value of the icon (car 100mph).
Any help will be greatly appreciated.
Instead of using the value attribute you can use a data-<name> attribute.
ie.
<img src="images/neptune planet.png" alt="" class="planet" data-radius="30000">
Then you can access this value with:
document.querySelector('#active-planet').dataset.radius
EDIT: I've added a runnable snippet example to show how I would approach your program.
I find it helps to break down the related logic into individual functions, particularly when I want to use the same logic in multiple places (in each button listener).
In this case ive created a setActiveClasses() function and renderOrbitDuration() function.
We keep track of the active vehicle and planet using an index (0, 1, 2, etc...) for each (activeVehicleIndex and activePlanetIndex).
The buttons simply increment and decrement the relevant index and then the setActiveClasses() function and renderOrbitDuration() function use this index to set the right active classes and render the orbital duration.
Read through and run the snippet below.
let activeVehicleIndex = 0
let activePlanetIndex = 0
const vehicleElements = document.querySelectorAll('.vehicles i')
const planetElements = document.querySelectorAll('.planets img')
function setActiveClasses () {
// Clear old active classes
[...vehicleElements, ...planetElements].forEach(el => {
el.classList.remove('active')
})
// Add new active classes
vehicleElements[activeVehicleIndex].classList.add('active')
planetElements[activePlanetIndex].classList.add('active')
}
function renderOrbitDuration () {
activeVehicleEl = vehicleElements[activeVehicleIndex]
activePlanetEl = planetElements[activePlanetIndex]
const html = `
Vehicle Name: ${activeVehicleEl.dataset.name}<br>
Vehicle Speed: ${activeVehicleEl.dataset.speed}<br>
Planet Name: ${activePlanetEl.dataset.name}<br>
Planet Radius: ${activePlanetEl.dataset.radius}<br>
Orbital Period: ${activePlanetEl.dataset.radius / activeVehicleEl.dataset.speed}
`
document.querySelector('.output').innerHTML = html
}
// Previous/Next Button Listeners
document.querySelector('.vehicles .prev').addEventListener('click', () => {
activeVehicleIndex-- // Decrement activeVehicleIndex
if (activeVehicleIndex < 0) { activeVehicleIndex = 0 } // Dont allow negative values
setActiveClasses()
renderOrbitDuration()
})
document.querySelector('.vehicles .next').addEventListener('click', () => {
activeVehicleIndex++ // Increment activeVehicleIndex
if (activeVehicleIndex > vehicleElements.length - 1) { activeVehicleIndex = vehicleElements.length - 1 } // Dont allow values greater than number of vehicles
setActiveClasses()
renderOrbitDuration()
})
document.querySelector('.planets .prev').addEventListener('click', () => {
activePlanetIndex-- // Decrement activePlanetIndex
if (activePlanetIndex < 0) { activePlanetIndex = 0 } // Dont allow negative values
setActiveClasses()
renderOrbitDuration()
})
document.querySelector('.planets .next').addEventListener('click', () => {
activePlanetIndex++ // Increment activePlanetIndex
if (activePlanetIndex > planetElements.length - 1) { activePlanetIndex = planetElements.length - 1 } // Dont allow values greater than number of planets
setActiveClasses()
renderOrbitDuration()
})
// Run both of these once on page load to set initial classes and render values
setActiveClasses()
renderOrbitDuration()
.vehicles, .planets {
margin-bottom: 1em;
}
.vehicles .active {
color: red;
}
.planets .active {
border: 1px solid red;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" rel="stylesheet"/>
<!-- Vehicles -->
<div class="vehicles">
<i class="fa fa-car" data-name="car" data-speed="100"></i>
<i class="fa fa-bicycle" data-name="bike" data-speed="25"></i>
<i class="fa fa-plane" data-name="plane" data-speed="500"></i>
<i class="fa fa-ship" data-name="ship" data-speed="10"></i>
<i class="fa fa-fighter-jet" data-name="fighter jet" data-speed="1000"></i>
<i class="fa fa-space-shuttle" data-name="space shuttle" data-speed="3000"></i>
<div>
<button class="prev">Prev</button>
<button class="next">Next</button>
</div>
</div>
<!-- Planets -->
<div class="planets">
<img src="http://via.placeholder.com/50" data-name="earth" data-radius="6000"/>
<img src="http://via.placeholder.com/50" data-name="saturn" data-radius="60000"/>
<img src="http://via.placeholder.com/50" data-name="neptune" data-radius="25000"/>
<img src="http://via.placeholder.com/50" data-name="mercury" data-radius="2500"/>
<img src="http://via.placeholder.com/50" data-name="sun" data-radius="700000"/>
<img src="http://via.placeholder.com/50" data-name="mars" data-radius="3500"/>
<div>
<button class="prev">Prev</button>
<button class="next">Next</button>
</div>
</div>
<!-- Output -->
<div class="output"></div>

How can I make my Slideshow Indicators change their style with my current code?

I have had an issue with placing slideshows in my website. I require more than one slideshow on the same page which has led to multiple problems with the scrolling and such. I finally came across a solution which works almost perfectly however, the indicators do not change color to reflect the current slide.
var w3 = {};
w3.slideshow = function (sel, ms, func) {
var i, ss, x = w3.getElements(sel), l = x.length;
ss = {};
ss.current = 1;
ss.x = x;
ss.ondisplaychange = func;
if (!isNaN(ms) || ms == 0) {
ss.milliseconds = ms;
} else {
ss.milliseconds = 1000;
}
ss.start = function() {
ss.display(ss.current)
if (ss.ondisplaychange) {ss.ondisplaychange();}
if (ss.milliseconds > 0) {
window.clearTimeout(ss.timeout);
ss.timeout = window.setTimeout(ss.next, ss.milliseconds);
}
};
ss.next = function() {
ss.current += 1;
if (ss.current > ss.x.length) {ss.current = 1;}
ss.start();
};
ss.previous = function() {
ss.current -= 1;
if (ss.current < 1) {ss.current = ss.x.length;}
ss.start();
};
ss.display = function (n) {
w3.styleElements(ss.x, "display", "none");
w3.styleElement(ss.x[n - 1], "display", "block");
}
ss.start();
return ss;
};
<html>
<script src="w3.js"></script>
<body>
<div id="2" class="w3-row-padding w3-light-grey w3-padding-64 w3-container">
<div class="w3-content">
<div class="w3-content w3-display-container w3-center">
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<!-- Second slide App Development -->
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<!-- Third slide App Development -->
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<!-- Fourth slide App Development -->
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<div class="w3-center w3-container w3-section w3-large w3-text-grey" style="width:100%">
<span class="w3-left w3-hover-text-blue fa fa-arrow-left" onclick="myShow2 .previous()"></span>
<span class="w3-right w3-hover-text-blue fa fa-arrow-right" onclick="myShow2 .next()"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(1)"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(2)"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(3)"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(4)"></span>
</div>
</div>
</div>
<script> myShow2 = w3.slideshow(".Slide2", 0); </script>
</div>
</body>
</html>
So the code works well and does what I want except I'm not sure how to make the circle indicators change to blue to reflect the current slide. I have tried completely different approaches except this is the only one that allows multiple slideshows on the same page. Could some please explain to me how I would go about making the circles stay blue when clicked and revert when another is clicked?
I have found a solution to my problem. First I added an extra variable to call a function <script> myShow4 = w3.slideshow(".Slide4", 0, "demo4"); </script>
the "demo4" will be used to find the indicator dots. <span class="fa fa-circle demo4 w3-hover-text-blue w3-transparent" onclick="myShow4 .display(4)"></span>each indicator has the specific class.
`ss.display = function (n) {
ss.current = n;
w3.styleElements(ss.x, "display", "none");
w3.styleElement(ss.x[n - 1], "display", "block");
ss.indicator(demo);
}
ss.indicator = function(n) {
var dots = document.getElementsByClassName(n);
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" w3-text-blue", "");
}
x[ss.current-1].style.display = "block";
dots[ss.current-1].className += " w3-text-blue";
}`
This is the new code in the JS file. on click the display function is called and I edited the function to also call the indicator function which changes the current slide relevant dot to blue while changing the rest to nothing or how they were before. This solution worked for me, adding another function within the called function.

Categories