feat: use saved colors in assessment_grading

This commit is contained in:
2025-08-09 16:44:00 +02:00
parent 096dcebd80
commit ac2762218e
4 changed files with 252 additions and 44 deletions

View File

@@ -450,7 +450,12 @@ const GRADING_CONFIG = {
'{{ value }}' : {{ scale_values[value] | tojson }}{% if not loop.last %},{% endif %}
{% endfor %}
},
special_keys: Object.keys({{ scale_values | tojson }}).filter(key => !['0', '1', '2', '3'].includes(key))
special_keys: Object.keys({{ scale_values | tojson }}).filter(key => !['0', '1', '2', '3'].includes(key)),
notes_gradient: {
min_color: '{{ notes_gradient.min_color }}',
max_color: '{{ notes_gradient.max_color }}',
enabled: {{ notes_gradient.enabled|tojson }}
}
};
// ====== ÉTAT GLOBAL ======
@@ -508,6 +513,118 @@ class GradingState {
const state = new GradingState();
// ====== FONCTIONS D'INTERPOLATION HSL ======
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function rgbToHex(r, g, b) {
const toHex = (c) => {
const hex = Math.round(Math.max(0, Math.min(255, c))).toString(16);
return hex.length == 1 ? "0" + hex : hex;
};
return "#" + toHex(r) + toHex(g) + toHex(b);
}
function rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h * 360, s: s * 100, l: l * 100 };
}
function hslToRgb(h, s, l) {
h = h / 360;
s = s / 100;
l = l / 100;
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
}
function interpolateColorHSL(color1, color2, factor) {
const rgb1 = hexToRgb(color1);
const rgb2 = hexToRgb(color2);
if (!rgb1 || !rgb2) return color1;
const hsl1 = rgbToHsl(rgb1.r, rgb1.g, rgb1.b);
const hsl2 = rgbToHsl(rgb2.r, rgb2.g, rgb2.b);
// Gérer la transition de teinte (chemin le plus court)
let h1 = hsl1.h;
let h2 = hsl2.h;
let deltaH = h2 - h1;
if (deltaH > 180) {
h2 -= 360;
} else if (deltaH < -180) {
h2 += 360;
}
const h = h1 + (h2 - h1) * factor;
const s = hsl1.s + (hsl2.s - hsl1.s) * factor;
const l = hsl1.l + (hsl2.l - hsl1.l) * factor;
const normalizedH = ((h % 360) + 360) % 360;
const rgb = hslToRgb(normalizedH, s, l);
return rgbToHex(rgb.r, rgb.g, rgb.b);
}
// Fonction globale pour calculer la couleur d'une note
window.getNotesGradientColor = function(note, maxPoints) {
if (!GRADING_CONFIG.notes_gradient.enabled) return '#6b7280';
const factor = Math.min(1, Math.max(0, note / maxPoints));
return interpolateColorHSL(
GRADING_CONFIG.notes_gradient.min_color,
GRADING_CONFIG.notes_gradient.max_color,
factor
);
};
// ====== INITIALISATION ======
document.addEventListener('DOMContentLoaded', function() {
setupKeyboardNavigation();
@@ -533,31 +650,24 @@ class ColorManager {
}
static applyColorToInput(input, value, type, isValid, maxPoints) {
// Reset styles
// Reset styles complètement
input.className = input.className.replace(/border-\w+-\d+|bg-\w+-\d+/g, '').trim();
input.style.cssText = '';
input.style.borderWidth = '1px'; // Reset border width
input.style.boxShadow = 'none'; // Reset box shadow
if (!value || value.trim() === '') {
input.style.color = '#6b7280';
return;
}
// Couleurs configurées
if (GRADING_CONFIG.scale_values[value]) {
const config = GRADING_CONFIG.scale_values[value];
input.style.color = config.color;
input.style.backgroundColor = this.hexToRgba(config.color, 0.1);
input.style.borderColor = this.hexToRgba(config.color, 0.3);
input.style.fontWeight = 'bold';
if (isNaN(value)) input.style.fontStyle = 'italic';
return;
}
if (!isValid) {
input.style.color = '#dc2626';
input.style.backgroundColor = '#fef2f2';
input.style.borderColor = '#fca5a5';
input.style.color = '#ffffff';
input.style.backgroundColor = '#dc2626';
input.style.borderColor = '#dc2626';
input.style.borderWidth = '2px';
input.style.fontWeight = 'bold';
input.style.boxShadow = '0 0 0 3px rgba(220, 38, 38, 0.3)';
const message = type === 'score' ?
'Valeur autorisée : 0, 1, 2, 3 ou valeurs spéciales' :
@@ -566,22 +676,43 @@ class ColorManager {
return;
}
// Gradient pour notes numériques
// Pour les scores : toujours utiliser les couleurs configurées de l'échelle
if (type === 'score') {
if (GRADING_CONFIG.scale_values[value]) {
const config = GRADING_CONFIG.scale_values[value];
input.style.color = '#374151';
input.style.backgroundColor = this.hexToRgba(config.color, 0.25);
input.style.borderColor = this.hexToRgba(config.color, 0.5);
input.style.fontWeight = 'bold';
if (isNaN(value)) input.style.fontStyle = 'italic';
}
return;
}
// Pour les notes : d'abord vérifier les valeurs spéciales, sinon utiliser le dégradé
if (type === 'notes') {
const percentage = Math.min(100, (parseFloat(value) / maxPoints) * 100);
const colors = ['#ef4444', '#f6d32d', '#22c55e', '#059669'];
const thresholds = [40, 60, 80];
let colorIndex = 0;
for (let i = 0; i < thresholds.length; i++) {
if (percentage >= thresholds[i]) colorIndex = i + 1;
// Valeurs spéciales (non numériques comme ".", "d", etc.)
if (GRADING_CONFIG.scale_values[value] && isNaN(value)) {
const config = GRADING_CONFIG.scale_values[value];
input.style.color = '#374151';
input.style.backgroundColor = this.hexToRgba(config.color, 0.25);
input.style.borderColor = this.hexToRgba(config.color, 0.5);
input.style.fontWeight = 'bold';
input.style.fontStyle = 'italic';
return;
}
const noteColor = colors[colorIndex];
input.style.color = noteColor;
input.style.backgroundColor = this.hexToRgba(noteColor, 0.1);
input.style.borderColor = this.hexToRgba(noteColor, 0.3);
input.style.fontWeight = 'bold';
// Notes numériques : utiliser le dégradé HSL
const numValue = parseFloat(value);
if (!isNaN(numValue)) {
const noteColor = window.getNotesGradientColor(numValue, maxPoints);
input.style.color = '#374151';
input.style.backgroundColor = this.hexToRgba(noteColor, 0.25);
input.style.borderColor = this.hexToRgba(noteColor, 0.5);
input.style.fontWeight = 'bold';
input.style.fontStyle = 'normal';
}
}
}