eis-website/js/notenrechner-dom.js

486 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 mit farbiger Visualisierung
*/
function updateProgressBar(percent, color) {
simpleProgressBar.style.display = 'block';
// Bestimme die Hintergrundfarbe basierend auf der Note
let bgColor = color;
let bgOpacity = 0.2;
simpleProgressBar.innerHTML = `
<div class="progress-bar-container-enhanced">
<div class="progress-bar-background" style="background-color: rgba(${hexToRgb(color)}, ${bgOpacity});">
<div class="progress-bar-fill" style="width: ${percent}%; background-color: ${color}; box-shadow: 0 0 15px ${color};">
<span class="progress-bar-text">${percent}%</span>
</div>
</div>
<div class="progress-bar-labels">
<span class="label-0">0%</span>
<span class="label-25">25%</span>
<span class="label-50">50%</span>
<span class="label-75">75%</span>
<span class="label-100">100%</span>
</div>
</div>
<p class="progress-text">
<span class="progress-emoji">📊</span>
Fortschritt: <strong>${percent}%</strong>
<span style="color: ${color}; font-weight: bold;">Sehr Gut Bereich</span>
</p>
`;
}
/**
* Konvertiert Hex-Farben zu RGB für rgba()
*/
function hexToRgb(hex) {
// Entfernt das # Zeichen
hex = hex.replace('#', '');
// Konvertiert zu RGB
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return `${r}, ${g}, ${b}`;
}
/**
* 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 mit Progressbars
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>
<div class="result-details-with-bar">
<div class="result-top">
<span class="result-details">${note.punkte} / ${note.maxPunkte}</span>
<span class="result-grade-dom" style="color: ${note.color};">${note.note}</span>
</div>
<div class="mini-progress-bar">
<div class="mini-progress-bar-bg">
<div class="mini-progress-bar-fill" style="width: ${note.prozent}%; background-color: ${note.color}; box-shadow: 0 0 8px ${note.color};"></div>
</div>
<span class="mini-progress-percent">${note.prozent}%</span>
</div>
</div>
</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" style="border: 3px solid ${durchschnittColor}; box-shadow: 0 0 20px ${durchschnittColor};">${durchschnittProzent}%</div>
<div class="average-note-dom" style="color: ${durchschnittColor};">${durchschnittNote}</div>
</div>
<div class="average-progress-bar">
<div class="average-progress-bg">
<div class="average-progress-fill" style="width: ${durchschnittProzent}%; background-color: ${durchschnittColor}; box-shadow: 0 0 15px ${durchschnittColor};"></div>
</div>
</div>
<p class="average-details-dom">Von ${noten.length} Note(n) Durchschnitt: <strong>${durchschnittProzent}%</strong></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();
}
});