fix: arreglar leyenda, utilizar colores importados desde config en step2 y step3
This commit is contained in:
@@ -1,11 +1,21 @@
|
|||||||
import Chart from '../membershipFunction/Chart';
|
import Chart from '../membershipFunction/Chart';
|
||||||
import Controls from '../membershipFunction/Controls';
|
import Controls from '../membershipFunction/Controls';
|
||||||
|
import { CHART_COLORS } from '../../config';
|
||||||
|
|
||||||
const COLORS = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6', '#d946ef', '#06b6d4', '#8b5cf6', '#f43f5e', '#6366f1'];
|
export default function Step2FuzzyModeling({
|
||||||
|
baseScale,
|
||||||
export default function Step2FuzzyModeling({baseScale, mfDefinitions, selectedTerm, setSelectedTerm, updateCurrentMf, handleFinalSubmit, onBack, subscales, onOpenSubscale}) {
|
mfDefinitions,
|
||||||
|
selectedTerm,
|
||||||
|
setSelectedTerm,
|
||||||
|
updateCurrentMf,
|
||||||
|
handleFinalSubmit,
|
||||||
|
onBack,
|
||||||
|
subscales,
|
||||||
|
onOpenSubscale
|
||||||
|
}) {
|
||||||
const scaleKeys = Object.keys(baseScale);
|
const scaleKeys = Object.keys(baseScale);
|
||||||
const selectedColor = COLORS[scaleKeys.indexOf(selectedTerm) % COLORS.length] || '#2563eb';
|
|
||||||
|
const selectedColor = CHART_COLORS[scaleKeys.indexOf(selectedTerm) % CHART_COLORS.length] || '#2563eb';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full bg-white p-6 rounded-2xl shadow-sm border border-slate-200 animate-fade-in relative overflow-visible">
|
<div className="w-full bg-white p-6 rounded-2xl shadow-sm border border-slate-200 animate-fade-in relative overflow-visible">
|
||||||
@@ -17,11 +27,18 @@ export default function Step2FuzzyModeling({baseScale, mfDefinitions, selectedTe
|
|||||||
|
|
||||||
<div className="flex flex-wrap justify-center gap-3 mb-6">
|
<div className="flex flex-wrap justify-center gap-3 mb-6">
|
||||||
{scaleKeys.map((name, index) => {
|
{scaleKeys.map((name, index) => {
|
||||||
const color = COLORS[index % COLORS.length];
|
|
||||||
const isSelected = selectedTerm === name;
|
const isSelected = selectedTerm === name;
|
||||||
|
const color = CHART_COLORS[index % CHART_COLORS.length];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button key={name} onClick={() => setSelectedTerm(name)} style={isSelected ? { backgroundColor: color, borderColor: color, color: '#fff' } : { borderColor: color, color: '#475569' }} className={`px-5 py-2 rounded-lg font-bold border-2 transition-all duration-300 flex flex-col items-center shadow-sm hover:shadow-md ${isSelected ? 'transform scale-105' : 'bg-white opacity-80 hover:opacity-100'}`}>
|
<button
|
||||||
<span>{name}</span><span className="text-[10px] font-normal opacity-80">(X: {baseScale[name].toFixed(2)})</span>
|
key={name}
|
||||||
|
onClick={() => setSelectedTerm(name)}
|
||||||
|
style={isSelected ? { backgroundColor: color, borderColor: color, color: '#fff' } : { borderColor: color, color: '#475569' }}
|
||||||
|
className={`px-5 py-2 rounded-lg font-bold border-2 transition-all duration-300 flex flex-col items-center shadow-sm hover:shadow-md ${isSelected ? 'transform scale-105' : 'bg-white opacity-80 hover:opacity-100'}`}
|
||||||
|
>
|
||||||
|
<span>{name}</span>
|
||||||
|
<span className="text-[10px] font-normal opacity-80">(X: {baseScale[name].toFixed(2)})</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -31,7 +48,7 @@ export default function Step2FuzzyModeling({baseScale, mfDefinitions, selectedTe
|
|||||||
baseScale={baseScale}
|
baseScale={baseScale}
|
||||||
mfDefinitions={mfDefinitions}
|
mfDefinitions={mfDefinitions}
|
||||||
selectedTerm={selectedTerm}
|
selectedTerm={selectedTerm}
|
||||||
colors={COLORS}
|
colors={CHART_COLORS}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controls
|
<Controls
|
||||||
@@ -46,11 +63,10 @@ export default function Step2FuzzyModeling({baseScale, mfDefinitions, selectedTe
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="w-full mt-8 flex justify-center">
|
<div className="w-full mt-8 flex justify-center">
|
||||||
<button onClick={handleFinalSubmit} className="px-10 py-3 bg-slate-900 text-white text-lg font-bold rounded-xl shadow-md hover:bg-black hover:shadow-lg transition-all">
|
<button onClick={handleFinalSubmit} className="px-10 py-3 bg-slate-900 text-white text-lg font-bold rounded-xl shadow-md hover:bg-slate-800 transition-colors">
|
||||||
Guardar Todo el Espectro Difuso
|
Guardar Todo el Espectro Difuso
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,85 +1,101 @@
|
|||||||
import {
|
import { useMemo } from 'react';
|
||||||
LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
|
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
|
||||||
} from 'recharts';
|
|
||||||
import { CHART_COLORS } from '../../config';
|
import { CHART_COLORS } from '../../config';
|
||||||
|
|
||||||
const Step3FinalGraph = ({ data }) => {
|
const Step3FinalGraph = ({ data }) => {
|
||||||
if (!data || !data.results) return <p>Cargando gráfico final...</p>;
|
const sortedResults = useMemo(() => {
|
||||||
|
if (!data || !data.results) return [];
|
||||||
|
|
||||||
const resultsWithOriginalIndex = data.results.map((item, index) => ({
|
const withPermanentColors = data.results.map((item, index) => ({
|
||||||
...item,
|
...item,
|
||||||
originalIndex: index
|
color: CHART_COLORS[index % CHART_COLORS.length]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const sortedResults = [...resultsWithOriginalIndex].sort((a, b) => {
|
return withPermanentColors.sort((a, b) => {
|
||||||
const valA = a.core ? a.core[0] : 0;
|
const coreA = Array.isArray(a.core) ? Number(a.core[0]) : 0;
|
||||||
const valB = b.core ? b.core[0] : 0;
|
const coreB = Array.isArray(b.core) ? Number(b.core[0]) : 0;
|
||||||
return valA - valB;
|
return coreA - coreB;
|
||||||
});
|
});
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
if (!data || !data.results) {
|
||||||
|
return <p className="text-center mt-10 text-slate-500">Cargando gráfico final...</p>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-[500px] mt-2 bg-white p-6 rounded-2xl shadow-sm border border-slate-200">
|
<div className="w-full h-[550px] mt-2 bg-white p-6 rounded-2xl shadow-sm border border-slate-200 flex flex-col">
|
||||||
<h3 className="text-2xl font-bold mb-8 text-center text-slate-800">Espectro Difuso Final</h3>
|
<h3 className="text-2xl font-bold mb-4 text-center text-slate-800">Espectro Difuso Final</h3>
|
||||||
|
|
||||||
<ResponsiveContainer width="100%" height="90%">
|
{/* Gráfica */}
|
||||||
<LineChart margin={{ top: 10, right: 30, left: 10, bottom: 40 }}>
|
<div className="flex-1 w-full min-h-[400px]">
|
||||||
<CartesianGrid strokeDasharray="3 3" opacity={0.5} vertical={false} />
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<LineChart margin={{ top: 10, right: 30, left: 10, bottom: 10 }}>
|
||||||
<XAxis
|
<CartesianGrid strokeDasharray="3 3" opacity={0.5} vertical={false} />
|
||||||
dataKey="x"
|
<XAxis
|
||||||
type="number"
|
dataKey="x"
|
||||||
domain={[0, 1]}
|
type="number"
|
||||||
tickCount={11}
|
domain={[0, 1]}
|
||||||
tick={{ fill: '#475569', fontWeight: 600, fontSize: 14 }}
|
tickCount={11}
|
||||||
allowDuplicatedCategory={false}
|
tick={{ fill: '#475569', fontWeight: 600, fontSize: 14 }}
|
||||||
/>
|
allowDuplicatedCategory={false}
|
||||||
<YAxis
|
/>
|
||||||
domain={[0, 1]}
|
<YAxis
|
||||||
tickCount={6}
|
domain={[0, 1]}
|
||||||
tick={{ fill: '#475569', fontSize: 14 }}
|
tickCount={6}
|
||||||
/>
|
tick={{ fill: '#475569', fontSize: 14 }}
|
||||||
|
/>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
formatter={(value, name) => [value.toFixed(3), name]}
|
formatter={(value, name) => [Number(value).toFixed(3), name]}
|
||||||
labelFormatter={(label) => `X: ${Number(label).toFixed(3)}`}
|
labelFormatter={(label) => `X: ${Number(label).toFixed(3)}`}
|
||||||
contentStyle={{ borderRadius: '12px', border: 'none', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)' }}
|
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) => {
|
{sortedResults.map((item) => {
|
||||||
const lineData = [...item.left_nodes, ...item.right_nodes].map(node => ({
|
const lineData = [...(item.left_nodes || []), ...(item.right_nodes || [])].map(node => ({
|
||||||
x: node[0],
|
x: Number(node[0]),
|
||||||
y: node[1]
|
y: Number(node[1])
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Line
|
||||||
|
key={item.term}
|
||||||
|
data={lineData}
|
||||||
|
type="linear"
|
||||||
|
dataKey="y"
|
||||||
|
name={item.term.toUpperCase()}
|
||||||
|
stroke={item.color}
|
||||||
|
strokeWidth={4}
|
||||||
|
dot={{ r: 5, strokeWidth: 2, fill: '#fff' }}
|
||||||
|
activeDot={{ r: 8 }}
|
||||||
|
isAnimationActive={true}
|
||||||
|
animationDuration={1500}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Leyenda */}
|
||||||
|
<div className="flex flex-wrap justify-center gap-x-8 gap-y-3 mt-6 pb-2">
|
||||||
|
{sortedResults.map((item) => (
|
||||||
|
<div key={`legend-${item.term}`} className="flex items-center gap-2">
|
||||||
|
|
||||||
|
<span
|
||||||
|
className="w-3.5 h-3.5 rounded-full shadow-sm"
|
||||||
|
style={{ backgroundColor: item.color }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span
|
||||||
|
className="text-sm font-medium uppercase tracking-wide"
|
||||||
|
style={{ color: item.color }}
|
||||||
|
>
|
||||||
|
{item.term}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user