diff --git a/src/components/D3Diagram.tsx b/src/components/D3Diagram.tsx
index 1e543d4..e53d8f5 100644
--- a/src/components/D3Diagram.tsx
+++ b/src/components/D3Diagram.tsx
@@ -13,6 +13,13 @@ const D3Diagram = ({ data, deviceColorMap }: D3DiagramProps) => {
useEffect(() => {
drawDiagram(d3Ref, data, deviceColorMap);
+
+ const currentD3Ref = d3Ref.current;
+ return () => {
+ if (currentD3Ref && currentD3Ref.firstChild) {
+ currentD3Ref.firstChild.remove();
+ }
+ };
}, [data, deviceColorMap]);
return ;
diff --git a/src/components/Diagram.tsx b/src/components/Diagram.tsx
index ac8af16..c787191 100644
--- a/src/components/Diagram.tsx
+++ b/src/components/Diagram.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from "react";
+import React, { useMemo, useState, useEffect } from "react";
import styled from "styled-components";
import DataType from "../../functions/src/models/DataType";
import GetMeasurementsParams from "../../functions/src/models/GetMeasurementsParams";
@@ -8,11 +8,13 @@ import { FlexColumn } from "../elements/Flex";
import { Heading2 } from "../elements/Typography";
import getMeasurements from "../api/getMeasurements";
import measurementsContainDataPoints from "./measurementsContainDataPoints";
+import Overlay from "../elements/Overlay";
interface DiagramProps {
dataType: DataType;
queryParams: GetMeasurementsParams;
deviceColorMap: Map;
+ autoRefreshPeriod: number;
}
const DiagramContainer = styled(FlexColumn)`
@@ -26,37 +28,62 @@ const DiagramContainer = styled(FlexColumn)`
const DiagramInner = styled.div`
display: flex;
+ position: relative;
flex-grow: 1;
width: 100%;
background-color: ${({ theme }) => theme.palette.background.paper};
`;
-const Diagram = ({ dataType, queryParams, deviceColorMap }: DiagramProps) => {
+const Diagram = ({
+ dataType,
+ queryParams,
+ deviceColorMap,
+ autoRefreshPeriod,
+}: DiagramProps) => {
+ const [updateKey, setUpdateKey] = useState(0);
+ useEffect(() => {
+ let interval: any = 0;
+ if (autoRefreshPeriod !== 0) {
+ interval = setInterval(
+ () => setUpdateKey(Date.now()),
+ autoRefreshPeriod * 1000
+ );
+ } else {
+ clearInterval(interval);
+ }
+ return () => clearInterval(interval);
+ }, [autoRefreshPeriod]);
const query = useMemo(() => {
return getMeasurements(queryParams);
}, [queryParams]);
const { responseData: measurements, error, isLoading } = useQuery({
query,
+ compare: updateKey,
});
+ const canShowRealData =
+ measurements &&
+ measurements.length &&
+ measurementsContainDataPoints(measurements);
+
return (
- {dataType.name} (unit: {dataType.unit})
+ {dataType.name} ({dataType.unit})
+
{isLoading ? (
- "Loading data..."
+ Loading data...
) : error ? (
- "Failed to load data."
- ) : measurements &&
- measurements.length &&
- measurementsContainDataPoints(measurements) ? (
-
- ) : (
- "No data to display."
- )}
+ Error loading data.
+ ) : !canShowRealData ? (
+ No data to display
+ ) : null}
);
diff --git a/src/elements/Overlay.ts b/src/elements/Overlay.ts
new file mode 100644
index 0000000..82ac1c9
--- /dev/null
+++ b/src/elements/Overlay.ts
@@ -0,0 +1,17 @@
+import styled from "styled-components";
+
+const Overlay = styled.div`
+ backdrop-filter: blur(50px);
+ opacity: 0.9;
+ background-color: ${({ theme }) => theme.palette.background.paper};
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+export default Overlay;
diff --git a/src/elements/Switch.tsx b/src/elements/Switch.tsx
new file mode 100644
index 0000000..5228fa1
--- /dev/null
+++ b/src/elements/Switch.tsx
@@ -0,0 +1,65 @@
+import React from "react";
+import styled from "styled-components";
+
+interface SwitchProps {
+ checked: boolean;
+ label: string;
+ onChange: () => void;
+}
+
+const HiddenSwitch = styled.input.attrs({
+ type: "checkbox",
+})`
+ left: -100%;
+ opacity: 0;
+ position: absolute;
+ margin: 0;
+ padding: 0;
+`;
+
+const SwitchContainer = styled.label`
+ position: relative;
+ display: inline-flex;
+ flex-flow: row nowrap;
+ flex-grow: 0;
+ overflow: hidden;
+ padding-top: ${({ theme }) => theme.spacing.d1}px;
+ padding-bottom: ${({ theme }) => theme.spacing.d1}px;
+`;
+
+const SwitchLabel = styled.span`
+ display: block;
+ margin-left: ${({ theme }) => theme.spacing.d1}px;
+`;
+
+const SwitchBackground = styled.span>`
+ display: block;
+ width: ${({ theme }) => theme.spacing.d4 + theme.spacing.d2}px;
+ height: ${({ theme }) => theme.spacing.d2}px;
+ border-radius: ${({ theme }) => theme.shapes.borderRadius}px;
+ background-color: ${({ theme }) => theme.palette.grey[100]};
+`;
+
+const SwitchBullet = styled.span>`
+ display: block;
+ position: absolute;
+ left: ${({ theme, checked }) => (!checked ? "0" : theme.spacing.d4 + "px")};
+ transition: all 0.1s ease-in-out;
+ height: ${({ theme }) => theme.spacing.d2}px;
+ width: ${({ theme }) => theme.spacing.d2}px;
+ border-radius: ${({ theme }) => theme.shapes.borderRadius}px;
+ background-color: ${({ theme, checked }) =>
+ !checked ? theme.palette.grey[400] : theme.palette.primary.main};
+`;
+
+const Switch = ({ checked, label, onChange }: SwitchProps) => (
+
+
+
+
+
+ {label}
+
+);
+
+export default Switch;
diff --git a/src/views/MainView.tsx b/src/views/MainView.tsx
index 6a84d3b..81e97e5 100644
--- a/src/views/MainView.tsx
+++ b/src/views/MainView.tsx
@@ -6,13 +6,19 @@ import TimeRangeRow from "../components/TimeRangeRow";
import { FlexColumn } from "../elements/Flex";
import GridContainer from "../elements/GridContainer";
import Label from "../elements/Label";
+import Switch from "../elements/Switch";
import useQuery from "../hooks/useQuery";
+const REFRESH_FREQUENCY = 10;
+
const MainView = () => {
const { responseData: dataTypes, error, isLoading } = useQuery({
query: getDataTypes,
});
+ // 0 is false
+ const [autoRefreshPeriod, setAutoRefreshPeriod] = useState(0);
+
// empty list state means are all selected
const [selectedDevices, setSelectedDevices] = useState([]);
@@ -46,6 +52,15 @@ const MainView = () => {
setSelectedDevices={setSelectedDevices}
setDeviceColorMap={setDeviceColorMap}
/>
+
+ setAutoRefreshPeriod((currentPeriod) =>
+ !!currentPeriod ? 0 : REFRESH_FREQUENCY
+ )
+ }
+ label={`Automatically refresh measurements every ${REFRESH_FREQUENCY} seconds`}
+ />
{isLoading ? (
@@ -59,6 +74,7 @@ const MainView = () => {
deviceColorMap={deviceColorMap}
key={dataType.id}
dataType={dataType}
+ autoRefreshPeriod={autoRefreshPeriod}
queryParams={{
dataTypes: [dataType.id],
devices: selectedDevices,