/* global React */ // ──────────────────────────────────────────────────────────── // STATS — статистика (графики за 14 дней) // ──────────────────────────────────────────────────────────── window.StatsScreen = ({ T, dark, onBack }) => { const data = window.DATA.useDataState(); const A = data.activity; const M = data.magDist; if (!A.length) { return (
Данные ещё не загружены.
); } const maxA = Math.max(1, ...A.map(d => d.world)); const maxM = Math.max(1, ...M.map(d => d.count)); const totalRu = A.reduce((s, d) => s + d.ru, 0); const totalWorld = A.reduce((s, d) => s + d.world, 0); const avgRu = (totalRu / A.length).toFixed(1); // Max magnitude over the past 30 days from the loaded events feed const events = data.events; const recent30 = events.filter(e => e.minutesAgo < 30 * 24 * 60); const maxMag = recent30.length > 0 ? Math.max(...recent30.map(e => e.mag)) : 0; const maxMagEvent = recent30.find(e => e.mag === maxMag); // SVG uses a viewBox so it scales fluidly to whatever width the card has. // The W/H here are virtual coordinates, not pixels. const W = 344, H = 140, PAD = 8; const stepX = A.length > 1 ? (W - PAD*2) / (A.length - 1) : (W - PAD*2); const pathRu = A.map((d, i) => `${i === 0 ? "M" : "L"} ${PAD + i*stepX} ${H - PAD - (d.ru / maxA) * (H - PAD*2)}`).join(" "); const pathW = A.map((d, i) => `${i === 0 ? "M" : "L"} ${PAD + i*stepX} ${H - PAD - (d.world / maxA) * (H - PAD*2)}`).join(" "); return (
{/* График активности */}
Активность по дням
РОССИЯ МИР
{[0, 0.25, 0.5, 0.75, 1].map((f, i) => ( ))} {A.map((d, i) => ( ))}
{A[0].d} {A[Math.floor(A.length/2)].d} {A[A.length-1].d}
{/* Распределение по магнитудам */} {M.length > 0 && (
Распределение по магнитудам · 30 дней
{/* Rows capped to a max width so the bar doesn't stretch on wide (desktop) viewports; the count lives in a fixed-width column so it stays visible at ANY width. The bar column uses minmax(0,1fr) so it can shrink instead of overflowing and pushing the count off-screen (the failure mode in Telegram Desktop's webview). */}
{M.map((d) => { const pct = (d.count / maxM) * 100; const isStrong = parseFloat(d.range) >= 5.0; return (
M {d.range || "—"}
{d.count}
); })}
)}
); }; function truncate(s, n) { if (!s) return ""; return s.length <= n ? s : s.slice(0, n - 1) + "…"; }