Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 2d09a76
Author: Derek McIntire <[email protected]>
Date:   Tue Jan 21 19:44:27 2025 -0500

    Fix tsconfig.json and Lint errors (#290)

    * fixed all ts errors and lint warnings

    * Add comments to tsconfig

    * Don't override includes

    * add stuff

    * change target to ES2020

    * add exclude list

    * remove commented out lines

    * More explicit exclude

    * try include as well as exclude

    * Letting claude give it a try

    * I dont think build is a hidden directory

    * undo claude

    * Type check working now

    * fix eslint comment as well

    * Add noUncheckedIndexAccess

commit ab29024
Author: Derek McIntire <[email protected]>
Date:   Tue Jan 14 20:42:54 2025 -0500

    223 heatload graph (#288)

    * 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

commit 98edbe0
Author: AdamFinkle <[email protected]>
Date:   Mon Dec 16 15:22:38 2024 -0500

    Fixed errors that CI workflow caught (#285)
  • Loading branch information
AdamFinkle committed Jan 22, 2025
1 parent 7a156cb commit 90b693b
Show file tree
Hide file tree
Showing 28 changed files with 556 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { tr } from '@faker-js/faker'
import { useState, useEffect } from 'react'
import { type z } from 'zod'
import { type UsageDataSchema, type BillingRecordsSchema } from '#/types/types.ts'
Expand All @@ -17,8 +18,6 @@ import HelpCircle from './assets/help-circle.svg'
import NonHeatingUsage from './assets/NonHeatingUsage.svg'
import NotAllowedInCalculations from './assets/NotAllowedInCalculations.svg'

import { tr } from '@faker-js/faker'

// type NaturalGasBillRecord = z.infer<typeof NaturalGasBillRecordZod>
// const naturalGasBillRecord01: NaturalGasBillRecord = {
// periodStartDate: new Date('12/08/2017'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,189 @@
import { useMemo } from 'react'
import {
ScatterChart,
Scatter,
ComposedChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Label,
Scatter,
} from 'recharts'
import { SummaryOutputSchema } from '../../../../../../types/types.ts'
import { Icon } from '../../../icon.tsx'
import { HeatLoadGrid } from '../HeatLoadGrid.tsx'
import {
COLOR_GREY_LIGHT,
COLOR_ORANGE,
COLOR_BLUE,
} from '../constants.ts'
import {
calculateAvgHeatLoad,
calculateMaxHeatLoad,
} from '../utility/heat-load-calculations.ts'
import { buildHeatLoadGraphData } from '../utility/build-heat-load-graph-data.ts'
import { HeatLoadGraphToolTip } from './HeatLoadGraphToolTip.tsx'
import { CustomLegend } from './HeatLoadGraphLegend.tsx'
import { DESIGN_SET_POINT } from '../../../../../global_constants.ts'

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])

/**
* 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>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
COLOR_ORANGE,
COLOR_BLUE,
} from '../constants.ts'

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>
);
};
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>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import { HeatLoad } from './Graphs/HeatLoad.tsx'
import { WholeHomeUAComparison } from './Graphs/WholeHomeUAComparison.tsx'

export function Graphs() {
interface GraphsProps {
heatLoadSummaryOutput: any;
}

export function Graphs({ heatLoadSummaryOutput }: GraphsProps) {
const fuel_type = 'Natural Gas'
const titleClassTailwind = 'text-5xl font-extrabold tracking-wide'
const componentMargin = 'mt-10'
Expand All @@ -14,7 +18,7 @@ export function Graphs() {
Fuel Type
{fuel_type}
{/* <AnalysisHeader /> */}
<HeatLoad />
<HeatLoad heatLoadSummaryOutput={heatLoadSummaryOutput} />
<WholeHomeUAComparison />
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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): JSX.Element => {
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>
)
}
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'
Loading

0 comments on commit 90b693b

Please sign in to comment.