Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Waveform Refresh Mode #3768

Merged
merged 13 commits into from
Nov 10, 2022
19 changes: 14 additions & 5 deletions src/Components/Facility/Consultations/components/LinePlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const LinePlot = (props: any) => {
yData,
low = null,
high = null,
defaultSpace = true,
defaultSpace,
} = props;
let generalOptions: any = {
grid: {
Expand Down Expand Up @@ -102,19 +102,27 @@ export const LinePlot = (props: any) => {
text: "",
},
grid: {
left: "15px",
right: "30px",
show: false,
borderColor: "transparent",
left: "40px",
right: "20px",
skks1212 marked this conversation as resolved.
Show resolved Hide resolved
},
animation: false,
xAxis: {
...generalOptions.xAxis,
show: false,

},
yAxis: {
...generalOptions.yAxis,
show: false,
show: true,
min: props.yStart,
max: props.yEnd,
splitLine: {
lineStyle: {
color: '#4E4E4E'
}
},
},
toolbox: {
...generalOptions.toolbox,
Expand Down Expand Up @@ -144,12 +152,13 @@ export const LinePlot = (props: any) => {
],
},
},
connectNulls: false,
},
],
};
}

if (!defaultSpace) {
if (defaultSpace != true) {
generalOptions = {
...generalOptions,
grid: {
Expand Down
32 changes: 16 additions & 16 deletions src/Components/TeleIcu/Patient/VitalsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export default function TeleICUPatientVitalsCard({
waveformColor?: string;
waveformName?: string;
waveformDefaultSpace?: boolean;
wavetype?: "STREAM" | "REFRESH";
};

const vitals: VitalType[] = [
Expand All @@ -125,8 +126,9 @@ export default function TeleICUPatientVitalsCard({
liveKey: "pulse-rate",
vitalKey: "pulse",
waveformKey: "II",
waveformColor: "blue",
waveformColor: "limegreen",
waveformName: "ECG",
wavetype: "REFRESH",
},
{
label: <>Blood Pressure</>,
Expand All @@ -142,15 +144,15 @@ export default function TeleICUPatientVitalsCard({
liveKey: "SpO2",
vitalKey: "ventilator_spo2",
waveformKey: "Pleth",
waveformColor: "red",
waveformColor: "yellow",
},
{
label: <>R. Rate</>,
liveKey: "respiratory-rate",
vitalKey: "resp",
waveformKey: "Respiration",
waveformColor: "green",
waveformDefaultSpace: true,
waveformColor: "cyan",
//waveformDefaultSpace: true
},
{
label: <>Temperature (F)</>,
Expand Down Expand Up @@ -184,6 +186,7 @@ export default function TeleICUPatientVitalsCard({
metrics={stats}
classes={"h-[150px]"}
defaultSpace={v.waveformDefaultSpace}
wavetype={v.wavetype || "STREAM"}
/>
) : (
<div className="flex items-center justify-center text-gray-900"></div>
Expand Down Expand Up @@ -214,23 +217,20 @@ export default function TeleICUPatientVitalsCard({
<h2 className="font-bold text-xl md:text-3xl">
{liveReading ||
(vital.vitalKey === "bp"
? `${
patient.last_consultation?.last_daily_round?.bp
.systolic || "--"
}/${
patient.last_consultation?.last_daily_round?.bp
.diastolic || "--"
}`
? `${patient.last_consultation?.last_daily_round?.bp
.systolic || "--"
}/${patient.last_consultation?.last_daily_round?.bp
.diastolic || "--"
}`
: patient.last_consultation?.last_daily_round?.[
vital.vitalKey || ""
]) ||
vital.vitalKey || ""
]) ||
"--"}
</h2>
<div className="text-xs md:text-base">
<i
className={`fas fa-circle text-xs mr-2 ${
liveReading ? "text-green-600" : "text-gray-400"
}`}
className={`fas fa-circle text-xs mr-2 ${liveReading ? "text-green-600" : "text-gray-400"
}`}
/>
{vital.label}
</div>
Expand Down
116 changes: 75 additions & 41 deletions src/Components/TeleIcu/Patient/Waveform.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useEffect, useState } from "react";
import { WAVEFORM_VIEWABLE_LENGTH } from "../../../Common/constants";
import { useEffect, useRef, useState } from "react";
import { LinePlot } from "../../Facility/Consultations/components/LinePlot";

export type WaveformType = {
Expand All @@ -24,20 +23,34 @@ export default function Waveform(props: {
metrics?: boolean;
classes?: string;
defaultSpace?: boolean;
wavetype?: "STREAM" | "REFRESH";
}) {
const wave = props.wave;
const data = wave.data.split(" ").map(Number);
const viewable = data.length;
const [queueData, setQueueData] = useState<number[]>(
Array(WAVEFORM_VIEWABLE_LENGTH).fill(0)
Array(viewable).fill(null)
);
const [refreshData, setRefreshData] = useState<number[]>([]);
const [lastData, setLastData] = useState<number[]>([]);
const [xData, setXData] = useState<number[]>([]);
const [lastStream, setLastStream] = useState(0);
const [rPointer, setRPointer] = useState(0);

const tpf = 4000 / data.length;
const initialRender = useRef(true);

useEffect(() => {
setQueueData(queueData.concat(data));
setXData(Array.from(Array(WAVEFORM_VIEWABLE_LENGTH).keys()));
if (props.wavetype === "STREAM") {
setQueueData(queueData.concat(data));
} else {
if (lastData.length === 0) {
setLastData(data);
} else {
setRefreshData(data);
}
setRPointer(0);
}
setXData(Array.from(Array(viewable).keys()));

let seconds = 1;
setLastStream(0);
Expand All @@ -46,15 +59,52 @@ export default function Waveform(props: {
seconds++;
}, 1000);
return () => clearInterval(timer);
}, [props.wave.data]);
}, [props.wave]);

useEffect(() => {
const timeout = setTimeout(() => {
setQueueData(queueData.slice(1));
}, tpf);
if (props.wavetype === "STREAM") {
if (queueData.length > 30000) {
setQueueData(queueData.slice(-viewable));
} else {
setQueueData(queueData.slice(2));
}
}
}, 6);
return () => clearTimeout(timeout);
}, [queueData]);

useEffect(() => {
let timeout: NodeJS.Timeout;
if (initialRender.current) {
initialRender.current = false;
} else {
timeout = setTimeout(() => {
setRefreshData([
...data.slice(0, rPointer - 25),
...Array(50).fill(null),
...lastData.slice(rPointer - 25),
]);
setRPointer(rPointer + Math.round(viewable / 150));
}, 2);
}
return () => clearTimeout(timeout);
}, [refreshData]);

useEffect(() => {
if (refreshData.length === 0) {
setRefreshData(data);
}
}, [lastData]);

useEffect(() => {
if (rPointer >= data.length) {
setLastData(data);
console.log("last data set");
//setRPointer(0);
}
}, [rPointer]);

return (
<div className="w-full relative">
<div className="text-gray-400 absolute top-0 left-5 text-xs">
Expand All @@ -64,9 +114,13 @@ export default function Waveform(props: {
title={props.title}
name={props.title}
xData={xData}
yData={queueData.slice(0, WAVEFORM_VIEWABLE_LENGTH)}
yStart={Math.min(...queueData)}
yEnd={Math.max(...queueData)}
yData={
props.wavetype === "STREAM"
? queueData.slice(0, viewable)
: refreshData
}
yStart={wave["data-low-limit"]}
yEnd={wave["data-high-limit"]}
classes={props.classes || "h-[90px]"}
type="WAVEFORM"
color={props.color || "green"}
Expand All @@ -75,37 +129,17 @@ export default function Waveform(props: {
<div className="absolute bottom-0 right-5 w-full md:w-[70%]">
{props.metrics && (
<div className="flex flex-row flex-wrap justify-end gap-2 text-[10px] text-gray-400">
<div>
<div>
Lowest:{" "}
{Math.min(...queueData.slice(0, WAVEFORM_VIEWABLE_LENGTH))}
</div>
<div>
Highest:{" "}
{Math.max(...queueData.slice(0, WAVEFORM_VIEWABLE_LENGTH))}
</div>
<div>Stream Length: {data.length}</div>
<div>
Lag:{" "}
{Number(
(tpf * (queueData.length - WAVEFORM_VIEWABLE_LENGTH)) / 1000
).toFixed(2)}{" "}
sec
</div>
</div>
<div>
<div>Buffer Length: {queueData.length}</div>
<div>Flow Rate: {Number(tpf).toFixed(2)} ms</div>
<div>Sampling Rate: {wave["sampling rate"]}</div>
<div>Last response: {lastStream} sec ago</div>
</div>

{queueData.length > WAVEFORM_VIEWABLE_LENGTH && (
<div>Lowest: {Math.min(...queueData.slice(0, viewable))}</div>
<div>Highest: {Math.max(...queueData.slice(0, viewable))}</div>
<div>Stream Length: {data.length}</div>
<div>Buffer Length: {queueData.length}</div>
<div>Sampling Rate: {wave["sampling rate"]}</div>
<div>Lag: {Math.round(queueData.length / viewable)} seconds</div>
<div>Last response: {lastStream} sec ago</div>
{queueData.length > viewable && (
<button
className="text-blue-400"
onClick={() =>
setQueueData(queueData.slice(-1 * WAVEFORM_VIEWABLE_LENGTH))
}
onClick={() => setQueueData(queueData.slice(-1 * viewable))}
>
Clear Buffer
</button>
Expand Down