/** CompositeCurvesChart — hot/cold composite curves via Plotly. */ import Plot from 'react-plotly.js'; import { useAnalysisStore } from '../../store/analysisStore'; import { useUIStore } from '../../store/uiStore'; import ChartHelpButton from '../ui/ChartHelpButton'; export default function CompositeCurvesChart() { const pinchResult = useAnalysisStore((s) => s.pinchResult); const showShifted = useAnalysisStore((s) => s.showShifted); const theme = useUIStore((s) => s.theme); const isDark = theme === 'dark'; if (!pinchResult) return null; const diagram = showShifted ? pinchResult.shifted_composite_diagram : pinchResult.composite_diagram; const titleText = showShifted ? 'Shifted Composite Curves' : 'Composite Curves'; const traces: any[] = [ { x: diagram.hot.H, y: diagram.hot.T, mode: 'lines+markers' as const, name: 'Hot streams (Heat sources)', line: { color: 'red', width: 2 }, marker: { size: 6 }, }, { x: diagram.cold.H, y: diagram.cold.T, mode: 'lines+markers' as const, name: 'Cold streams (Heat sinks)', line: { color: 'blue', width: 2 }, marker: { size: 6 }, }, ]; const layout: any = { title: { text: titleText, font: { size: 14, color: isDark ? '#F8FAFC' : '#1A1C1E' } }, xaxis: { title: 'Enthalpy H (kW)', rangemode: 'tozero', gridcolor: isDark ? '#334155' : '#E2E8F0', tickfont: { color: isDark ? '#94A3B8' : '#5F6368' }, titlefont: { color: isDark ? '#F8FAFC' : '#1A1C1E' } }, yaxis: { title: 'Temperature T (°C)', rangemode: 'tozero', gridcolor: isDark ? '#334155' : '#E2E8F0', tickfont: { color: isDark ? '#94A3B8' : '#5F6368' }, titlefont: { color: isDark ? '#F8FAFC' : '#1A1C1E' } }, height: 400, paper_bgcolor: 'rgba(0,0,0,0)', plot_bgcolor: 'rgba(0,0,0,0)', margin: { l: 60, r: 20, t: 40, b: 50 }, legend: { x: 0.01, y: 0.99, xanchor: 'left', yanchor: 'top', font: { color: isDark ? '#F8FAFC' : '#1A1C1E' } }, hovermode: 'closest' as const, shapes: [ { type: 'line', x0: 0, x1: 1, xref: 'paper', y0: pinchResult.pinch_temperature, y1: pinchResult.pinch_temperature, line: { dash: 'dash', color: 'gray', width: 1 }, }, ], annotations: [ { x: 1, xref: 'paper', xanchor: 'right', y: pinchResult.pinch_temperature, text: `Pinch: ${pinchResult.pinch_temperature.toFixed(1)}°C`, showarrow: false, font: { size: 11, color: isDark ? '#60A5FA' : 'gray' }, }, ], }; return (

The horizontal overlap between the Hot (Red) and Cold (Blue) lines represents the maximum heat that can be recovered internally.

The remaining gaps on the left and right show the external heating and cooling utility we still need to provide.

The vertical distance between the curves represents the temperature difference driving the heat transfer.

} />
); }