Skip to content

Commit 6354989

Browse files
committed
lightweight charts working
1 parent 9cfbb46 commit 6354989

7 files changed

Lines changed: 173 additions & 140 deletions

File tree

ethernet-view/package-lock.json

Lines changed: 57 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ethernet-view/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"react-window": "^1.8.8",
3030
"vite-plugin-svgr": "^2.4.0",
3131
"vite-tsconfig-paths": "^4.0.5",
32-
"zustand": "^4.4.6"
32+
"zustand": "^4.4.6",
33+
"zustymiddleware": "^1.2.0"
3334
},
3435
"devDependencies": {
3536
"@testing-library/jest-dom": "^5.16.5",
Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,74 @@
1-
import { NumericMeasurementInfo } from "common";
1+
import { MeasurementId, NumericMeasurementInfo, UpdateFunction, useGlobalTicker } from "common";
2+
import { ColorType, IChartApi, ISeriesApi, UTCTimestamp, createChart } from "lightweight-charts";
3+
import { useEffect, useRef } from "react";
4+
5+
type DataSerieAndUpdater = Map<MeasurementId, [ISeriesApi<"Line">, UpdateFunction]>;
26

37
interface Props {
48
measurements: NumericMeasurementInfo[];
59
}
610

11+
const CHART_HEIGHT = 300;
12+
713
export const ChartCanvas = ({ measurements }: Props) => {
814

15+
const chartContainerRef = useRef<HTMLDivElement>(null);
16+
const chart = useRef<IChartApi | null>(null);
17+
const chartDataSeries = useRef<DataSerieAndUpdater>(new Map());
18+
19+
useEffect(() => {
20+
const handleResize = () => {
21+
if (chartContainerRef.current)
22+
if(chart)
23+
chart.current?.applyOptions({ width: chartContainerRef.current.clientWidth });
24+
};
25+
26+
const resizeObserver = new ResizeObserver(handleResize);
27+
if (chartContainerRef.current)
28+
resizeObserver.observe(chartContainerRef.current);
29+
30+
if (chartContainerRef.current) {
31+
if(chart)
32+
chart.current = createChart(chartContainerRef.current, {
33+
layout: {
34+
background: { type: ColorType.Solid, color: "white" },
35+
textColor: "black",
36+
},
37+
width: chartContainerRef.current.clientWidth,
38+
height: CHART_HEIGHT,
39+
timeScale: {
40+
timeVisible: true,
41+
secondsVisible: true,
42+
fixLeftEdge: true,
43+
fixRightEdge: true,
44+
lockVisibleTimeRangeOnResize: true,
45+
}
46+
});
47+
}
48+
49+
return () => {
50+
resizeObserver.disconnect();
51+
chart.current?.remove();
52+
}
53+
}, []);
54+
55+
useEffect(() => {
56+
chartDataSeries.current.clear();
57+
measurements.forEach((measurement) => {
58+
if(chart.current)
59+
chartDataSeries.current.set(measurement.id, [chart.current.addLineSeries({color: measurement.color}), measurement.getUpdate]);
60+
});
61+
}, [measurements.length])
62+
63+
useGlobalTicker(() => {
64+
const now = Date.now() / 1000 as UTCTimestamp;
65+
chartDataSeries.current?.forEach((serieAndUpdater) => {
66+
const [DataSerie, Updater] = serieAndUpdater;
67+
DataSerie.update({ time: now, value: Updater() })
68+
});
69+
});
70+
971
return (
10-
<div>
11-
{measurements.map((measurement) => (
12-
<div key={measurement.id}>{measurement.id}</div>
13-
))}
14-
</div>
72+
<div ref={chartContainerRef}></div>
1573
);
1674
};
Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
import styles from "./ChartElement.module.scss";
22
import { AiOutlineCloseCircle } from 'react-icons/ai'
3-
import { useMeasurementsStore } from 'common';
4-
import { ChartInfo, useChartStore } from '../ChartStore';
3+
import { MeasurementId, NumericMeasurementInfo, useMeasurementsStore } from 'common';
4+
import { ChartId } from '../ChartMenu';
55
import { ChartCanvas } from './ChartCanvas/ChartCanvas';
66
import { ChartLegend } from './ChartLegend/ChartLegend';
7-
import { useCallback } from "react";
7+
import { memo, useState } from "react";
88

99
type Props = {
10-
chart: ChartInfo;
10+
chartId: ChartId;
11+
initialMeasurement: NumericMeasurementInfo;
12+
removeChart(chartId: ChartId): void;
1113
};
1214

1315
// React component that keeps the chart render and measurements represented on it.
14-
export const ChartElement = ({ chart }: Props) => {
15-
const removeChart = useChartStore((state) => state.removeChart);
16-
const addMeasurementToChart = useChartStore((state) => state.addMeasurementToChart);
17-
const getNumericMeasurementInfo = useMeasurementsStore((state) => state.getNumericMeasurementInfo);
16+
export const ChartElement = memo(({ chartId, initialMeasurement, removeChart }: Props) => {
17+
const [measurementsInChart, setMeasurementsInChart] = useState<NumericMeasurementInfo[]>([initialMeasurement]);
18+
const getNumericMeasurementInfo = useMeasurementsStore(state => state.getNumericMeasurementInfo);
1819

19-
const handleDrop = useCallback((ev: React.DragEvent<HTMLDivElement>) => {
20+
const handleDrop = (ev: React.DragEvent<HTMLDivElement>) => {
2021
ev.stopPropagation();
2122
const id = ev.dataTransfer.getData("id");
2223
const measurementInfo = getNumericMeasurementInfo(id);
23-
addMeasurementToChart(chart.chartId, measurementInfo);
24-
}, []);
24+
setMeasurementsInChart([...measurementsInChart, measurementInfo]);
25+
};
2526

2627
return (
2728
<div
@@ -34,11 +35,18 @@ export const ChartElement = ({ chart }: Props) => {
3435
<AiOutlineCloseCircle
3536
size={30}
3637
cursor="pointer"
37-
onClick={() => removeChart(chart.chartId)}
38+
onClick={() => removeChart(chartId)}
39+
/>
40+
<ChartCanvas
41+
measurements={measurementsInChart}
42+
/>
43+
<ChartLegend
44+
chartId={chartId}
45+
measurements={measurementsInChart}
46+
removeMeasurementFromChart={(measurementId: MeasurementId) => setMeasurementsInChart(measurementsInChart.filter(measurement => measurement.id !== measurementId))}
47+
removeChart={removeChart}
3848
/>
39-
<ChartCanvas measurements={chart.measurements} />
40-
<ChartLegend chartId={chart.chartId} measurements={chart.measurements} />
4149
</div>
4250
</div>
4351
);
44-
};
52+
});

ethernet-view/src/components/ChartMenu/ChartElement/ChartLegend/ChartLegend.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
import styles from "./ChartLegend.module.scss";
2-
import { useCallback, useEffect, useRef } from "react";
2+
import { useEffect, useRef } from "react";
33
import { MeasurementId, NumericMeasurementInfo } from "common";
4-
import { ChartId, useChartStore } from "components/ChartMenu/ChartStore";
4+
import { ChartId } from "components/ChartMenu/ChartStore";
55

66
interface Props {
77
chartId: ChartId;
88
measurements: NumericMeasurementInfo[];
9+
removeMeasurementFromChart(measurementId: MeasurementId): void;
10+
removeChart(chartId: ChartId): void;
911
}
1012

11-
export const ChartLegend = ({ chartId, measurements }: Props) => {
13+
export const ChartLegend = ({ chartId, measurements, removeMeasurementFromChart, removeChart }: Props) => {
14+
1215
const legendRef = useRef<HTMLDivElement>(null);
13-
const charts = useChartStore((state) => state.charts);
14-
const removeMeasurementFromChart = useChartStore((state) => state.removeMeasurementFromChart);
15-
const removeChart = useChartStore((state) => state.removeChart);
16+
17+
const onRemoveMeasurement = (measurementId: MeasurementId) => {
18+
removeMeasurementFromChart(measurementId);
19+
};
1620

17-
const removeMeasurement = useCallback((measurementId: MeasurementId) => {
18-
removeMeasurementFromChart(chartId, measurementId);
19-
if (charts.find((chart) => chart.chartId === chartId)?.measurements.length === 0) {
20-
removeChart(chartId);
21-
}
22-
}, []);
21+
useEffect(() => {
22+
if(measurements.length == 0) removeChart(chartId);
23+
}, [measurements.length])
2324

2425
useEffect(() => {
2526
if (legendRef.current) {
@@ -28,7 +29,7 @@ export const ChartLegend = ({ chartId, measurements }: Props) => {
2829
}
2930
measurements.forEach((measurement) => {
3031
const newChartLegendItem = createChartLegendItem(measurement);
31-
newChartLegendItem.onclick = (_) => removeMeasurement(measurement.id);
32+
newChartLegendItem.onclick = (_) => onRemoveMeasurement(measurement.id);
3233
legendRef.current?.appendChild(newChartLegendItem);
3334
});
3435
}

0 commit comments

Comments
 (0)