Click here to Skip to main content
16,022,060 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am making a competition card and i use a countdown in that but i can see flicker in days

What I have tried:

JavaScript
function calculateTimeRemaining(endDate) {
            const now = new Date();
            const timeRemaining = endDate - now;
            const days = Math.floor(timeRemaining / (1000 * 60 * 60 * 24));
            const hours = Math.floor((timeRemaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((timeRemaining % (1000 * 60)) / 1000);
            return {
                days,
                hours,
                minutes,
                seconds
            };
        }

        function startCountdown(element, endDate) {
            function updateCountdown() {
                const {
                    days,
                    hours,
                    minutes,
                    seconds
                } = calculateTimeRemaining(endDate);
                element.innerHTML = `
                <div class="m-table__itm"><span>${days}</span><span>DAYS</span></div>
                <div class="m-table__itm"><span>${hours}</span><span>HRS</span></div>
                <div class="m-table__itm"><span>${minutes}</span><span>MIN</span></div>
                <div class="m-table__itm"><span>${seconds}</span><span>SEC</span></div>
            `;
                if (endDate > new Date()) {
                    setTimeout(updateCountdown, 1000);
                } else {
                    element.innerHTML = '<div class="m-table__itm"><span>-</span><span>DAYS</span></div><div class="m-table__itm"><span>-</span><span>HRS</span></div><div class="m-table__itm"><span>-</span><span>MIN</span></div><div class="m-table__itm"><span>-</span><span>SEC</span></div>';
                }
            }
            updateCountdown();
        }


      // Start countdown for each card
            startCountdown(document.getElementById(`countdown-${index}`), new Date(data.endDate));
        });

        // Initial countdowns
        const currentEndDate = new Date(currentDate.getFullYear(), currentMonth + 1, 0, 23, 59, 59);
        const upcomingEndDate = new Date(currentDate.getFullYear(), currentMonth + 2, 0, 23, 59, 59);

        if (currentDay <= 7) {
            startCountdown(document.getElementById('countdown-0'), currentTimerEnd);
            startCountdown(document.getElementById('countdown-1'), currentTimerEnd);
        } else {
            startCountdown(document.getElementById('countdown-0'), currentTimerEnd);
            startCountdown(document.getElementById('countdown-1'), upcomingTimerEnd);
        }
Posted
Updated 5-Oct-24 2:39am
v2

1 solution

The flickering of the days part in your code is likely caused by the frequent updates and recalculations you are making. I can think of a few reasons based on your code why this might be happening.

Your 'setTimeout' function does not guarantee exact timing which might lead to slight variations when your countdown is updated.
When you create a new Date object in your 'calculateTimeRemaining' there might be small inconsistencies.
When you use the 'Math.floor' function it can cause jumps when the remaining time is close to a day boundary/end.

See my code below as well as the working fiddle at Eliminate date flickering[^] where I used 'requestAnimationFrame' instead of your 'setTimeout' for smoother updates.

I also created a single 'Date' object for the current time and pass it to the 'calculateTimeRemaining' function.

The code will also calculate days with more precision to avoid rounding issues which leads to flickering.

JavaScript
function calculateTimeRemaining(endDate, now) {
    const timeRemaining = endDate - now;
    const days = timeRemaining / (1000 * 60 * 60 * 24);
    const hours = (timeRemaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
    const minutes = (timeRemaining % (1000 * 60 * 60)) / (1000 * 60);
    const seconds = (timeRemaining % (1000 * 60)) / 1000;
    return {
        days: Math.floor(days),
        hours: Math.floor(hours),
        minutes: Math.floor(minutes),
        seconds: Math.floor(seconds)
    };
}

function startCountdown(element, endDate) {
    let animationFrameId;

    function updateCountdown() {
        const now = new Date();
        const { days, hours, minutes, seconds } = calculateTimeRemaining(endDate, now);
        element.innerHTML = `
            <div class="m-table__itm"><span>${days}</span><span>DAYS</span></div>
            <div class="m-table__itm"><span>${hours}</span><span>HRS</span></div>
            <div class="m-table__itm"><span>${minutes}</span><span>MIN</span></div>
            <div class="m-table__itm"><span>${seconds}</span><span>SEC</span></div>
        `;
        if (endDate > now) {
            animationFrameId = requestAnimationFrame(updateCountdown);
        } else {
            element.innerHTML = '<div class="m-table__itm"><span>-</span><span>DAYS</span></div><div class="m-table__itm"><span>-</span><span>HRS</span></div><div class="m-table__itm"><span>-</span><span>MIN</span></div><div class="m-table__itm"><span>-</span><span>SEC</span></div>';
        }
    }

    updateCountdown();

    //Return a function to cancel the animation frame when you want to...
    return () => {
        if (animationFrameId) {
            cancelAnimationFrame(animationFrameId);
        }
    };
}

//This stays the same as you had it...
//Start your countdown for each card...
startCountdown(document.getElementById(`countdown-${index}`), new Date(data.endDate));

//Initial countdowns...
const currentEndDate = new Date(currentDate.getFullYear(), currentMonth + 1, 0, 23, 59, 59);
const upcomingEndDate = new Date(currentDate.getFullYear(), currentMonth + 2, 0, 23, 59, 59);

if (currentDay <= 7) {
    startCountdown(document.getElementById('countdown-0'), currentTimerEnd);
    startCountdown(document.getElementById('countdown-1'), currentTimerEnd);
} else {
    startCountdown(document.getElementById('countdown-0'), currentTimerEnd);
    startCountdown(document.getElementById('countdown-1'), upcomingTimerEnd);
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900