-
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Use rules engine output to populate heat load graph * update graph record type * run prettier for select files * fix dataKeys * Use correct data and make chart pretty * Graph working, but needs clean up * Clean up and comments * Comments on calculation functions * Add icon, still need to add values underneath chart * restore ws changes to types * Add columns at bottom of chart * Fix reversed average and max in grid * Fix responsiveness issues * Extract utility and data building functions, tool tip and constants * Add comment with link to external calculation docs * Fix tool tip * quick refactor * clean up * refactor calculating min and max for Y axis * set start and end temps once * Add 2f to x axis so tool tip is easier to invoke * review changes to HeatLoad.tsx * All issues except legend and tool type type errors addressed * legend working with valid value for layout * break out legend and fix avg heat load endpoint * Adjust x axis ticks and make design set point a global constant * fix HeatLoadGraphToolTip type error * Remove hard coded data * Add comment to calculateAvgHeatLoadEndPoint * comment out inclusion_override * Fix type errors * re-comment tsconfig
- Loading branch information
1 parent
98edbe0
commit ab29024
Showing
11 changed files
with
484 additions
and
35 deletions.
There are no files selected for viewing
187 changes: 164 additions & 23 deletions
187
heat-stack/app/components/ui/heat/CaseSummaryComponents/Graphs/HeatLoad.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,189 @@ | ||
import React, { useMemo } from 'react' | ||
import { | ||
ScatterChart, | ||
Scatter, | ||
ComposedChart, | ||
Line, | ||
XAxis, | ||
YAxis, | ||
CartesianGrid, | ||
Tooltip, | ||
ResponsiveContainer, | ||
Label, | ||
Scatter, | ||
} from 'recharts' | ||
import { SummaryOutputSchema } from '../../../../../../types/types' | ||
import { Icon } from '../../../icon' | ||
import { HeatLoadGrid } from '../HeatLoadGrid' | ||
import { | ||
COLOR_GREY_LIGHT, | ||
COLOR_ORANGE, | ||
COLOR_BLUE, | ||
} from '../constants' | ||
import { | ||
calculateAvgHeatLoad, | ||
calculateMaxHeatLoad, | ||
} from '../utility/heat-load-calculations' | ||
import { buildHeatLoadGraphData } from '../utility/build-heat-load-graph-data' | ||
import { HeatLoadGraphToolTip } from './HeatLoadGraphToolTip' | ||
import { CustomLegend } from './HeatLoadGraphLegend' | ||
import { DESIGN_SET_POINT } from '../../../../../global_constants' | ||
|
||
const X_AXIS_BUFFER_PERCENTAGE_MAX = 1.3; // 30% buffer | ||
const Y_AXIS_ROUNDING_UNIT = 10000; // Rounding unit for minY and maxY | ||
const Y_AXIS_MIN_VALUE = 0; // Always start the Y axis at 0 | ||
|
||
const roundDownToNearestTen = (n: number) => Math.floor(n / 10) * 10; // Used for determining the start temperature on the X axis | ||
|
||
type HeatLoadProps = { | ||
heatLoadSummaryOutput: SummaryOutputSchema | ||
} | ||
|
||
/** | ||
* HeatLoad component renders a chart displaying the heating system demand based on different outdoor temperatures. | ||
* It includes two lines for the maximum and average heat loads, with scatter points at the design temperature. | ||
* | ||
* @param {HeatLoadProps} props - The props containing heat load data to render the chart. | ||
* @returns {JSX.Element} - The rendered chart component. | ||
*/ | ||
export function HeatLoad({ | ||
heatLoadSummaryOutput, | ||
}: HeatLoadProps): JSX.Element { | ||
const { design_temperature, whole_home_heat_loss_rate } = heatLoadSummaryOutput | ||
const minTemperature = roundDownToNearestTen(design_temperature - 10) // Start temperature rounded down from design temperature for visual clarity | ||
const maxTemperature = DESIGN_SET_POINT + 2 // end the X axis at the DESIGN_SET_POINT plus 2f for visual clarity | ||
|
||
/** | ||
* useMemo to build the HeatLoad graph data. | ||
*/ | ||
const data = useMemo(() => { | ||
return buildHeatLoadGraphData( | ||
heatLoadSummaryOutput, | ||
minTemperature, | ||
DESIGN_SET_POINT, | ||
maxTemperature, | ||
) | ||
}, [heatLoadSummaryOutput]) | ||
Check warning on line 64 in heat-stack/app/components/ui/heat/CaseSummaryComponents/Graphs/HeatLoad.tsx GitHub Actions / ⬣ Heat-Stack - ESLint
|
||
|
||
/** | ||
* useMemo to iterate through the data and calculate the min and max values for the Y axis. | ||
*/ | ||
const { minYValue, maxYValue } = useMemo(() => { | ||
let minValue = Infinity | ||
let maxValue = 0 | ||
|
||
for (const point of data) { | ||
const maxLine = point.maxLine || 0 | ||
const avgLine = point.avgLine || 0 | ||
|
||
minValue = Math.min(minValue, maxLine || Infinity, avgLine || Infinity) | ||
maxValue = Math.max(maxValue, maxLine, avgLine) | ||
} | ||
|
||
// data from Karle Heat Load Analysis Beta 7 2023-07-11 | ||
const data = [ | ||
{ x: 0, y: 74015 }, | ||
{ x: 60.5, y: 10045 }, | ||
{ x: 67, y: 3172 }, | ||
{ x: 70, y: 0 }, | ||
{ x: 8.4, y: 65133 }, | ||
] | ||
// seet min and max Y axis values | ||
const minY = Y_AXIS_MIN_VALUE | ||
const adjustedMaxYValue = maxValue * X_AXIS_BUFFER_PERCENTAGE_MAX; | ||
const maxY = Math.ceil(adjustedMaxYValue / Y_AXIS_ROUNDING_UNIT) * Y_AXIS_ROUNDING_UNIT | ||
|
||
return { minYValue: minY, maxYValue: maxY } | ||
}, [data]) | ||
|
||
export function HeatLoad() { | ||
return ( | ||
<div> | ||
<div className="item-title">Heating System Demand</div> | ||
<div className="min-w-[625px] rounded-lg shadow-lg"> | ||
<span className="mb-4 text-lg font-semibold"> | ||
Heating System Demand | ||
<Icon name="question-mark-circled" className="ps-1" size="md" /> | ||
</span> | ||
|
||
<div className="relative w-full h-[400px]"> | ||
<ResponsiveContainer width="100%" height={400}> | ||
<ScatterChart | ||
<ComposedChart | ||
margin={{ | ||
top: 20, | ||
right: 20, | ||
bottom: 20, | ||
bottom: 50, | ||
left: 100, | ||
}} | ||
data={data} | ||
> | ||
<CartesianGrid /> | ||
<CartesianGrid stroke={COLOR_GREY_LIGHT} strokeDasharray="3 3"/> | ||
|
||
<XAxis | ||
type="number" | ||
dataKey="x" | ||
name=" Outdoor Temperature" | ||
unit="°F" | ||
dataKey="temperature" | ||
name="Outdoor Temperature" | ||
domain={[minTemperature, maxTemperature]} | ||
tickCount={(maxTemperature - minTemperature) / 4 } // Ensure whole number ticks | ||
> | ||
<Label | ||
value="Outdoor Temperature (°F)" | ||
position="bottom" | ||
offset={20} | ||
/> | ||
</XAxis> | ||
|
||
<YAxis type="number" name="Heat Load" domain={[minYValue, maxYValue]}> | ||
<Label | ||
value="Heat Load (BTU/h)" | ||
position="left" | ||
angle={-90} | ||
offset={30} | ||
/> | ||
</YAxis> | ||
|
||
<Tooltip content={<HeatLoadGraphToolTip />} /> | ||
|
||
{/* Line for maximum heat load */} | ||
<Line | ||
type="monotone" | ||
dataKey="maxLine" | ||
stroke={COLOR_ORANGE} | ||
dot={false} | ||
name="Maximum, no internal or solar gain" | ||
/> | ||
|
||
{/* Line for average heat load */} | ||
<Line | ||
type="monotone" | ||
dataKey="avgLine" | ||
stroke={COLOR_BLUE} | ||
dot={false} | ||
name="Average, with internal & solar gain" | ||
/> | ||
|
||
{/* Scatter point for maximum heat load at design temperature */} | ||
<Scatter | ||
dataKey="maxPoint" | ||
fill={COLOR_ORANGE} | ||
name="Maximum at design temperature" | ||
shape="diamond" | ||
legendType="diamond" | ||
/> | ||
<YAxis type="number" dataKey="y" name=" Heat Load" unit=" BTU/h" /> | ||
<Tooltip cursor={{ strokeDasharray: '3 3' }} /> | ||
<Scatter name="Heat Load" data={data} fill="#8884d8" /> | ||
</ScatterChart> | ||
|
||
{/* Scatter point for average heat load at design temperature */} | ||
<Scatter | ||
dataKey="avgPoint" | ||
fill={COLOR_BLUE} | ||
name="Average at design temperature" | ||
shape="diamond" | ||
legendType="diamond" | ||
/> | ||
</ComposedChart> | ||
</ResponsiveContainer> | ||
<CustomLegend /> | ||
</div> | ||
|
||
<HeatLoadGrid | ||
setPoint={DESIGN_SET_POINT} | ||
averageHeatLoad={calculateAvgHeatLoad( | ||
heatLoadSummaryOutput, | ||
design_temperature, | ||
DESIGN_SET_POINT, | ||
)} | ||
maxHeatLoad={calculateMaxHeatLoad( | ||
whole_home_heat_loss_rate, | ||
design_temperature, | ||
DESIGN_SET_POINT, | ||
)} | ||
/> | ||
</div> | ||
) | ||
} |
28 changes: 28 additions & 0 deletions
28
heat-stack/app/components/ui/heat/CaseSummaryComponents/Graphs/HeatLoadGraphLegend.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { | ||
COLOR_ORANGE, | ||
COLOR_BLUE, | ||
} from '../constants' | ||
|
||
export const CustomLegend = () => { | ||
const legendItems = [ | ||
{ name: "Maximum, no internal or solar gain", color: COLOR_ORANGE, type: "line" }, | ||
{ name: "Average, with internal & solar gain", color: COLOR_BLUE, type: "line" }, | ||
{ name: "Maximum at design temperature", color: COLOR_ORANGE, type: "diamond" }, | ||
{ name: "Average at design temperature", color: COLOR_BLUE, type: "diamond" } | ||
]; | ||
|
||
return ( | ||
<div className="absolute top-6 right-6 bg-white border border-gray-200 rounded p-4 shadow-sm"> | ||
{legendItems.map((item, index) => ( | ||
<div key={index} className="flex items-center gap-2 mb-2 last:mb-0"> | ||
{item.type === 'line' ? ( | ||
<div className="w-8 h-0.5" style={{ backgroundColor: item.color }} /> | ||
) : ( | ||
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: item.color }} /> | ||
)} | ||
<span className="text-sm">{item.name}</span> | ||
</div> | ||
))} | ||
</div> | ||
); | ||
}; |
35 changes: 35 additions & 0 deletions
35
heat-stack/app/components/ui/heat/CaseSummaryComponents/Graphs/HeatLoadGraphToolTip.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
type HeatLoadGraphToolTipProps = { | ||
payload?: Array<{ payload: { temperature?: number }; value?: number; name?: string }> | ||
} | ||
|
||
/** | ||
* CustomTooltip renders a tooltip for the heat load chart. | ||
* @param {object} props - The props containing data for the tooltip. | ||
* @returns {JSX.Element} - The rendered tooltip element. | ||
*/ | ||
export const HeatLoadGraphToolTip = ( | ||
props: HeatLoadGraphToolTipProps, | ||
): JSX.Element => { | ||
const { payload } = props | ||
const temperature = payload?.[0]?.payload?.temperature ?? null | ||
const value = payload?.[0]?.value ?? null | ||
const name = payload?.[0]?.name ?? '' | ||
|
||
if (temperature !== null) { | ||
return ( | ||
<div className="tooltip-content rounded border border-gray-300 bg-white p-2"> | ||
<div>{`${Number(value).toLocaleString()} BTU/h`}</div> | ||
<div>{`${temperature}°F ${name.replace('Line', ' Heat Load').replace('Point', ' at Design Temperature')}`}</div> | ||
</div> | ||
) | ||
} | ||
|
||
return ( | ||
<div className="tooltip-content rounded border border-gray-300 bg-white p-2"> | ||
<div>{`${Number(value).toLocaleString()} BTU/h`}</div> | ||
<div> | ||
{name.replace('Line', ' Heat Load').replace('Point', ' at Design Temperature')} | ||
</div> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
heat-stack/app/components/ui/heat/CaseSummaryComponents/HeatLoadGrid.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import React from 'react' | ||
|
||
type HeatLoadGridProps = { | ||
setPoint: number | ||
averageHeatLoad: number | ||
maxHeatLoad: number | ||
} | ||
|
||
/** | ||
* HeatLoadGrid is a stateless functional component that displays key summary data | ||
* in a grid format. The grid includes the set point temperature, maximum heat load, | ||
* and average heat load values. | ||
* | ||
* @component | ||
* @param {HeatLoadGridProps} props - The props for the HeatLoadGrid component. | ||
* @param {number} props.setPoint - The set point temperature in degrees Fahrenheit. | ||
* @param {number} props.averageHeatLoad - The average heat load in BTU/h. | ||
* @param {number} props.maxHeatLoad - The maximum heat load in BTU/h. | ||
* @returns {JSX.Element} - A styled grid displaying the set point, max heat load, and average heat load. | ||
*/ | ||
export const HeatLoadGrid = ({ | ||
setPoint, | ||
averageHeatLoad, | ||
maxHeatLoad, | ||
}: HeatLoadGridProps) => { | ||
return ( | ||
<div className="container mx-auto p-4"> | ||
<div className="grid grid-cols-3 gap-4"> | ||
{/* Grid Item 1 */} | ||
<div className="flex items-center justify-center border-r-2 border-gray-300 p-6"> | ||
<div className="flex flex-col items-center"> | ||
<div className="text-gray-500">Set Point</div> | ||
<div className="font-semibold">{`${setPoint} °F`}</div> | ||
</div> | ||
</div> | ||
|
||
{/* Grid Item 2 */} | ||
<div className="flex items-center justify-center border-r-2 border-gray-300 p-6"> | ||
<div className="flex flex-col items-center"> | ||
<div className="text-gray-500">Max Heat Load</div> | ||
<div className="font-semibold">{`${maxHeatLoad} BTU/h`}</div> | ||
</div> | ||
</div> | ||
|
||
{/* Grid Item 3 */} | ||
<div className="flex items-center justify-center p-6"> | ||
<div className="flex flex-col items-center"> | ||
<div className="text-gray-500">Average Heat Load</div> | ||
<div className="font-semibold">{`${averageHeatLoad} BTU/h`}</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} |
6 changes: 6 additions & 0 deletions
6
heat-stack/app/components/ui/heat/CaseSummaryComponents/constants.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Constants for chart styling | ||
export const COLOR_ORANGE = '#FF5733' | ||
export const COLOR_BLUE = '#8884d8' | ||
export const COLOR_GREY = '#999999' | ||
export const COLOR_GREY_LIGHT = '#cccccc' | ||
export const COLOR_WHITE = '#fff' |
Oops, something went wrong.