refactor: better lyric scroll with requestAnimationFrame algo
This commit is contained in:
parent
03a6952287
commit
7b2e35dab5
2 changed files with 42 additions and 20 deletions
|
|
@ -13,6 +13,7 @@ document.addEventListener('alpine:init', () => {
|
|||
isPlaying: false,
|
||||
countdown: 180,
|
||||
isDownloadReady: false,
|
||||
scrollAnimationId: null,
|
||||
|
||||
async init() {
|
||||
this.sessionId = this.getSessionId();
|
||||
|
|
@ -178,25 +179,41 @@ document.addEventListener('alpine:init', () => {
|
|||
}, 100);
|
||||
},
|
||||
|
||||
updateLyricsScroll() {
|
||||
const player = document.getElementById('audio-player');
|
||||
initScrollLogic(player) {
|
||||
const container = document.getElementById('lyrics-container');
|
||||
|
||||
const update = () => {
|
||||
if (!player.duration || player.duration === Infinity || !container) {
|
||||
this.scrollAnimationId = requestAnimationFrame(update);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player || !container || !player.duration || player.duration === Infinity) {
|
||||
return;
|
||||
}
|
||||
const maxScroll = container.scrollHeight - container.clientHeight;
|
||||
const progress = player.currentTime / player.duration;
|
||||
|
||||
// We use direct assignment for performance within the rAF loop
|
||||
container.scrollTop = progress * maxScroll;
|
||||
|
||||
// Calculate how far through the song we are (0 to 1)
|
||||
const playbackPercentage = player.currentTime / player.duration;
|
||||
if (!player.paused) {
|
||||
this.scrollAnimationId = requestAnimationFrame(update);
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate the total scrollable area
|
||||
// scrollHeight (total content) - clientHeight (visible area)
|
||||
const maxScroll = container.scrollHeight - container.clientHeight;
|
||||
player.addEventListener('play', () => {
|
||||
cancelAnimationFrame(this.scrollAnimationId);
|
||||
update();
|
||||
});
|
||||
|
||||
// Set the scroll position
|
||||
container.scrollTo({
|
||||
top: maxScroll * playbackPercentage,
|
||||
behavior: 'smooth' // Gives it a nice fluid feel
|
||||
player.addEventListener('pause', () => {
|
||||
cancelAnimationFrame(this.scrollAnimationId);
|
||||
});
|
||||
|
||||
player.addEventListener('seeking', () => {
|
||||
// Snap the scroll immediately when the user drags the seek bar
|
||||
if (player.duration && player.duration !== Infinity) {
|
||||
const maxScroll = container.scrollHeight - container.clientHeight;
|
||||
container.scrollTop = (player.currentTime / player.duration) * maxScroll;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
17
result.php
17
result.php
|
|
@ -40,10 +40,9 @@
|
|||
id="audio-player"
|
||||
:src="$store.songApp.audioUrl"
|
||||
preload="metadata"
|
||||
x-init="$store.songApp.initScrollLogic($el)"
|
||||
@play="$store.songApp.isPlaying = true"
|
||||
@pause="$store.songApp.isPlaying = false"
|
||||
@timeupdate="$store.songApp.updateLyricsScroll()"
|
||||
@loadedmetadata="$store.songApp.updateLyricsScroll()"
|
||||
>
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
|
|
@ -59,10 +58,16 @@
|
|||
|
||||
<div
|
||||
class="song-lyrics"
|
||||
id="lyrics-container"
|
||||
x-show="$store.songApp.lyrics"
|
||||
x-text="$store.songApp.lyrics"
|
||||
></div>
|
||||
id="lyrics-container"
|
||||
style="overflow: hidden; position: relative;"
|
||||
x-show="$store.songApp.lyrics"
|
||||
>
|
||||
<div
|
||||
id="lyrics-content"
|
||||
style="transition: transform 0.4s linear; will-change: transform;"
|
||||
x-text="$store.songApp.lyrics">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="share-container">
|
||||
<div class="share-title">Share the love.</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue