import React, { useState, useEffect, useRef, useCallback } from 'react'; import { ComposedChart, Area, Line, XAxis, YAxis, CartesianGrid, ReferenceArea, ReferenceLine, ResponsiveContainer, } from 'recharts'; // ── Fake demo data ────────────────────────────────────────────────────────── const STEP1_CARDS = ['Bajo', 'Medio', 'Alto', 'Perfecto']; const STEP1_BLANKS = [3, 1, 4]; // huecos asimétricos entre cartas const STEP2_TERMS = [ { name: 'Bajo', xVal: 0.08, mf: { supportStart: 0.00, coreStart: 0.00, coreEnd: 0.06, supportEnd: 0.30 } }, { name: 'Medio', xVal: 0.38, mf: { supportStart: 0.18, coreStart: 0.38, coreEnd: 0.38, supportEnd: 0.59 } }, // pico/triángulo { name: 'Alto', xVal: 0.65, mf: { supportStart: 0.52, coreStart: 0.60, coreEnd: 0.69, supportEnd: 0.77 } }, { name: 'Perfecto', xVal: 0.92, mf: { supportStart: 0.74, coreStart: 0.88, coreEnd: 1.00, supportEnd: 1.00 } }, ]; const STEP2_COLORS = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6']; // Igual que interpolateY en useGraphData.js: // · Zona buffer justo fuera del soporte → 0 (ancla la línea en y=0) // · Más allá del buffer → null (corte, sin línea horizontal) const TRAP_BUF = 1.1e-4; function trapVal(x, s0, c0, c1, s1) { if (x < s0 - TRAP_BUF || x > s1 + TRAP_BUF) return null; if (x < s0 || x > s1) return 0; if (x >= c0 && x <= c1) return 1; if (x < c0 && c0 > s0) return (x - s0) / (c0 - s0); if (x > c1 && s1 > c1) return (s1 - x) / (s1 - c1); return 0; } // Solo 'Alto' es IT2 (tiene subescala). LMF es triángulo → banda "lente" visible. const STEP3_TERMS = [ { name: 'Bajo', color: '#ef4444', type: 't1', pts: [0.00, 0.00, 0.06, 0.30] }, { name: 'Medio', color: '#f59e0b', type: 't1', pts: [0.18, 0.38, 0.38, 0.59] }, { name: 'Alto', color: '#10b981', type: 't2', u: [0.49, 0.57, 0.71, 0.81], l: [0.56, 0.64, 0.64, 0.76] }, { name: 'Perfecto', color: '#3b82f6', type: 't1', pts: [0.74, 0.88, 1.00, 1.00] }, ]; // Puntos clave del trapecio (piezas lineales → basta con vértices, como en el paso 2). // Recharts interpola el trazo entre ellos con animación fluida. function getTermLineData(term) { const name = term.name; if (term.type === 't1') { const [s0, c0, c1, s1] = term.pts; const xs = new Set([s0, c0, c1, s1]); if (s0 <= 0.001) xs.add(s0 - TRAP_BUF); if (s1 >= 0.999) xs.add(s1 + TRAP_BUF); return Array.from(xs).sort((a, b) => a - b).map(x => ({ x, [name]: trapVal(x, s0, c0, c1, s1), })); } const xs = new Set([...term.u, ...term.l]); return Array.from(xs).sort((a, b) => a - b).map(x => { const upper = trapVal(x, ...term.u); const lower = trapVal(x, ...term.l); return { x, [`${name}_upper`]: upper, [`${name}_lower`]: lower, [`${name}_range`]: (lower === null && upper === null) ? null : [lower ?? 0, upper ?? 0], }; }); } const STEP_LABELS = [ { n: 1, label: 'Escala' }, { n: 2, label: 'Modelado' }, { n: 3, label: 'Espectro IT2' }, ]; // ── Step sub-components ───────────────────────────────────────────────────── function Step1Content({ count }) { const done = count >= STEP1_CARDS.length; return (
Criterio: Calidad Investigadora
Espectro difuso · Calidad Investigadora