import { useState, useEffect } from "react";
const DATA = {
"№1": { интер: 3, поток: 1, сети: 1, инст: 0 },
"№2": { интер: 1, поток: 1, сети: 0, инст: 2 },
"№3": { интер: 1, поток: 1, сети: 3, инст: 0 },
"№4": { интер: 0, поток: 0, сети: 0, инст: 0 },
"№5": { интер: 1, поток: 1, сети: 2, инст: 1 },
"№6": { интер: 2, поток: 2, сети: 1, инст: 2 },
"№7": { интер: 0, поток: 1, сети: 0, инст: 0 },
"№8": { интер: 0, поток: 2, сети: 1, инст: 2 },
"№9": { интер: 1, поток: 3, сети: 0, инст: 1 },
"№10": { интер: 2, поток: 1, сети: 1, инст: 0 },
"№11": { интер: 1, поток: 1, сети: 1, инст: 2 },
};
const CATS = ["интер", "поток", "сети", "инст"];
const LABELS = { интер: "Интеракция", поток: "Потоки", сети: "Сети", инст: "Институц." };
const COLORS = { интер: "#f97316", поток: "#06b6d4", сети: "#a3e635", инст: "#e879f9" };
const GROUPS = Object.keys(DATA);
const MAX_VAL = 3;
function polar(angleDeg, r, cx, cy) {
const rad = (angleDeg - 90) * Math.PI / 180;
return [cx + r * Math.cos(rad), cy + r * Math.sin(rad)];
}
function hexToRgb(hex) {
const r = parseInt(hex.slice(1,3),16);
const g = parseInt(hex.slice(3,5),16);
const b = parseInt(hex.slice(5,7),16);
return `${r},${g},${b}`;
}
function dominant(g) {
return CATS.reduce((a,b) => DATA[g][a] >= DATA[g][b] ? a : b);
}
function RadarChart({ highlighted, onSelect }) {
const S = 360, cx = 180, cy = 180, maxR = 130;
const step = 360 / CATS.length;
const rings = [1,2,3];
return (
);
}
function StatBar({ g }) {
const total = CATS.reduce((s,c) => s+DATA[g][c], 0);
if (total === 0) return
нет активности
;
return (
{CATS.map(cat => {
const v = DATA[g][cat];
const pct = total > 0 ? (v/MAX_VAL)*100 : 0;
return (
);
})}
);
}
export default function App() {
const [highlighted, setHighlighted] = useState(null);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setTimeout(() => setMounted(true), 100);
}, []);
const totals = CATS.map(cat => ({
cat, val: GROUPS.reduce((s,g) => s+DATA[g][cat], 0)
}));
const maxTotal = Math.max(...totals.map(t=>t.val));
const hlData = highlighted ? DATA[highlighted] : null;
const hlTotal = hlData ? CATS.reduce((s,c)=>s+hlData[c],0) : 0;
return (
{/* Header */}
Групповой анализ
РОЗА АКТИВНОСТИ
№1 – №11 · 4 НАПРАВЛЕНИЯ
{/* Legend */}
{/* Radar */}
{/* Highlighted info */}
{highlighted ? (
<>
{highlighted}
сумма: {hlTotal}
>
) : (
Нажми на группу для деталей
)}
{/* Right panel */}
{/* Group list */}
Группы
{GROUPS.map((g,idx) => {
const isHl = highlighted===g;
const dom = dominant(g);
const col = COLORS[dom];
const total = CATS.reduce((s,c)=>s+DATA[g][c],0);
const isEmpty = total === 0;
return (
setHighlighted(isHl?null:g)}
style={{
display:'flex',alignItems:'center',gap:8,
padding:'7px 12px',borderRadius:10,cursor:'pointer',
background: isHl ? `rgba(${hexToRgb(col)},0.18)` : 'rgba(255,255,255,0.03)',
border:`1px solid ${isHl ? col : 'rgba(255,255,255,0.07)'}`,
opacity: highlighted&&!isHl ? 0.4 : isEmpty ? 0.4 : 1,
transition:'all 0.2s',
boxShadow: isHl ? `0 0 16px ${col}40` : 'none',
minWidth:70,
}}>
{g}
{total}
);
})}
{/* Category totals */}
Итого по направлениям
{totals.map(({cat,val}) => (
))}
{/* Heat summary */}
Тепловая карта
{CATS.map(c => (
{c.slice(0,3).toUpperCase()}
))}
{GROUPS.map(g => (
<>
{g}
{CATS.map(cat => {
const v = DATA[g][cat];
const alpha = v/MAX_VAL;
return (
setHighlighted(highlighted===g?null:g)}
style={{
height:20,borderRadius:4,cursor:'pointer',
background: v>0 ? `rgba(${hexToRgb(COLORS[cat])},${0.15+alpha*0.75})` : 'rgba(255,255,255,0.04)',
border: highlighted===g ? `1px solid ${COLORS[cat]}80` : '1px solid transparent',
display:'flex',alignItems:'center',justifyContent:'center',
fontSize:10,color:v>0?'rgba(255,255,255,0.9)':'rgba(255,255,255,0.15)',
fontWeight:700,transition:'all 0.2s',
}}>
{v||'·'}
);
})}
>
))}
НАЖМИ НА ГРУППУ · ВЫДЕЛИ НА РАДАРЕ
);
}