// diag-charts.jsx — Radar (araña 8 ejes con iconos) + brecha tipo dot-plot. function polar(cx, cy, r, angleDeg) { const a = (angleDeg - 90) * Math.PI / 180; return [cx + r * Math.cos(a), cy + r * Math.sin(a)]; } function RadarChart({ scores, light }) { const size = 540, cx = size / 2, cy = size / 2, R = 156; const N = scores.length; const levels = [1, 2, 3, 4, 5]; const angleAt = i => (360 / N) * i; const ring = (lvl) => { const r = R * (lvl / 5); return scores.map((_, i) => polar(cx, cy, r, angleAt(i)).join(',')).join(' '); }; const poly = (accessor) => scores.map((s, i) => { const r = R * (accessor(s) / 5); return polar(cx, cy, r, angleAt(i)).join(','); }).join(' '); const curPts = poly(s => s.current); const tgtPts = poly(s => s.target); const cls = 'radar-svg' + (light ? ' light' : ''); return (
{levels.map(l => )} {scores.map((s, i) => { const [x, y] = polar(cx, cy, R, angleAt(i)); return ; })} {/* current + target areas */} {scores.map((s, i) => { const [cxp, cyp] = polar(cx, cy, R * (s.current / 5), angleAt(i)); const [txp, typ] = polar(cx, cy, R * (s.target / 5), angleAt(i)); return ( ); })} {/* icon badges + names at each vertex */} {scores.map((s, i) => { const [ix, iy] = polar(cx, cy, R + 26, angleAt(i)); const [lx, ly] = polar(cx, cy, R + 54, angleAt(i)); const anchor = Math.abs(lx - cx) < 14 ? 'middle' : (lx > cx ? 'start' : 'end'); const icon = window.DIAG_EJE_ICONS[s.key] || ''; return ( {s.name} ); })}
); } /* ---- BRECHA: dot-plot coloquial (gris = hoy, círculo rojo = tu siguiente nivel) ---- light = versión compacta para el PDF (sin cambios). web = versión enriquecida: ordena por prioridad, muestra los valores hoy → meta sobre la escala 1–5 y marca los ejes que más se deben trabajar. */ function DetailBars({ scores, light }) { const pos = v => Math.max(0, Math.min(100, ((v - 1) / 4) * 100)); /* ---------- versión compacta (PDF) ---------- */ if (light) { return (
{scores.map(s => { const cur = pos(s.current), tgt = pos(s.target); const gap = Math.round((s.target - s.current) * 10) / 10; const lo = Math.min(cur, tgt), hi = Math.max(cur, tgt); const icon = window.DIAG_EJE_ICONS[s.key] || ''; return (
{s.name}
{gap > 0.1 ? `+${gap.toFixed(1)}` : '✓'}
); })}
); } /* ---------- versión web enriquecida ---------- */ // Ordena por prioridad (mismo criterio que la recomendación): los ejes que // más se deben trabajar quedan arriba. Los 3 primeros se marcan como foco. const ranked = [...scores].sort((a, b) => (b.priority || 0) - (a.priority || 0)); const focusCount = ranked.filter(s => (s.target - s.current) > 0.1).length >= 3 ? 3 : 0; return (
{/* escala 1–5 alineada con las pistas */} {ranked.map((s, idx) => { const cur = pos(s.current), tgt = pos(s.target); const gap = Math.round((s.target - s.current) * 10) / 10; const lo = Math.min(cur, tgt), hi = Math.max(cur, tgt); const isFocus = idx < focusCount && gap > 0.1; const done = gap <= 0.1; const icon = window.DIAG_EJE_ICONS[s.key] || ''; const cls = 'gp-row' + (isFocus ? ' focus' : '') + (done ? ' done' : ''); return (
{idx + 1} {s.name} {isFocus && {idx === 0 ? 'Empieza por aquí' : 'Prioridad'}} {done && Ya casi lo tienes}
{s.current.toFixed(1)}
{s.target.toFixed(1)}
{gap > 0.1 ? ( +{gap.toFixed(1)} por subir ) : ( )}
); })}
Ordenado por dónde tu esfuerzo rinde más — empieza por arriba.
); } Object.assign(window, { RadarChart, DetailBars });