Agility Test Timer

Agility Test Timer

00:00.00

Results

Press 'Lap' to record times.

Press \'Lap\' to record times.

'; updateButtonStates(); }; /** * Records the current time as a lap without stopping the timer. */ window.recordLap = function() { if (elapsedTime === 0) return; // Don't record if timer hasn't started laps.push(elapsedTime); displayLaps(); }; // --- UI UPDATE FUNCTIONS --- /** * The main loop called by setInterval to update the timer. */ function updateTimer() { elapsedTime = Date.now() - startTime; updateTimerDisplay(); } /** * Formats the elapsed time and updates the display. */ function updateTimerDisplay() { let diff = elapsedTime; let minutes = Math.floor(diff / 60000); diff -= minutes * 60000; let seconds = Math.floor(diff / 1000); diff -= seconds * 1000; let milliseconds = Math.floor(diff / 10); timerDisplay.textContent = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds + '.' + (milliseconds < 10 ? '0' : '') + milliseconds; } /** * Formats a time value (in ms) into a string for display. * @param {number} time - The time in milliseconds. * @returns {string} The formatted time string. */ function formatTime(time) { let diff = time; let minutes = Math.floor(diff / 60000); diff -= minutes * 60000; let seconds = Math.floor(diff / 1000); diff -= seconds * 1000; let milliseconds = Math.floor(diff / 10); return (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds + '.' + (milliseconds < 10 ? '0' : '') + milliseconds; } /** * Renders the recorded laps into the log table. */ function displayLaps() { lapsLog.innerHTML = ''; // Clear previous logs const table = document.createElement('table'); table.className = 'w-full text-left'; const tbody = document.createElement('tbody'); laps.forEach((lap, index) => { const row = tbody.insertRow(0); // Insert at the top row.className = 'lap-item border-b border-gray-200'; const cell1 = row.insertCell(0); const cell2 = row.insertCell(1); cell1.className = 'py-2 px-2 font-semibold text-gray-600'; cell2.className = 'py-2 px-2 text-right font-mono text-gray-800'; cell1.textContent = `Lap ${index + 1}`; cell2.textContent = formatTime(lap); }); table.appendChild(tbody); lapsLog.appendChild(table); } /** * Manages the enabled/disabled state of control buttons. */ function updateButtonStates() { startBtn.disabled = running; stopBtn.disabled = !running; lapBtn.disabled = !running && elapsedTime === 0; resetBtn.disabled = !running && elapsedTime === 0; } // --- PDF GENERATION --- /** * Generates and downloads a PDF of the agility test results. */ window.downloadPDF = async function() { // Clear any previous messages statusMessage.textContent = ''; statusMessage.className = 'h-6 mt-2 text-sm font-medium'; // Check if there are laps to record if (laps.length === 0) { statusMessage.textContent = "No laps recorded to download."; statusMessage.classList.add('text-red-600'); return; } // Check for required libraries if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { console.error("jsPDF or html2canvas library not loaded."); statusMessage.textContent = "PDF library failed to load."; statusMessage.classList.add('text-red-600'); return; } statusMessage.textContent = "Generating Performance Report..."; statusMessage.classList.add('text-gray-600'); downloadPdfBtn.disabled = true; const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); const reportDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); let tableRows = laps.map((lap, index) => ` Lap ${index + 1} ${formatTime(lap)} `).join(''); pdfContent.innerHTML = `

Agility Test Report

Test Date: ${reportDate}

Recorded Lap Times

${tableRows}
Trial Time

Best Lap

${formatTime(Math.min(...laps))}

Slowest Lap

${formatTime(Math.max(...laps))}

This report was generated for performance tracking purposes. For official timing, please use certified equipment.

`; pdfContent.style.position = 'absolute'; pdfContent.style.left = '-9999px'; pdfContent.classList.remove('hidden'); try { const canvas = await html2canvas(pdfContent.firstElementChild, { scale: 2 }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'in', format: 'letter' }); pdf.addImage(imgData, 'PNG', 0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight()); pdf.save('Agility_Test_Results.pdf'); } catch (error) { console.error("Error generating PDF:", error); statusMessage.textContent = "An error occurred during PDF creation."; statusMessage.className = 'h-6 mt-2 text-sm font-medium text-red-600'; } finally { // Clear status message after a delay setTimeout(() => { statusMessage.textContent = ''; }, 4000); pdfContent.classList.add('hidden'); pdfContent.innerHTML = ''; downloadPdfBtn.disabled = false; } }; // --- INITIALIZATION --- updateButtonStates(); });
Scroll to Top