diff --git a/README.md b/README.md index f44e1f2..74853e9 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,19 @@ Das Training umfasst 20 Lektionen: 4. Ihre Statistiken (WPM und Genauigkeit) werden in Echtzeit aktualisiert 5. Wechseln Sie zur nächsten Lektion oder beenden Sie die Sitzung +## Zeitmessung und Statistik + +Die Zeitmessung beginnt mit dem ersten Tastendruck und läuft kontinuierlich bis zum Abschluss der Lektion. Folgende Metriken werden berechnet: + +- **Tastaturanschläge**: Jeder Tastendruck wird gezählt (inklusive Backspace) +- **Korrekte Zeichen**: Zeichen, die exakt mit der Vorlage übereinstimmen +- **Falsche Zeichen**: Differenz zwischen Gesamtanschlägen und korrekten Zeichen +- **Zeichen pro Sekunde**: Korrekte Zeichen / verstrichene Zeit in Sekunden +- **Fehlerrate**: (Falsche Zeichen * 100) / Korrekte Zeichen +- **Wörter pro Minute (WPM)**: (Korrekte Zeichen / 5) / (verstrichene Zeit in Minuten) + +Die Berechnung erfolgt über die gesamte Lektion hinweg und berücksichtigt alle Zeilen. + ## Entwickler-Funktionen - `/debug` - Debug-Informationen diff --git a/static/js/script.js b/static/js/script.js index 4be86bf..13a21a1 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -44,11 +44,15 @@ document.addEventListener('DOMContentLoaded', function() { const totalElement = document.getElementById('total'); const wpmElement = document.getElementById('wpm'); - // Aktuelle Textdaten (verwende nur lines, entferne currentText) + // Aktuelle Textdaten let lines = window.lines; let currentLineIndex = window.currentLineIndex; let startTime = null; let timerInterval = null; + let completedLines = []; // Abgeschlossene Zeilen + let currentLineInput = ''; // Aktuelle Eingabe in der aktuellen Zeile + let fullText = lines.join('\n'); // Gesamter Text der Lektion + let keyStrokeCount = 0; // Zähler für alle Tastaturanschläge (inkl. Backspace) // Zeige die erste Zeile an updateLineDisplay(); @@ -56,33 +60,43 @@ document.addEventListener('DOMContentLoaded', function() { // Fokus auf das Eingabefeld setzen userInput.focus(); - // Starte die Zeitmessung beim ersten Tastendruck + // Starte die Zeitmessung beim ersten Tastendruck und zähle Tastaturanschläge userInput.addEventListener('keydown', function(event) { - if (!startTime && event.key.length === 1) { // Nur Buchstaben, Zahlen, etc. - startTime = new Date(); + // Zähle Tastaturanschläge für alle Tasten, die keine Steuertasten sind (inkl. Backspace) + // Beachte: event.key für Backspace ist 'Backspace' + if (event.key.length === 1 || event.key === 'Backspace') { + if (!startTime) { + startTime = new Date(); + } + keyStrokeCount++; + // Aktualisiere die Statistik sofort, um die Änderung anzuzeigen + updateStatistics(); } }); - // Aktualisiere die Statistik bei jedem Tastendruck + // Aktualisiere die Statistik bei jedem Tastendruck (keyup) userInput.addEventListener('keyup', function() { - const userValue = this.value; + currentLineInput = this.value; const currentLine = lines[currentLineIndex]; - updateStatistics(userValue, currentLine); // Wenn die Zeile vollständig korrekt getippt wurde, zur nächsten Zeile - if (userValue === currentLine) { + if (currentLineInput === currentLine) { if (currentLineIndex < lines.length - 1) { + completedLines.push(currentLineInput); + currentLineInput = ''; + this.value = ''; currentLineIndex++; - userInput.value = ''; updateLineDisplay(); - updateStatistics('', lines[currentLineIndex]); } else { - // Lektion beendet - Statistik speichern + // Letzte Zeile abgeschlossen + completedLines.push(currentLineInput); + currentLineInput = ''; + this.value = ''; alert('Lektion beendet!'); - // Setze zurück für nächste Lektion? - // Oder automatisch zur nächsten Lektion? } } + + updateStatistics(); }); // Funktion zum Aktualisieren der Lektionsmarkierung @@ -124,14 +138,18 @@ document.addEventListener('DOMContentLoaded', function() { if (data.error) { alert('Fehler: ' + data.error); } else { - // Verwende nur lines, entferne currentText lines = data.text.split('\n'); currentLineIndex = 0; + completedLines = []; + currentLineInput = ''; + fullText = lines.join('\n'); + startTime = null; + keyStrokeCount = 0; // Zurücksetzen des Tastaturanschlagszählers updateLineDisplay(); document.getElementById('lesson-title').textContent = data.title; userInput.value = ''; userInput.focus(); - updateStatistics('', lines[currentLineIndex]); + updateStatistics(); // Aktualisiere die Markierung der aktuellen Lektion updateLessonHighlight(lessonIndex); } @@ -157,15 +175,19 @@ document.addEventListener('DOMContentLoaded', function() { }) .then(response => response.json()) .then(data => { - // Verwende nur lines, entferne currentText lines = data.text.split('\n'); currentLineIndex = 0; + completedLines = []; + currentLineInput = ''; + fullText = lines.join('\n'); + startTime = null; + keyStrokeCount = 0; // Zurücksetzen des Tastaturanschlagszählers updateLineDisplay(); // Aktualisiere den Lektionstitel document.getElementById('lesson-title').textContent = data.title; userInput.value = ''; userInput.focus(); // Fokus zurück auf Eingabefeld - updateStatistics('', lines[currentLineIndex]); + updateStatistics(); // Aktualisiere die Markierung der aktuellen Lektion updateLessonHighlight(data.index); }) @@ -190,7 +212,7 @@ document.addEventListener('DOMContentLoaded', function() { }); // Statistik aktualisieren - function updateStatistics(userInput, currentText) { + function updateStatistics() { // Berechne verstrichene Zeit nur wenn der Benutzer tippt let elapsedTime = 0; if (startTime) { @@ -198,32 +220,42 @@ document.addEventListener('DOMContentLoaded', function() { elapsedTime = (now - startTime) / 1000; // in Sekunden } - // Sende Daten an den Server nur wenn der Benutzer tippt oder klickt - fetch('/update_progress', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - user_input: userInput, - current_text: currentText, - elapsed_time: elapsedTime - }) - }) - .then(response => response.json()) - .then(data => { - // Aktualisiere die Anzeige - speedElement.textContent = data.typing_speed; - errorRateElement.textContent = data.error_rate.toFixed(1); - correctElement.textContent = data.correct_chars; - incorrectElement.textContent = data.incorrect_chars; - totalElement.textContent = data.total_chars; - wpmElement.textContent = Math.round(data.words_per_minute); - - // Aktualisiere die Textfarben - updateTextHighlighting(userInput, currentText); - }) - .catch(error => console.error('Fehler:', error)); + // Berechne die gesamte Benutzereingabe + let fullUserInput = completedLines.join('\n'); + if (completedLines.length > 0) { + fullUserInput += '\n' + currentLineInput; + } else { + fullUserInput = currentLineInput; + } + + // Berechne Statistiken + let totalKeyStrokes = keyStrokeCount; // Verwende jetzt die Anzahl aller Tastaturanschläge (inkl. Backspace) + let correctKeyStrokes = 0; + + // Zähle korrekte Zeichen + for (let i = 0; i < fullUserInput.length; i++) { + if (i < fullText.length && fullUserInput[i] === fullText[i]) { + correctKeyStrokes++; + } else { + break; + } + } + + let incorrectKeyStrokes = totalKeyStrokes - correctKeyStrokes; + let charsPerSecond = elapsedTime > 0 ? correctKeyStrokes / elapsedTime : 0; + let errorRate = correctKeyStrokes > 0 ? (incorrectKeyStrokes * 100.0) / correctKeyStrokes : 0; + let wpm = elapsedTime > 0 ? (correctKeyStrokes / 5) / (elapsedTime / 60) : 0; + + // Aktualisiere die Anzeige + speedElement.textContent = charsPerSecond.toFixed(1); + errorRateElement.textContent = errorRate.toFixed(1); + correctElement.textContent = correctKeyStrokes; + incorrectElement.textContent = incorrectKeyStrokes; + totalElement.textContent = totalKeyStrokes; + wpmElement.textContent = Math.round(wpm); + + // Aktualisiere die Textfarben + updateTextHighlighting(currentLineInput, lines[currentLineIndex]); } // Text hervorheben diff --git a/templates/index.html b/templates/index.html index 28d94ea..b97afd2 100644 --- a/templates/index.html +++ b/templates/index.html @@ -101,7 +101,7 @@ 0