import { useTheme } from "@mui/material"; import { blue, indigo, orange, red } from "@mui/material/colors"; import MaterialChartTooltip from "charts/MaterialChartTooltip"; import { usePrevious } from "hooks"; import moment from "moment"; import { useEffect, useState } from "react"; import { Area, AreaChart, Legend, ReferenceArea, ResponsiveContainer, Tooltip, TooltipProps, XAxis, YAxis } from "recharts"; import { roundTo } from "utils/numbers"; export interface GrainDryingPoint { timestamp: number; dryScore: number; } interface Props { data: GrainDryingPoint[]; showStroke?: boolean; useGradient?: boolean; displayY?: boolean; newXDomain?: number[] | string[]; multiGraphZoom?: (domain: number[] | string[]) => void; multiGraphZoomOut?: boolean; } export default function GrainDryingChart(props: Props) { const { data, showStroke, useGradient, displayY, newXDomain, multiGraphZoom } = props; const prevData = usePrevious(data); const theme = useTheme(); const [offset, setOffset] = useState(0); const now = moment(); const veryDry = red[800]; const dry = orange[500]; const damp = blue[500]; const veryDamp = indigo[800]; const [xDomain, setXDomain] = useState(["dataMin", "dataMax"]); const [refLeft, setRefLeft] = useState(); const [refRight, setRefRight] = useState(); useEffect(() => { if (newXDomain) { setXDomain(newXDomain); } }, [newXDomain]); useEffect(() => { const gradientOffset = () => { const vpdMax = Math.max(...data.map(p => p.dryScore)); const vpdMin = Math.min(...data.map(p => p.dryScore)); if (vpdMax <= 0) { return 0; } if (vpdMin >= 0) { return 1; } return vpdMax / (vpdMax - vpdMin); }; if (!prevData || prevData !== data) { setOffset(gradientOffset()); } }, [data, prevData, now]); const zoom = () => { let newDomain: number[] | string[] = ["dataMin", "dataMax"]; if (refLeft && refRight && refLeft !== refRight) { refLeft < refRight ? (newDomain = [refLeft, refRight]) : (newDomain = [refRight, refLeft]); setRefLeft(undefined); setRefRight(undefined); if (multiGraphZoom) { multiGraphZoom(newDomain); } else { setXDomain(newDomain); } } }; //just commenting this out as this charts zoom will likely never be controlled from inside // const zoomOut = () => { // setXDomain(["dataMin", "dataMax"]); // }; if (data.length <= 1) return null; return ( { if (e) { setRefLeft(e.activeLabel); } }} onMouseMove={(e: any) => { if (e) { setRefRight(e.activeLabel); } }} onMouseUp={() => { setRefLeft(undefined); setRefRight(undefined); zoom(); }}> {displayY && ( { let val = vpd.toFixed(2); return val; }} type="number" // label={{ // value: "Water Content", // angle: -90, // position: "insideLeft", // fill: theme.palette.text.primary // }} domain={["auto", "auto"]} tick={{ fill: theme.palette.text.primary }} /> )} { let t = moment(timestamp); return now.isSame(t, "day") ? t.format("LT") : t.format("MMM DD"); }} scale="time" type="number" tick={{ fill: theme.palette.text.primary }} stroke={theme.palette.divider} interval="preserveStartEnd" /> moment(timestamp).format("lll")} content={(props: TooltipProps) => ( `${roundTo(parseFloat(String(score)), 2).toString()} ${ score === 0 ? "" : score as number > 0 ? " (Drying)" : " (Hydrating)" }` } /> )} /> {refLeft && refRight ? ( ) : null} ); }