/* ============================================================
CHARTS — visualizaciones SVG (radar, barras, dona, heatmap…)
Exporta a window: Glyph, Radar, DistBars, Donut, Heatmap,
EvolBar, HistLines, ScoreBar, RingStat
============================================================ */
const IHX = window.IH;
const ARCH = IHX.archetypes;
const COL = Object.fromEntries(ARCH.map(a => [a.id, a.hex]));
/* —— Glifo geométrico abstracto por arquetipo —— */
function Glyph({ id, size = 28, stroke = 2, color }) {
const c = color || COL[id] || '#888';
const s = size, m = s / 2;
const props = { fill: 'none', stroke: c, strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round' };
let body = null;
switch (id) {
case 'huerfano': // anillo abierto
body = ;
break;
case 'vagabundo': // zigzag
body = ;
break;
case 'martir': // diamante partido
body =
;
break;
case 'guerrero': // triángulo ascendente
body = ;
break;
case 'sabio': // concéntrico
body =
;
break;
case 'mago': // octograma (dos cuadrados)
body =
;
break;
default:
body = ;
}
return ;
}
/* —— RADAR —— series: [{scores, color, fillOpacity, label, dash}] —— */
function Radar({ series = [], size = 360, max = 100, showColoredAxes = true, labels = true, levels = 4 }) {
const cx = size / 2, cy = size / 2;
const pad = labels ? 58 : 14;
const R = size / 2 - pad;
const ids = IHX.order;
const N = ids.length;
const angle = i => (-Math.PI / 2) + (i * 2 * Math.PI / N);
const pt = (i, r) => [cx + r * Math.cos(angle(i)), cy + r * Math.sin(angle(i))];
const gridPolys = [];
for (let l = 1; l <= levels; l++) {
const r = R * l / levels;
const pts = ids.map((_, i) => pt(i, r).join(',')).join(' ');
gridPolys.push();
}
const spokes = ids.map((_, i) => {
const [x, y] = pt(i, R);
return ;
});
return (
);
}
/* —— Etiqueta de valor en el eje (leyenda compacta) —— */
function AxisLegend({ scores }) {
return (
{IHX.order.map(id => {
const a = IHX.byId[id];
return (
{a.name}
{scores[id]}%
);
})}
);
}
/* —— Barra de puntaje horizontal —— */
function ScoreBar({ id, value, max = 100, height = 9, showGlyph = false, animated = true }) {
const a = IHX.byId[id];
return (
);
}
/* —— Distribución: cuántos colaboradores por arquetipo dominante —— */
function DistBars({ dist, total }) {
const maxV = Math.max(1, ...Object.values(dist));
return (
{IHX.order.map(id => {
const a = IHX.byId[id];
const v = dist[id] || 0;
const pct = Math.round((v / (total || 1)) * 100);
return (
);
})}
);
}
/* —— Dona de distribución —— */
function Donut({ dist, total, size = 200, thickness = 26 }) {
const cx = size / 2, cy = size / 2, r = (size - thickness) / 2;
const circ = 2 * Math.PI * r;
let acc = 0;
const segs = IHX.order.map(id => {
const v = dist[id] || 0;
const frac = total ? v / total : 0;
const seg = { id, frac, off: acc };
acc += frac;
return seg;
});
return (
);
}
/* —— Mapa de calor organizacional (área × arquetipo) —— */
function Heatmap({ areaMap }) {
const areas = Object.keys(areaMap);
const ids = IHX.order;
const cell = (v) => {
// 0..100 → opacidad
return Math.max(0.06, Math.min(1, v / 100));
};
return (
| Área |
{ids.map(id => (
{IHX.byId[id].name}
|
))}
{areas.map(ar => (
| {ar}
n={areaMap[ar].n}
|
{ids.map(id => {
const v = areaMap[ar].scores[id];
const op = cell(v);
const light = op > 0.62;
return (
{v}
|
);
})}
))}
);
}
/* —— Ranking de evolución por área —— */
function EvolRanking({ rows }) {
const maxV = 100;
return (
{rows.map((r, i) => (
{String(i + 1).padStart(2, '0')}
{r.area}
{r.evol}
))}
);
}
/* —— Comparación histórica (líneas/área del índice + arquetipos) —— */
function HistLines({ hist, width = 520, height = 200 }) {
const pad = { t: 16, r: 16, b: 30, l: 30 };
const W = width - pad.l - pad.r, H = height - pad.t - pad.b;
const xs = hist.map((_, i) => pad.l + (hist.length === 1 ? W / 2 : i * W / (hist.length - 1)));
const y = v => pad.t + H - (v / 100) * H;
const ids = IHX.order;
return (
);
}
/* —— Anillo estadístico (índice de evolución) —— */
function RingStat({ value, label, size = 132, color = 'var(--gold)' }) {
const r = (size - 14) / 2, circ = 2 * Math.PI * r, cx = size / 2;
return (
{label && {label}}
);
}
Object.assign(window, { Glyph, Radar, AxisLegend, ScoreBar, DistBars, Donut, Heatmap, EvolRanking, HistLines, RingStat, COL });