436 lines
13 KiB
JavaScript
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();
|
|
}
|
|
});
|