From fcb860af293bc295276f201d56d139e0f70e200e Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Sun, 13 Feb 2022 08:27:21 +0000 Subject: [PATCH] Memoize x axis, add solar, dust, sleep charts --- client/package.json | 1 + client/src/App.css | 12 +- client/src/App.js | 291 +++++++++++++++++++++++++++++++++++++------- client/yarn.lock | 9 +- 4 files changed, 265 insertions(+), 48 deletions(-) diff --git a/client/package.json b/client/package.json index 6796c13..e5aded1 100644 --- a/client/package.json +++ b/client/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "^12.1.10", "axios": "^0.21.1", "moment": "^2.29.1", + "moment-timezone": "^0.5.34", "react": "^17.0.2", "react-datetime": "^3.1.1", "react-dom": "^17.0.2", diff --git a/client/src/App.css b/client/src/App.css index e914c32..98fb376 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -6,10 +6,16 @@ body { margin: 0; } - .container { - max-width: 40em; - margin: 0 auto 3rem auto; + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-bottom: 3rem; +} + +.chart { + width: 100%; + max-width: 38em; } h2 { diff --git a/client/src/App.js b/client/src/App.js index 10313bd..160120e 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -3,18 +3,20 @@ import { ComposedChart, Bar, Label, LineChart, ReferenceLine, Line, XAxis, YAxis import Datetime from 'react-datetime'; import 'react-datetime/css/react-datetime.css'; import axios from 'axios'; -import moment from 'moment'; +import moment from 'moment-timezone'; import './App.css'; +let tzcache = {}; + const durations = [ - {id: 0, len: 'Day', win: '10m', full: '10 min', delta: [1, 'days']}, - {id: 1, len: 'Day', win: '1h', full: '1 hour', delta: [1, 'days']}, - {id: 2, len: 'Week', win: '1h', full: '1 hour', delta: [7, 'days']}, - {id: 3, len: 'Week', win: '1d', full: '1 day', delta: [7, 'days']}, - {id: 4, len: 'Month', win: '1d', full: '1 day', delta: [1, 'months']}, - {id: 5, len: 'Month', win: '7d', full: '7 day', delta: [1, 'months']}, - {id: 6, len: 'Year', win: '1d', full: '1 day', delta: [1, 'years']}, - {id: 7, len: 'Year', win: '30d', full: '30 day', delta: [1, 'years']}, + {id: 0, len: 'Day', win: '10m', full: '10 min', delta: [1, 'days'], format: 'HH'}, + {id: 1, len: 'Day', win: '1h', full: '1 hour', delta: [1, 'days'], format: 'HH'}, + {id: 2, len: 'Week', win: '1h', full: '1 hour', delta: [7, 'days'], format: 'HH'}, + {id: 3, len: 'Week', win: '1d', full: '1 day', delta: [7, 'days'], format: 'D'}, + {id: 4, len: 'Month', win: '1d', full: '1 day', delta: [1, 'months'], format: 'D'}, + {id: 5, len: 'Month', win: '7d', full: '7 day', delta: [1, 'months'], format: 'D'}, + {id: 6, len: 'Year', win: '1d', full: '1 day', delta: [1, 'years'], format: 'M/D'}, + {id: 7, len: 'Year', win: '30d', full: '30 day', delta: [1, 'years'], format: 'M'}, ]; function useSensor(measurement, name, end, duration) { @@ -38,14 +40,43 @@ function useSensor(measurement, name, end, duration) { }; get(); - const interval = setInterval(get, 30000); - return () => clearInterval(interval); }, [end, duration]); - return [data, loading]; + const memoConvertTZ = (isDST, timeStr, format) => { + if (!timeStr) return '?'; + + let lookUp, result = null; + const date = timeStr.slice(5, 10); + const hours = timeStr.slice(11, 13); + const minutes = timeStr.slice(14, 16); + + if (format === 'HH') { + lookUp = [isDST, hours, format]; + } else { + lookUp = [isDST, date, format]; + } + + if (tzcache[lookUp] != undefined ) { + result = tzcache[lookUp]; + } else { + result = moment(timeStr).tz('America/Edmonton').format(format); + tzcache[lookUp] = result; + } + + if (format === 'HH') { + return result + ':' + minutes; + } else { + return result; + } + }; + + const isDST = end.tz('America/Edmonton').isDST(); + const tickFormatter = (timeStr) => memoConvertTZ(isDST, timeStr, duration.format); + + return [data, loading, tickFormatter]; }; -function ChartContainer({name, data, loading, children, topMargin}) { +function ChartContainer({name, data, lastFormatter, loading, children, topMargin}) { topMargin = topMargin || 5; if (!data) { @@ -58,29 +89,79 @@ function ChartContainer({name, data, loading, children, topMargin}) { ); } + const last = data.length ? lastFormatter(data.slice(-1)[0]) : null; + return ( - <> -

{name} {loading ? 'Loading...' : ''}

+
+

{name}: {loading ? 'Loading...' : last || 'No data'}

{children} - +
); } +function SolarPower({end, duration}) { + const [data, loading, tickFormatter] = useSensor('solar', 'Solar', end, duration); + + return ( + x.actual_total + ' W'} + loading={loading} + topMargin={25} + > + + + + v + ' W'} + labelFormatter={timeStr => moment(timeStr).tz('America/Edmonton').format('ddd MMM DD h:mm A')} + separator=': ' + /> + + + + + + + ); +} + function OutsideTemperature({end, duration}) { - const [data, loading] = useSensor('temperature', 'Outside', end, duration); + const [data, loading, tickFormatter] = useSensor('temperature', 'Outside', end, duration); return ( - + x.temperature_C?.toFixed(1) + ' °C'} + loading={loading} + > moment(timeStr).format('HH:mm')} + tickFormatter={tickFormatter} /> v.toFixed(1) + ' °C'} - labelFormatter={timeStr => moment(timeStr).format('ddd MMM DD h:mm A')} + labelFormatter={timeStr => moment(timeStr).tz('America/Edmonton').format('ddd MMM DD h:mm A')} separator=': ' /> @@ -96,9 +177,7 @@ function OutsideTemperature({end, duration}) {