Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a09a872
add graphs component
justin-phxm Mar 2, 2024
c84ab2f
updated css for graph
justin-phxm Mar 2, 2024
a7d5c00
Remove commented out code and unused variables
justin-phxm Mar 2, 2024
8f3efee
Some styling fixes
ideen1 Mar 5, 2024
616a942
added tooltip to open graph
justin-phxm Mar 9, 2024
41c3cb8
update tooltip to follow mouse
justin-phxm Mar 10, 2024
94a8cf4
Co-authored-by: Ideen <[email protected]>
justin-phxm Mar 16, 2024
95407b0
add graph react to live data
justin-phxm Mar 23, 2024
922649f
add types and color to graph
justin-phxm Mar 23, 2024
8597120
Add Highcharts event for adding points
justin-phxm Mar 23, 2024
4042397
Remove recharts dependency from package.json
justin-phxm Mar 25, 2024
1674de2
Refactor graph-related components for readability
justin-phxm Mar 25, 2024
c09b4d4
added types for highcharts pulse event
justin-phxm Mar 25, 2024
3f21792
rename graphcomponent2
justin-phxm Mar 25, 2024
6d5bc9a
updated size, hide series
justin-phxm Mar 26, 2024
c089d3f
add graphs component
justin-phxm Mar 2, 2024
331e660
updated css for graph
justin-phxm Mar 2, 2024
3376dba
Remove commented out code and unused variables
justin-phxm Mar 2, 2024
91bdf03
Some styling fixes
ideen1 Mar 5, 2024
91183c8
added tooltip to open graph
justin-phxm Mar 9, 2024
a5b1ebf
update tooltip to follow mouse
justin-phxm Mar 10, 2024
5ccfefb
Co-authored-by: Ideen <[email protected]>
justin-phxm Mar 16, 2024
b8983b5
add graph react to live data
justin-phxm Mar 23, 2024
8989017
add types and color to graph
justin-phxm Mar 23, 2024
f582627
Add Highcharts event for adding points
justin-phxm Mar 23, 2024
c592528
Remove recharts dependency from package.json
justin-phxm Mar 25, 2024
813835a
Refactor graph-related components for readability
justin-phxm Mar 25, 2024
e01d32f
added types for highcharts pulse event
justin-phxm Mar 25, 2024
9aa1cf8
rename graphcomponent2
justin-phxm Mar 25, 2024
d6ed635
updated size, hide series
justin-phxm Mar 26, 2024
6daf083
Merge branch 'TEL-95-make-graph-component-to-be-used-in-different-pla…
justin-phxm Apr 9, 2024
2d258e6
Merge branch 'main' of https://github.com/UCSolarCarTeam/Helios-Telem…
justin-phxm May 22, 2024
5ef1f54
fixed type error in PisTransformer
justin-phxm May 22, 2024
a812740
update package lock
justin-phxm May 28, 2024
fd317ff
Merge branch 'main' of https://github.com/UCSolarCarTeam/Helios-Telem…
justin-phxm May 28, 2024
b8b25ff
fixed merge conflicts
justin-phxm May 28, 2024
f7151b8
Merge branch 'main' of https://github.com/UCSolarCarTeam/Helios-Telem…
justin-phxm May 28, 2024
7fe2ffd
debug main
justin-phxm Jun 4, 2024
149b428
Merge branch 'main' of https://github.com/UCSolarCarTeam/Helios-Telem…
justin-phxm Jun 4, 2024
42db8c7
Merge branch 'main' of https://github.com/UCSolarCarTeam/Helios-Telem…
justin-phxm Jun 17, 2024
f33aa65
fix?
justin-phxm Jun 18, 2024
46d8572
Merge branch 'main' into TEL-95-make-graph-component-to-be-used-in-di…
ideen1 Jul 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@
"editor.formatOnSave": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
"editor.formatOnSave": true,
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
41 changes: 41 additions & 0 deletions client/src/components/molecules/GraphMolecules/DraggableGraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { type MutableRefObject, useEffect } from "react";
import Draggable from "react-draggable";
import { IoIosClose } from "react-icons/io";

import { type AnchorElTooltipsRefHandle } from "@/components/molecules/GraphMolecules/FieldGraphTooltip";
import GraphComponent from "@/components/molecules/GraphMolecules/GraphComponent";
import { usePacket } from "@/contexts/PacketContext";

function DraggableGraph({
graphRef,
closeGraph,
graphID,
}: {
graphRef: MutableRefObject<AnchorElTooltipsRefHandle | null>;
graphID: string;
closeGraph: (field: string) => void;
}) {
const { currentPacket } = usePacket();
useEffect(() => {}, [currentPacket, graphRef]);

return (
<Draggable handle="strong">
<div className="box bg-light text-light dark:bg-dark dark:text-dark absolute z-50 w-fit rounded shadow-2xl">
<div className="flex w-full flex-row ">
<strong className="flex grow justify-center ">
<button className=" cursor-all-scroll select-none text-center">
{graphID}
</button>
</strong>
<IoIosClose
onClick={() => closeGraph(graphID)}
size={40}
className=" cursor-pointer select-none text-black dark:text-white"
/>
</div>
<GraphComponent graphData={graphRef.current?.getData()[0]} />
</div>
</Draggable>
);
}
export default DraggableGraph;
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { forwardRef, useCallback, useImperativeHandle, useRef } from "react";

// Random build issue and prettier
import { useGraphOverlay } from "@/contexts/GraphOverlayContext";
import {
type I_PISField,
type I_PISFieldData,
} from "@/objects/PIS/PIS.interface";
import { Tooltip } from "@mui/material";
import type { Instance } from "@popperjs/core";

export type AnchorElTooltipsRefHandle = {
getData: () => I_PISFieldData[];
};

type AnchorElTooltipsProps = {
children: React.ReactNode;
field: I_PISField;
};

const AnchorElTooltips = forwardRef<
AnchorElTooltipsRefHandle,
AnchorElTooltipsProps
>(function AnchorElTooltips(props: AnchorElTooltipsProps, ref) {
const { children, field } = props;
const positionRef = useRef<{ x: number; y: number }>({
x: 0,
y: 0,
});
const popperRef = useRef<Instance>(null);
const areaRef = useRef<HTMLDivElement>(null);

const handleMouseMove = (event: React.MouseEvent) => {
positionRef.current = { x: event.clientX, y: event.clientY };

if (popperRef.current != null) {
void popperRef.current.update();
}
};
const { openNewGraph } = useGraphOverlay();

const getData = useCallback(() => {
return field.data;
}, [field.data]);

useImperativeHandle(ref, () => {
return {
getData,
};
}, [getData]);

return (
<Tooltip
arrow
title={
<button onClick={() => openNewGraph(field.name, ref)}>
Open Graph
</button>
}
slotProps={{
popper: {
modifiers: [
{
name: "offset",
options: {
offset: [0, 14],
},
},
],
},
}}
PopperProps={{
popperRef,
anchorEl: {
getBoundingClientRect: () => {
return new DOMRect(
positionRef.current.x,
areaRef.current!.getBoundingClientRect().y,
0,
0,
);
},
},
}}
>
<div ref={areaRef} onMouseMove={handleMouseMove}>
{children}
</div>
</Tooltip>
);
});

export default AnchorElTooltips;
100 changes: 100 additions & 0 deletions client/src/components/molecules/GraphMolecules/GraphComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import * as Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";
import { useEffect, useRef, useState } from "react";

import { type I_PISFieldData } from "@/objects/PIS/PIS.interface";

export default function GraphComponent({
graphData,
}: {
graphData?: I_PISFieldData;
}) {
const [chartOptions] = useState<Highcharts.Options>({
chart: {
backgroundColor: "#D2D2D2",
type: "spline",
height: 200,
},
xAxis: {
title: { text: "Time" },
},
yAxis: {
title: { text: `Value (${graphData?.unit})` },
},
series: [
{
showInLegend: false,
data: new Array(15).fill(0),
name: undefined,
color: "#9C0534",
type: "spline",
},
],
credits: {
enabled: false,
},
title: {
text: undefined,
},
});
const [chart, setChart] = useState<Highcharts.Chart | null>(null);
const chartComponent = useRef<HighchartsReact.RefObject>(null);
interface PulseSeries extends Highcharts.Series {
pulse: Highcharts.SVGElement;
markerGroup?: Highcharts.SVGElement;
}
interface AddPointEvent {
point: Highcharts.Point;
target: PulseSeries;
}
Highcharts.addEvent(Highcharts.Series, "addPoint", (e: AddPointEvent) => {
const point: Highcharts.Point = e.point,
series: PulseSeries = e.target;

if (!series.pulse) {
series.pulse = series.chart.renderer.circle().add(series.markerGroup);
}
setTimeout(() => {
series.pulse
.attr({
x: series.xAxis.toPixels(point.x, true),
y: series.yAxis.toPixels(point.y as number, true),
// @ts-expect-error: Necessary for accessing 'radius' property.
r: (series.options.marker as { object }).radius as number,
opacity: 1,
fill: series.color,
})
.animate(
{
r: 20,
opacity: 0,
},
{
duration: 1000,
},
);
}, 1);
});

useEffect(() => {
setChart(chartComponent.current && chartComponent.current.chart);
}, []);

const updateSeries = () => {
if (chart) {
chart.series[0].addPoint([graphData?.value], true, true);
}
};
useEffect(() => {
updateSeries();
}, [graphData]);
return (
<div className=" w-80">
<HighchartsReact
ref={chartComponent}
highcharts={Highcharts}
options={chartOptions}
/>
</div>
);
}
26 changes: 26 additions & 0 deletions client/src/components/molecules/GraphMolecules/GraphContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type MutableRefObject } from "react";

import DraggableGraph from "@/components/molecules/GraphMolecules/DraggableGraph";
import { type AnchorElTooltipsRefHandle } from "@/components/molecules/GraphMolecules/FieldGraphTooltip";
import { useGraphOverlay } from "@/contexts/GraphOverlayContext";

export default function GraphContainer() {
const { openGraphs, closeGraph } = useGraphOverlay();

return (
<div className="absolute z-50 m-auto">
{openGraphs.map((graph) => {
return (
<DraggableGraph
graphRef={
graph.ref as MutableRefObject<AnchorElTooltipsRefHandle | null>
}
closeGraph={closeGraph}
graphID={graph.name}
key={graph.name}
/>
);
})}
</div>
);
}
19 changes: 10 additions & 9 deletions client/src/components/transformers/PISTransformer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import React, { useRef } from "react";

import AnchorElTooltips, {
type AnchorElTooltipsRefHandle,
} from "@/components/molecules/GraphMolecules/FieldGraphTooltip";
import { APPUNITS, useAppState } from "@/contexts/AppStateContext";
import type I_PIS from "@/objects/PIS/PIS.interface";
import {
Expand All @@ -9,7 +14,6 @@ import {
type RangeCheckedFieldDataProps = {
fieldData: I_PISFieldData;
};

function FieldUnitsHandler(
unit: UnitType | undefined,
value: string | number | boolean,
Expand Down Expand Up @@ -101,7 +105,6 @@ type FormatStringProps = {
function FormatString(props: FormatStringProps): JSX.Element {
const { fstring, data } = props;
// %s •C (%s) - %s •C (%s)
// console.log("TEST", fstring.split("%s"));

return (
<span>
Expand Down Expand Up @@ -130,7 +133,6 @@ function FieldDataFormatter(props: FieldDataFormatterProps): JSX.Element {

const formatString = (string: string, params: I_PISFieldData[]) => {
// %s •C (%s) - %s •C (%s)
// console.log("TEST", string.split("%s"));
return string
.split("%s")
.map((part, index) => {
Expand All @@ -157,12 +159,9 @@ function FieldDataFormatter(props: FieldDataFormatterProps): JSX.Element {
);
}

type FieldPrinterProps = {
field: I_PISField;
};

function FieldPrinter(props: FieldPrinterProps): JSX.Element {
function FieldPrinter(props: { field: I_PISField }): JSX.Element {
const { field } = props;
const tooltipRef = useRef<AnchorElTooltipsRefHandle | null>(null);
if (
field.fstring !== undefined &&
(field?.fstring.match(/%s/g) || []).length !== field.data.length
Expand All @@ -174,7 +173,9 @@ function FieldPrinter(props: FieldPrinterProps): JSX.Element {
}
return (
<div className="mt-1 flex items-center justify-between text-xs">
{field.name}:
<AnchorElTooltips {...props} ref={tooltipRef}>
<p>{field.name}</p>
</AnchorElTooltips>
<FieldDataFormatter data={field.data} fstring={field.fstring} />
</div>
);
Expand Down
59 changes: 59 additions & 0 deletions client/src/contexts/GraphOverlayContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
type ForwardedRef,
type ReactNode,
createContext,
useContext,
useState,
} from "react";

import { type AnchorElTooltipsRefHandle } from "@/components/molecules/GraphMolecules/FieldGraphTooltip";

interface GraphOverlayContextProps {
children: ReactNode | ReactNode[];
}
interface GraphElement {
name: string;
ref: ForwardedRef<AnchorElTooltipsRefHandle>;
}
interface IGraphOverlayContexttReturn {
openNewGraph: (
name: string,
ref: React.ForwardedRef<AnchorElTooltipsRefHandle>,
) => void;
openGraphs: GraphElement[];
closeGraph: (field: string) => void;
}

const graphOverlayContext = createContext<IGraphOverlayContexttReturn>(
{} as IGraphOverlayContexttReturn,
);

export function GraphOverlayContextProvider({
children,
}: GraphOverlayContextProps): JSX.Element {
const [openGraphs, setOpenGraphs] = useState<GraphElement[]>([]);

const openNewGraph = (
name: string,
ref: ForwardedRef<AnchorElTooltipsRefHandle>,
) => {
setOpenGraphs([...openGraphs, { name, ref }]);
};
const closeGraph = (field: string) => {
setOpenGraphs((prevGraph) =>
prevGraph.filter((graph) => graph.name !== field),
);
};

return (
<graphOverlayContext.Provider
value={{ openNewGraph, openGraphs, closeGraph }}
>
{children}
</graphOverlayContext.Provider>
);
}

export function useGraphOverlay(): IGraphOverlayContexttReturn {
return useContext(graphOverlayContext);
}
Loading