import { Avatar, Box, Button, Card, CardHeader, LinearProgress, Theme, Tooltip, Typography } from "@mui/material"; import { ZoomOut } from "@mui/icons-material"; import AreaGraph, { AreaData } from "charts/measurementCharts/AreaGraph"; import MultiLineGraph, { LineData, Point } from "charts/measurementCharts/MultiLineGraph"; import { GetDefaultDateRange } from "common/time/DateRange"; import TimeBar from "common/time/TimeBar"; import UnitMeasurementSummary from "component/UnitMeasurementSummary"; import { useThemeType } from "hooks"; import { Component } from "models"; import { Gate } from "models/Gate"; import { UnitMeasurement } from "models/UnitMeasurement"; import moment, { Moment } from "moment"; import { GetComponentIcon } from "pbHelpers/ComponentType"; import { describeMeasurement, MeasurementDescriber } from "pbHelpers/MeasurementDescriber"; import { useGateAPI, useGlobalState } from "providers"; import React, { useEffect, useState } from "react"; import { avg } from "utils"; import GateFlowGraph from "./GateFlowGraph"; import { makeStyles } from "@mui/styles"; import { cloneDeep } from "lodash"; import GateDeltaTempGraph from "./GateDeltaTempGraph"; interface Props { gate: Gate; display: "analytics" | "sensors"; compMap: Map; device: number; pressure: string; ambient: string; tempChain: string; redKey: string; greenKey: string; // setPCAState: (state: boolean) => void; } const useStyles = makeStyles((theme: Theme) => ({ card: { position: "relative", display: "flex", height: "100%", flexDirection: "column", overflow: "visible" }, cardHeader: { padding: theme.spacing(1), paddingLeft: theme.spacing(2), marginRight: 10 }, avatarIcon: { width: 33, height: 33 } }) ); export default function GateGraphs(props: Props) { const { gate, display, compMap, device, pressure, ambient, tempChain, greenKey, redKey } = props; const [{ as }] = useGlobalState(); const [xDomain, setXDomain] = useState(["dataMin", "dataMax"]); const [zoomed, setZoomed] = useState(false); const defaultDateRange = GetDefaultDateRange(); const [startDate, setStartDate] = useState(defaultDateRange.start); const [endDate, setEndDate] = useState(defaultDateRange.end); const themeType = useThemeType(); const classes = useStyles(); const [{ user }] = useGlobalState(); const [compMeasurements, setCompMeasurements] = useState>( new Map() ); const gateAPI = useGateAPI(); const [loading, setLoading] = useState(false); useEffect(() => { if (loading) return; setLoading(true); let measurementMap: Map = new Map(); gateAPI .listGateMeasurements(gate.key, startDate.toISOString(), endDate.toISOString(), as) .then(resp => { resp.data.measurements.forEach(um => { let unitMeasurement = UnitMeasurement.any(um, user); let entry = measurementMap.get(unitMeasurement.componentId); if (entry) { entry.push(unitMeasurement); } else { measurementMap.set(unitMeasurement.componentId, [unitMeasurement]); } }); setLoading(false); setCompMeasurements(measurementMap); }); }, [gate, endDate, gateAPI, startDate, as]); // eslint-disable-line react-hooks/exhaustive-deps const updateDateRange = (newStartDate: any, newEndDate: any) => { let range = GetDefaultDateRange(); range.start = newStartDate; range.end = newEndDate; setStartDate(newStartDate); setEndDate(newEndDate); }; const zoomOut = () => { setXDomain(["dataMin", "dataMax"]); setZoomed(false); }; const lineGraph = ( unitMeasurement: UnitMeasurement, describer: MeasurementDescriber, averages?: number ) => { if (unitMeasurement.values.length > 0) { let firstTime: Moment | undefined; let lastTime: Moment | undefined; //build line data to pass to graph let lineData: LineData[] = []; let averagedData: LineData[] = []; let valMap: Map = new Map(); unitMeasurement.values.forEach((vals, i) => { let avgVals: Point[] = []; let newLineData: LineData = { timestamp: moment(unitMeasurement.timestamps[i]).valueOf(), points: vals.values.map((val, i) => ({ value: val, node: i })) }; lineData.push(newLineData); if (averages) { vals.values.forEach((val, k) => { let entry = valMap.get(k); if (entry) { entry.push(val); if (entry.length >= averages) { lastTime = moment(unitMeasurement.timestamps[i]); avgVals.push({ node: k, value: avg(entry) }); } } else { valMap.set(k, [val]); firstTime = moment(unitMeasurement.timestamps[i]); } }); } if (firstTime && lastTime) { averagedData.push({ points: avgVals, timestamp: Math.abs(firstTime.diff(lastTime)) / 2 + Math.min(firstTime.valueOf(), lastTime.valueOf()) }); firstTime = undefined; lastTime = undefined; valMap = new Map(); } }); return ( 1 ? unitMeasurement.values[0].values.length : 0} describer={describer} tooltip newXDomain={xDomain} multiGraphZoom={domain => { setXDomain(domain); setZoomed(true); }} multiGraphZoomOut /> ); } }; const areaGraph = ( unitMeasurement: UnitMeasurement, describer: MeasurementDescriber, averages?: number ) => { if (unitMeasurement.timestamps.length > 0) { let firstTime: Moment | undefined; let lastTime: Moment | undefined; //build line data to pass to graph let areaData: AreaData[] = []; let avgData: AreaData[] = []; let maxVals: number[] = []; let minVals: number[] = []; unitMeasurement.values.forEach((val, j) => { let currentMax = Math.min(...val.values); let currentMin = Math.max(...val.values); let dataPoint: AreaData = { timestamp: moment(unitMeasurement.timestamps[j]).valueOf(), value: [currentMax, currentMin] }; if (averages) { if (minVals.length === 0) { firstTime = moment(unitMeasurement.timestamps[j]); } maxVals.push(currentMax); minVals.push(currentMin); if (minVals.length >= averages) { lastTime = moment(unitMeasurement.timestamps[j]); } } if (firstTime && lastTime) { avgData.push({ timestamp: Math.abs(firstTime.diff(lastTime)) / 2 + Math.min(firstTime.valueOf(), lastTime.valueOf()), value: [avg(maxVals), avg(minVals)] }); firstTime = undefined; lastTime = undefined; maxVals = []; minVals = []; } areaData.push(dataPoint); }); return ( { setXDomain(domain); setZoomed(true); }} multiGraphZoomOut /> ); } }; const graphHeader = (comp: Component) => { const componentIcon = GetComponentIcon(comp.settings.type, comp.settings.subtype, themeType); console.log(comp) let measurement = cloneDeep(comp.status.measurement) let umArray = measurement.map(um => UnitMeasurement.create(um, user)) return ( } title={{comp.name()}} subheader={ } /> ); }; const graphCard = (component: Component, unitMeasurements: UnitMeasurement[]) => { return ( {graphHeader(component)} {unitMeasurements.map(um => { if (um.values[0] && um.values[0].values.length > 1) { return areaGraph( um, describeMeasurement(um.type, component.type(), component.subType()), component.settings.smoothingAverages ); } else { return lineGraph( um, describeMeasurement(um.type, component.type(), component.subType()), component.settings.smoothingAverages ); } })} ); } /** * This function creates the charts for the gate page using the MAIN components on the gate, and delta time, it DOES NOT show any other components that could be on the device * @returns list of cards for the charts */ const sensorGraphs = () => { const tempComp = compMap.get(tempChain) let graphs: JSX.Element[] = [] //pressure let pressureComp = compMap.get(pressure) let pressureReadings = compMeasurements.get(pressure) if(pressureComp && pressureReadings){ graphs.push(graphCard(pressureComp, pressureReadings)) } if(tempComp){ graphs.push( ) } //T/H chain let tempReadings = compMeasurements.get(tempChain) if(tempComp && tempReadings){ graphs.push(graphCard(tempComp, tempReadings)) } //ambient let ambientComp = compMap.get(ambient) let ambientReadings = compMeasurements.get(ambient) if (ambientComp && ambientReadings){ graphs.push(graphCard(ambientComp, ambientReadings)) } //green let greenComp = compMap.get(greenKey) let greenReadings = compMeasurements.get(greenKey) if (greenComp && greenReadings){ graphs.push(graphCard(greenComp, greenReadings)) } //red let redComp = compMap.get(redKey) let redReadings = compMeasurements.get(redKey) if (redComp && redReadings){ graphs.push(graphCard(redComp, redReadings)) } return graphs } const analyticGraphs = () => { let tempComp = compMap.get(tempChain) return ( { // setPCAState(state); // }} multiGraphZoom={domain => { setXDomain(domain); setZoomed(true); }} /> {/* add a new chart here for the delta temp over time */} {tempComp && } ); }; const showGraphs = () => { switch (display) { case "sensors": return sensorGraphs(); case "analytics": return analyticGraphs(); default: return Unknown Graph Type Selected; } }; return ( {zoomed && ( )} {loading ? : showGraphs()} ); }