// Export Web/SCORM — port de screens/rendering/render_jauge.py (jauge liée // à une donnée : remplissage % + dégradé de couleur recalculés depuis un // champ numérique d'un objet). Lit gameData.data/fields_meta directement // au lieu d'une requête SQL (voir _read_field_value côté serveur). function forgeHexToRgb(hexColor) { let hex = (hexColor || '#5b8cff').replace(/^#/, ''); if (hex.length !== 6) hex = '5b8cff'; return [parseInt(hex.substr(0, 2), 16), parseInt(hex.substr(2, 2), 16), parseInt(hex.substr(4, 2), 16)]; } function forgeInterpolateColor(lowHex, highHex, ratio) { const lo = forgeHexToRgb(lowHex); const hi = forgeHexToRgb(highHex); const mixed = lo.map((c, i) => Math.round(c + (hi[i] - c) * ratio)); const toHex = function (n) { return n.toString(16).padStart(2, '0'); }; return `#${mixed.map(toHex).join('')}`; } // Port de _read_field_value — repli sur la ligne la PLUS RÉCENTE si // row_id est absent/introuvable (comportement historique, un objet à une // seule ligne n'est jamais impacté). function forgeReadFieldValue(gameData, definitionId, rowId, fieldName) { if (!definitionId || !fieldName) return null; definitionId = String(definitionId); const rows = gameData.data && gameData.data[definitionId]; if (!rows || !rows.length) return null; let row = null; if (rowId) row = rows.find((r) => String(r.id) === String(rowId)); if (!row) row = rows[0]; return row[fieldName]; } function forgeRenderJauge(el, meta, gameData, childrenMap, ctx, parentFlexDirection) { const attrs = el.attributes || {}; const nomPosition = attrs._nom_position || 'dessus'; const nomAlignement = attrs._nom_alignement || 'centre'; const nomPolice = attrs._nom_police || 'inherit'; const nomTaille = attrs._nom_taille || '12'; const nomGras = attrs._nom_gras === '1'; const nomItalique = attrs._nom_italique === '1'; const flexDir = nomPosition === 'cote' ? 'row' : 'column'; const alignItems = nomPosition === 'cote' ? 'center' : 'stretch'; const style = `${forgeStyleString(el, parentFlexDirection, el.widget)} display:flex; flex-direction:${flexDir}; align-items:${alignItems}; justify-content:center; gap:4px;`; const definitionId = attrs._definition_id; const rowId = attrs._row_id; const fieldName = (attrs._champ || '').trim(); const fieldNameNom = (attrs._champ_nom || '').trim(); let minV = parseFloat(attrs._min); if (Number.isNaN(minV)) minV = 0; let maxV = parseFloat(attrs._max); if (Number.isNaN(maxV)) maxV = 100; const couleurBasse = attrs._couleur_basse || '#e05252'; const couleurHaute = attrs._couleur_haute || '#4caf50'; const afficherValeur = attrs._afficher_valeur === '1'; const rawValue = fieldName ? forgeReadFieldValue(gameData, definitionId, rowId, fieldName) : null; let value = parseFloat(rawValue); if (Number.isNaN(value)) value = minV; const span = (maxV - minV) || 1; const ratio = Math.max(0, Math.min(1, (value - minV) / span)); const percent = Math.round(ratio * 1000) / 10; const fillColor = forgeInterpolateColor(couleurBasse, couleurHaute, ratio); let labelHtml = ''; if (afficherValeur) { labelHtml = '
${ forgeHtmlEscape(rawValue !== null && rawValue !== undefined ? String(rawValue) : '—')}
`; } let nameHtml = ''; if (fieldNameNom) { const nomValue = forgeReadFieldValue(gameData, definitionId, rowId, fieldNameNom); if (nomValue !== null && nomValue !== undefined && nomValue !== '') { const textAlign = (nomPosition === 'dessus' && nomAlignement === 'gauche') ? 'left' : 'center'; nameHtml = `
${forgeHtmlEscape(String(nomValue))}
`; } } const extraClasses = Object.keys(attrs) .filter((k) => k.indexOf('_class_') === 0 && attrs[k]) .map((k) => attrs[k]).join(' '); const barClass = forgeHtmlEscape((`progress jaugeBar ${extraClasses}`).trim()); const bar = `${percent}%`; const barWrap = '
${bar}${labelHtml}
`; return `
${ nameHtml}${barWrap}
`; } if (typeof module !== 'undefined' && module.exports) { module.exports = { forgeRenderJauge, forgeHexToRgb, forgeInterpolateColor, forgeReadFieldValue, }; const renderMod = require('./render-element.js'); global.forgeStyleString = global.forgeStyleString || renderMod.forgeStyleString; global.forgeHtmlEscape = global.forgeHtmlEscape || renderMod.forgeHtmlEscape; global.forgeAutoId = global.forgeAutoId || renderMod.forgeAutoId; }