add: añadida gráfica final. reforzada la seguridad en el payload para la petición a "build"
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
import {
|
||||||
|
LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
|
||||||
|
} from 'recharts';
|
||||||
|
import { CHART_COLORS } from '../../config';
|
||||||
|
|
||||||
|
const Step3FinalGraph = ({ data }) => {
|
||||||
|
if (!data || !data.results) return <p>Cargando gráfico final...</p>;
|
||||||
|
|
||||||
|
const resultsWithOriginalIndex = data.results.map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
originalIndex: index
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sortedResults = [...resultsWithOriginalIndex].sort((a, b) => {
|
||||||
|
const valA = a.core ? a.core[0] : 0;
|
||||||
|
const valB = b.core ? b.core[0] : 0;
|
||||||
|
return valA - valB;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full h-[500px] mt-2 bg-white p-6 rounded-2xl shadow-sm border border-slate-200">
|
||||||
|
<h3 className="text-2xl font-bold mb-8 text-center text-slate-800">Espectro Difuso Final</h3>
|
||||||
|
|
||||||
|
<ResponsiveContainer width="100%" height="90%">
|
||||||
|
<LineChart margin={{ top: 10, right: 30, left: 10, bottom: 40 }}>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" opacity={0.5} vertical={false} />
|
||||||
|
|
||||||
|
<XAxis
|
||||||
|
dataKey="x"
|
||||||
|
type="number"
|
||||||
|
domain={[0, 1]}
|
||||||
|
tickCount={11}
|
||||||
|
tick={{ fill: '#475569', fontWeight: 600, fontSize: 14 }}
|
||||||
|
allowDuplicatedCategory={false}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
domain={[0, 1]}
|
||||||
|
tickCount={6}
|
||||||
|
tick={{ fill: '#475569', fontSize: 14 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
formatter={(value, name) => [value.toFixed(3), name]}
|
||||||
|
labelFormatter={(label) => `X: ${Number(label).toFixed(3)}`}
|
||||||
|
contentStyle={{ borderRadius: '12px', border: 'none', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Legend
|
||||||
|
wrapperStyle={{ paddingTop: '30px' }}
|
||||||
|
iconType="circle"
|
||||||
|
payload={sortedResults.map(item => ({
|
||||||
|
id: item.term,
|
||||||
|
type: 'circle',
|
||||||
|
value: item.term.toUpperCase(),
|
||||||
|
color: CHART_COLORS[item.originalIndex % CHART_COLORS.length]
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{sortedResults.map((item) => {
|
||||||
|
const lineData = [...item.left_nodes, ...item.right_nodes].map(node => ({
|
||||||
|
x: node[0],
|
||||||
|
y: node[1]
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Line
|
||||||
|
key={item.term}
|
||||||
|
data={lineData}
|
||||||
|
type="linear"
|
||||||
|
dataKey="y"
|
||||||
|
name={item.term.toUpperCase()}
|
||||||
|
stroke={CHART_COLORS[item.originalIndex % CHART_COLORS.length]}
|
||||||
|
strokeWidth={4}
|
||||||
|
dot={{ r: 5, strokeWidth: 2, fill: '#fff' }}
|
||||||
|
activeDot={{ r: 8 }}
|
||||||
|
isAnimationActive={true}
|
||||||
|
animationDuration={1500}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Step3FinalGraph;
|
||||||
@@ -1 +1,6 @@
|
|||||||
export const API_BASE_URL = import.meta.env.VITE_API_URL;
|
export const API_BASE_URL = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
|
export const CHART_COLORS = [
|
||||||
|
'#ef4444', '#f59e0b', '#10b981', '#3b82f6',
|
||||||
|
'#d946ef', '#06b6d4', '#8b5cf6', '#f43f5e', '#6366f1'
|
||||||
|
];
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import Step1BaseScale from '../components/editor/Step1BaseScale';
|
import Step1BaseScale from '../components/editor/Step1BaseScale';
|
||||||
import Step2FuzzyModeling from '../components/editor/Step2FuzzyModeling';
|
import Step2FuzzyModeling from '../components/editor/Step2FuzzyModeling';
|
||||||
import SubscaleModal from '../components/editor/SubscaleModal';
|
import SubscaleModal from '../components/editor/SubscaleModal';
|
||||||
import { calculateValueFunction, buildFuzzyGraph } from '../services/docService';
|
import { calculateValueFunction, buildFuzzyGraph } from '../services/docService';
|
||||||
|
import Step3FinalGraph from '../components/editor/Step3FinalGraph';
|
||||||
|
|
||||||
export default function DocEditor() {
|
export default function DocEditor() {
|
||||||
const [step, setStep] = useState(1);
|
const [step, setStep] = useState(1);
|
||||||
@@ -125,20 +126,26 @@ export default function DocEditor() {
|
|||||||
const mf = mfDefinitions[term];
|
const mf = mfDefinitions[term];
|
||||||
const sub = subscales[term] || {};
|
const sub = subscales[term] || {};
|
||||||
|
|
||||||
|
const c_start = Number(mf.coreStart.toFixed(4));
|
||||||
|
const c_end = Number(mf.coreEnd.toFixed(4));
|
||||||
|
|
||||||
|
const s_start = Math.min(Number(mf.supportStart.toFixed(4)), c_start);
|
||||||
|
const s_end = Math.max(Number(mf.supportEnd.toFixed(4)), c_end);
|
||||||
|
|
||||||
const leftCount = sub.left ? sub.left.cardsCount : 2;
|
const leftCount = sub.left ? sub.left.cardsCount : 2;
|
||||||
const left_nodes_x = Array.from({ length: leftCount }).map((_, i) =>
|
const left_nodes_x = Array.from({ length: leftCount }).map((_, i) =>
|
||||||
Number((mf.supportStart + (mf.coreStart - mf.supportStart) * (i / (leftCount - 1))).toFixed(4))
|
Number((s_start + (c_start - s_start) * (i / (leftCount - 1))).toFixed(4))
|
||||||
);
|
);
|
||||||
|
|
||||||
const rightCount = sub.right ? sub.right.cardsCount : 2;
|
const rightCount = sub.right ? sub.right.cardsCount : 2;
|
||||||
const right_nodes_x = Array.from({ length: rightCount }).map((_, i) =>
|
const right_nodes_x = Array.from({ length: rightCount }).map((_, i) =>
|
||||||
Number((mf.coreEnd + (mf.supportEnd - mf.coreEnd) * (i / (rightCount - 1))).toFixed(4))
|
Number((c_end + (s_end - c_end) * (i / (rightCount - 1))).toFixed(4))
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
term: term,
|
term: term,
|
||||||
core: [ Number(mf.coreStart.toFixed(4)), Number(mf.coreEnd.toFixed(4)) ],
|
core: [ c_start, c_end ],
|
||||||
support: [ Number(mf.supportStart.toFixed(4)), Number(mf.supportEnd.toFixed(4)) ],
|
support: [ s_start, s_end ],
|
||||||
left_nodes_x: left_nodes_x,
|
left_nodes_x: left_nodes_x,
|
||||||
left_blank_cards: sub.left ? sub.left.blankCards : [0],
|
left_blank_cards: sub.left ? sub.left.blankCards : [0],
|
||||||
right_nodes_x: right_nodes_x,
|
right_nodes_x: right_nodes_x,
|
||||||
@@ -187,13 +194,16 @@ export default function DocEditor() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{step === 3 && (
|
{step === 3 && finalResult && (
|
||||||
<div className="w-full bg-white p-6 rounded-2xl shadow-sm border border-slate-200 flex flex-col items-center">
|
<div className="flex flex-col gap-6 w-full">
|
||||||
<h2 className="text-2xl font-bold text-slate-800 mb-4">Paso 3: Espectro Difuso Final</h2>
|
<Step3FinalGraph data={finalResult} />
|
||||||
<p className="text-slate-600 mb-6">Gráfica construida correctamente. ¡Mira la consola!</p>
|
|
||||||
<button onClick={() => setStep(2)} className="text-slate-500 hover:text-blue-600 underline">
|
<button
|
||||||
← Volver a editar
|
onClick={() => console.log("Lógica para guardar")}
|
||||||
</button>
|
className="mt-4 px-8 py-3 bg-blue-600 text-white font-bold rounded-xl shadow-md hover:bg-blue-700 w-fit self-end transition-all"
|
||||||
|
>
|
||||||
|
Finalizar y Guardar
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user