/** HPIChart — GCC with diamond markers for selected heat pumps. */
import Plot from 'react-plotly.js';
import { useAnalysisStore } from '../../store/analysisStore';
import { useUIStore } from '../../store/uiStore';
import ChartHelpButton from '../ui/ChartHelpButton';
const HP_COLORS = [
'#00CC96', '#AB63FA', '#FFA15A', '#19D3F3',
'#FF6692', '#B6E880', '#FF97FF', '#FECB52',
];
export default function HPIChart() {
const hpiResult = useAnalysisStore((s) => s.hpiResult);
const pinchResult = useAnalysisStore((s) => s.pinchResult);
const selectedHPTypes = useAnalysisStore((s) => s.selectedHPTypes);
const theme = useUIStore((s) => s.theme);
const isDark = theme === 'dark';
if (!hpiResult || !pinchResult) return null;
const gccH = hpiResult.gcc_data.H;
const gccT = hpiResult.gcc_data.T;
// GCC segment traces
const traces: any[] = [];
const heatCascade = pinchResult.heat_cascade;
for (let i = 0; i < gccH.length - 1; i++) {
let color = 'gray';
if (i < heatCascade.length) {
const dh = heatCascade[i].deltaH ?? 0;
if (dh > 0) color = 'red';
else if (dh < 0) color = 'blue';
}
traces.push({
x: [gccH[i], gccH[i + 1]],
y: [gccT[i], gccT[i + 1]],
mode: 'lines+markers' as const,
line: { color, width: 2 },
marker: { size: 5 },
showlegend: false,
hovertemplate: `T: %{y:.1f}°C
H: %{x:.1f} kW`,
});
}
// Diamond markers for selected HP types
const feasible = hpiResult.integrations.filter((r) => r.feasible);
const allHPNames = feasible.map((r) => r.hp_type);
const displayed = selectedHPTypes.length > 0
? feasible.filter((r) => selectedHPTypes.includes(r.hp_type))
: feasible.slice(0, 1); // default: first
displayed.forEach((hp) => {
const globalIdx = allHPNames.indexOf(hp.hp_type);
const color = HP_COLORS[globalIdx % HP_COLORS.length];
const hpName = hp.hp_type;
if (hp.source_points.H.length > 0) {
traces.push({
x: hp.source_points.H,
y: hp.source_points.T,
mode: 'markers' as const,
marker: {
size: 12,
color,
symbol: 'diamond',
line: { width: 2, color },
},
name: `${hpName} - Source`,
legendgroup: hpName,
hovertemplate: `${hpName} - Source
T: %{y:.1f}°C
Q: %{x:.1f} kW
COP: ${hp.COP?.toFixed(2)}`,
});
}
if (hp.sink_points.H.length > 0) {
traces.push({
x: hp.sink_points.H,
y: hp.sink_points.T,
mode: 'markers' as const,
marker: {
size: 12,
color,
symbol: 'diamond-open',
line: { width: 2, color },
},
name: `${hpName} - Sink`,
legendgroup: hpName,
hovertemplate: `${hpName} - Sink
T: %{y:.1f}°C
Q: %{x:.1f} kW
COP: ${hp.COP?.toFixed(2)}`,
});
}
});
const layout: any = {
title: { text: 'Heat Pump Integration - Grand Composite Curve', font: { size: 14, color: isDark ? '#F8FAFC' : '#1A1C1E' } },
xaxis: {
title: 'Net ΔH (kW)',
gridcolor: isDark ? '#334155' : '#E2E8F0',
tickfont: { color: isDark ? '#94A3B8' : '#5F6368' },
titlefont: { color: isDark ? '#F8FAFC' : '#1A1C1E' }
},
yaxis: {
title: 'Shifted Temperature (°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: 220, r: 20, t: 40, b: 50 },
hovermode: 'closest' as const,
showlegend: true,
legend: {
x: -0.15, y: 1.0,
xanchor: 'right', yanchor: 'top',
font: { size: 10, color: isDark ? '#F8FAFC' : '#1A1C1E' },
itemsizing: 'constant'
},
shapes: [
{
type: 'line',
x0: 0, x1: 1, xref: 'paper',
y0: pinchResult.pinch_temperature,
y1: pinchResult.pinch_temperature,
line: { dash: 'dash', color: 'gray', width: 1 },
},
{
type: 'line',
x0: 0, x1: 0,
y0: 0, y1: 1, yref: 'paper',
line: { color: isDark ? '#94A3B8' : 'black', width: 1 },
opacity: 0.3,
},
],
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 (
Visualizes how a heat pump bridges the temperature gap to lift heat from below the pinch (source) to above the pinch (sink).
The solid diamonds represent the heat pump source, and hollow diamonds represent the sink.
Heat pumps reduce both external heating and cooling demands simultaneously.
>
}
/>
);
}