javascripthtmlcsshtml5-audiowebvtt

Oncuechange event trigger a fade-in/fade-out animation inside the P tag of html


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>
    


Solution

  • 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;
    }