I'm fairly new to web development, just started to learn the javascript.. So beside learning I'm trying to build a web page where the lyrics will be shown inside a p tag, which is synced with an audio file. The subtitle source is given by vet file extension, and with the help of javascript "cuechange" event I'm trying to inject fat text inside that p tag. Till now everything is working fine. But one more thing I wanna add, that is I want to have a fade-in/fadeout effect animation on cue change event listener inside my p tag, means for each sentence of the lyrics I want a fade-in/fadeout animation before and after. I tried to add css animation directly on p element, but that's not really firing it with an event listener. Can anyone help me out about this?
The github link is given below: https://github.com/beatzonic/Audio-Lyrics-Subtitle
document.getElementById('my_audio').textTracks[0].addEventListener('cuechange', function() {
document.getElementById('lyric').innerText = this.activeCues[0].text;
});
body{
margin: 0;
padding: 0;
}
#lyrics_container{
width: 100%;
height: auto;
padding: 30px;
box-sizing: border-box;
}
p{
font-size: 2em;
color: red;
font-weight: 600;
}
@keyframes fadein{
0% {
opacity:0;
}
100% {
opacity:1;
}
}
<div id="lyrics_container">
<audio id="my_audio" controls>
<source src="https://github.com/beatzonic/Audio-Lyrics-Subtitle/raw/master/in_case_you_didnt_know.mp3" type="audio/mpeg">
<track id="sub" kind="subtitles" label="English subtitles" src="https://raw.githubusercontent.com/beatzonic/Audio-Lyrics-Subtitle/master/in_case_you_didnt_know.txt.vtt" srclang="en" default>
Your browser does not support the audio tag.
</audio>
<p id="lyric" class="lyrics-class"></p>
</div>
You could write a function which adds a class now and removes the class after a given amount of time. Check out this example down here. It adds a transition
property to a given element and adds the is-animating
class to it. Then after half of the duration
has passed it will change the content
and remove the is-animating
class again. Then after the animations have been completed, remove the transition
property as well.
This function will return another function to make use of a closure. This ensures that when you try to animate the text before the previous animation is finished it will first cancel the previous animation before starting the new one. Otherwise you would get overlapping transitions.
function buildAnimator(element, duration) {
let timeouts = [];
return function(content) {
if (timeouts.length > 0) {
for (const timeout of timeouts) {
clearTimeout(timeout);
}
timeouts.length = 0;
}
const halfDuration = duration / 2;
element.style.transition = `opacity ${halfDuration}ms ease-in-out`;
element.classList.add('is-animating');
const firstTimeout = setTimeout(() => {
element.textContent = content;
element.classList.remove('is-animating');
}, halfDuration);
const secondTimeout = setTimeout(() => {
element.style.transition = '';
currentTimeout = null;
}, duration);
timeouts.push(firstTimeout, secondTimeout);
}
}
Now build your animateLyrics
function by calling the buildAnimator
function above with the element that you want to animate and the duration of the total animation, so that is fade in and fade out combined.
Then add it in your cuechange
event handler. Pass the newly updated text of the cue to the animateLyrics
function to change the textContent
property of the element you want to animate.
const textTrack = document.getElementById('sub');
const lyric = document.getElementById('lyric');
const animateLyrics = buildAnimator(lyric, 500);
textTrack.addEventListener('cuechange', function(event) {
animateLyrics(event.target.activeCues[0].text);
});
And in CSS, tell the browser what it should transition to when the class is added. For example:
#lyric.is-animating {
opacity: 0;
}