eis-website/js/notenrechner-dom.js

436 lines
13 KiB
JavaScript

/**
* Notenrechner DOM-Version
* Moderne JavaScript DOM-Manipulation mit addEventListener
* David & Karo - EIS Projekt
*/
// Notenmaßstab definieren
const NOTENMASSTAB = {
'sehr gut': { min: 90, max: 100, color: '#ff1493' },
'gut': { min: 75, max: 89, color: '#ff69b4' },
'befriedigend': { min: 60, max: 74, color: '#ffa500' },
'ausreichend': { min: 50, max: 59, color: '#ff8c00' },
'nicht bestanden': { min: 0, max: 49, color: '#dc143c' }
};
/**
* Berechnet die Note basierend auf der Punktzahl
* @param {number} punkte - Erreichte Punktzahl
* @param {number} maxPunkte - Maximale Punktzahl (default: 100)
* @returns {object} - Enthält Note, Prozentage und Details
*/
function berechneNote(punkte, maxPunkte = 100) {
// Eingabe validieren
punkte = parseFloat(punkte);
maxPunkte = parseFloat(maxPunkte);
if (isNaN(punkte) || isNaN(maxPunkte)) {
return {
note: 'Fehler',
prozent: 0,
valid: false,
nachricht: 'Bitte geben Sie Zahlen ein!'
};
}
if (maxPunkte <= 0) {
return {
note: 'Fehler',
prozent: 0,
valid: false,
nachricht: 'Maximale Punktzahl muss größer als 0 sein!'
};
}
if (punkte < 0 || punkte > maxPunkte) {
return {
note: 'Fehler',
prozent: 0,
valid: false,
nachricht: `Punkte müssen zwischen 0 und ${maxPunkte} liegen!`
};
}
// Prozentage berechnen
const prozent = Math.round((punkte / maxPunkte) * 100);
// Note basierend auf Prozentage bestimmen
let note = 'nicht bestanden';
let noteColor = '#dc143c';
for (const [noteText, range] of Object.entries(NOTENMASSTAB)) {
if (prozent >= range.min && prozent <= range.max) {
note = noteText;
noteColor = range.color;
break;
}
}
return {
note: note,
prozent: prozent,
punkte: punkte,
maxPunkte: maxPunkte,
valid: true,
color: noteColor,
nachricht: `${punkte} von ${maxPunkte} Punkten (${prozent}%) = ${note}`
};
}
/**
* Validiert die Eingabe
*/
function validateInput(value, maxValue = 100) {
if (value === '' || value === null) {
return { valid: false, error: 'Bitte geben Sie eine Punktzahl ein!' };
}
const num = parseFloat(value);
if (isNaN(num)) {
return { valid: false, error: 'Bitte geben Sie eine Zahl ein!' };
}
if (num < 0 || num > maxValue) {
return { valid: false, error: `Punktzahl muss zwischen 0 und ${maxValue} liegen!` };
}
return { valid: true };
}
// Warte bis DOM geladen ist
document.addEventListener('DOMContentLoaded', function() {
// Simple Notenrechner
const simplePointsInput = document.getElementById('simple-points');
const simpleMaxInput = document.getElementById('simple-max');
const simpleCalculateBtn = document.getElementById('simple-calculate-btn');
const simpleResult = document.getElementById('simple-result');
const simpleProgressBar = document.getElementById('simple-progress-bar');
// Multiple Notenrechner
const addGradeBtn = document.getElementById('add-grade-btn');
const multipleCalculateBtn = document.getElementById('multiple-calculate-btn');
const multipleResetBtn = document.getElementById('multiple-reset-btn');
const gradesContainer = document.getElementById('grades-container');
const multipleResult = document.getElementById('multiple-result');
const multipleAverage = document.getElementById('multiple-average');
// Simple Grade Calculator Event Listener
if (simpleCalculateBtn && simplePointsInput) {
simpleCalculateBtn.addEventListener('click', function() {
calculateSimpleGrade();
});
// Enter-Taste auch zum Berechnen verwenden
simplePointsInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
calculateSimpleGrade();
}
});
// Live-Berechnung während des Tippens
simplePointsInput.addEventListener('input', function() {
updateSimpleGradeLive();
});
simpleMaxInput.addEventListener('input', function() {
updateSimpleGradeLive();
});
}
// Multiple Grade Calculator Event Listener
if (addGradeBtn) {
addGradeBtn.addEventListener('click', function() {
addGradeInput();
});
}
if (multipleCalculateBtn) {
multipleCalculateBtn.addEventListener('click', function() {
calculateMultipleGrades();
});
}
if (multipleResetBtn) {
multipleResetBtn.addEventListener('click', function() {
resetMultipleCalculator();
});
}
// Initiale Grade hinzufügen
if (gradesContainer) {
addGradeInput();
}
/**
* Berechnet einfache Note und zeigt Ergebnis
*/
function calculateSimpleGrade() {
const points = simplePointsInput.value;
const max = simpleMaxInput.value || 100;
// Validierung
const validation = validateInput(points, max);
if (!validation.valid) {
showSimpleError(validation.error);
return;
}
// Berechnung
const result = berechneNote(parseFloat(points), parseFloat(max));
if (!result.valid) {
showSimpleError(result.nachricht);
return;
}
// Erfolgreiche Anzeige
showSimpleSuccess(result);
}
/**
* Live-Aktualisierung während des Tippens
*/
function updateSimpleGradeLive() {
const points = simplePointsInput.value;
const max = simpleMaxInput.value || 100;
if (points === '') {
simpleResult.innerHTML = '';
simpleProgressBar.style.display = 'none';
return;
}
const validation = validateInput(points, max);
if (!validation.valid) {
simpleResult.innerHTML = `<p class="error-text">⚠️ ${validation.error}</p>`;
simpleProgressBar.style.display = 'none';
return;
}
const result = berechneNote(parseFloat(points), parseFloat(max));
if (result.valid) {
simpleResult.innerHTML = `
<div class="grade-result-inline">
<span class="grade-note" style="color: ${result.color};">${result.note}</span>
<span class="grade-percent">${result.prozent}%</span>
</div>
`;
updateProgressBar(result.prozent, result.color);
}
}
/**
* Fehleranzeige mit rotem Hintergrund
*/
function showSimpleError(errorMessage) {
simplePointsInput.style.borderColor = 'red';
simplePointsInput.style.backgroundColor = 'rgba(220, 20, 60, 0.1)';
simpleResult.innerHTML = `<p class="error-text">❌ ${errorMessage}</p>`;
simpleProgressBar.style.display = 'none';
// Reset nach 2 Sekunden
setTimeout(() => {
simplePointsInput.style.borderColor = '';
simplePointsInput.style.backgroundColor = '';
}, 2000);
}
/**
* Erfolgreiche Anzeige mit Progressbar
*/
function showSimpleSuccess(result) {
simplePointsInput.style.borderColor = 'green';
simplePointsInput.style.backgroundColor = 'rgba(34, 197, 94, 0.1)';
simpleResult.innerHTML = `
<div class="grade-result-detailed">
<div class="result-header">
<h4>📊 Ergebnis:</h4>
<span class="grade-note-large" style="color: ${result.color};">${result.note}</span>
</div>
<div class="result-details">
<p><strong>Punkte:</strong> ${result.punkte} / ${result.maxPunkte}</p>
<p><strong>Prozentage:</strong> ${result.prozent}%</p>
</div>
</div>
`;
updateProgressBar(result.prozent, result.color);
// Reset nach 3 Sekunden
setTimeout(() => {
simplePointsInput.style.borderColor = '';
simplePointsInput.style.backgroundColor = '';
}, 3000);
}
/**
* Aktualisiert die Progressbar
*/
function updateProgressBar(percent, color) {
simpleProgressBar.style.display = 'block';
simpleProgressBar.innerHTML = `
<div class="progress-bar-background">
<div class="progress-bar-fill" style="width: ${percent}%; background-color: ${color};"></div>
</div>
<p class="progress-text">${percent}% Complete</p>
`;
}
/**
* Neue Grade-Input-Zeile hinzufügen (Multiple)
*/
function addGradeInput() {
if (!gradesContainer) return;
const gradeId = Date.now();
const gradeDiv = document.createElement('div');
gradeDiv.className = 'grade-input-group-dom';
gradeDiv.id = `grade-${gradeId}`;
gradeDiv.innerHTML = `
<div class="grade-input-wrapper-dom">
<input
type="number"
class="grade-points-dom"
placeholder="Punkte"
min="0"
step="0.5"
>
<span class="grade-separator">/</span>
<input
type="number"
class="grade-max-dom"
placeholder="Max"
value="100"
min="1"
step="1"
>
<div class="grade-result-dom">
<span class="grade-note-dom">-</span>
<span class="grade-percent-dom">0%</span>
</div>
<button class="grade-remove-btn-dom" type="button">✕</button>
</div>
`;
gradesContainer.appendChild(gradeDiv);
// Event Listener für neue Eingabe
const pointsInput = gradeDiv.querySelector('.grade-points-dom');
const maxInput = gradeDiv.querySelector('.grade-max-dom');
const removeBtn = gradeDiv.querySelector('.grade-remove-btn-dom');
const noteSpan = gradeDiv.querySelector('.grade-note-dom');
const percentSpan = gradeDiv.querySelector('.grade-percent-dom');
function updateGradeLive() {
const points = parseFloat(pointsInput.value) || 0;
const max = parseFloat(maxInput.value) || 100;
if (max > 0 && points >= 0 && points <= max) {
const result = berechneNote(points, max);
if (result.valid) {
noteSpan.textContent = result.note;
percentSpan.textContent = result.prozent + '%';
noteSpan.style.color = result.color;
}
} else {
noteSpan.textContent = '-';
percentSpan.textContent = '0%';
}
}
pointsInput.addEventListener('input', updateGradeLive);
maxInput.addEventListener('input', updateGradeLive);
removeBtn.addEventListener('click', function() {
gradeDiv.remove();
});
pointsInput.focus();
}
/**
* Berechnet mehrere Noten
*/
function calculateMultipleGrades() {
const gradeInputs = gradesContainer.querySelectorAll('.grade-input-group-dom');
const noten = [];
gradeInputs.forEach(input => {
const points = parseFloat(input.querySelector('.grade-points-dom').value);
const max = parseFloat(input.querySelector('.grade-max-dom').value);
if (!isNaN(points) && !isNaN(max) && max > 0) {
const result = berechneNote(points, max);
if (result.valid) {
noten.push(result);
}
}
});
if (noten.length === 0) {
multipleResult.innerHTML = `<p class="error-text">⚠️ Bitte füllen Sie mindestens eine Note aus!</p>`;
multipleAverage.innerHTML = '';
return;
}
// Einzelnoten anzeigen
let resultHTML = '<div class="results-list"><h4>📊 Ihre Noten:</h4>';
noten.forEach((note, index) => {
resultHTML += `
<div class="result-item-dom">
<span class="result-number">#${index + 1}</span>
<span class="result-details">${note.punkte} / ${note.maxPunkte} (${note.prozent}%)</span>
<span class="result-grade-dom" style="color: ${note.color};">${note.note}</span>
</div>
`;
});
resultHTML += '</div>';
multipleResult.innerHTML = resultHTML;
// Durchschnitt berechnen
if (noten.length > 1) {
const durchschnittProzent = Math.round(
noten.reduce((sum, n) => sum + n.prozent, 0) / noten.length
);
let durchschnittNote = 'nicht bestanden';
let durchschnittColor = '#dc143c';
for (const [noteText, range] of Object.entries(NOTENMASSTAB)) {
if (durchschnittProzent >= range.min && durchschnittProzent <= range.max) {
durchschnittNote = noteText;
durchschnittColor = range.color;
break;
}
}
multipleAverage.innerHTML = `
<div class="average-box-dom">
<h4>📈 Durchschnitt:</h4>
<div class="average-display-dom">
<div class="average-percent-dom">${durchschnittProzent}%</div>
<div class="average-note-dom" style="color: ${durchschnittColor};">${durchschnittNote}</div>
</div>
<p class="average-details-dom">Von ${noten.length} Note(n)</p>
</div>
`;
// Console Ausgabe
console.log(`Durchschnitt: ${durchschnittProzent}% = ${durchschnittNote}`);
} else {
multipleAverage.innerHTML = '';
}
}
/**
* Setzt Multiple Grade Calculator zurück
*/
function resetMultipleCalculator() {
gradesContainer.innerHTML = '';
multipleResult.innerHTML = '';
multipleAverage.innerHTML = '';
addGradeInput();
}
});