From 5b2fbd354a8a053e5543e3527f7448b2d538bbdb Mon Sep 17 00:00:00 2001 From: kunkoala Date: Wed, 18 Sep 2024 14:18:29 +0200 Subject: [PATCH] :tada: added a new hook for creating series range, and use it with useLineSeries to create all ranges (wonder if this approach worked) --- .../LineChartComponents/LineChart.tsx | 72 +++++++++++-------- .../shared/LineChart/SeriesRange.ts | 61 ++++++++++++++++ 2 files changed, 103 insertions(+), 30 deletions(-) create mode 100644 frontend/src/components/shared/LineChart/SeriesRange.ts diff --git a/frontend/src/components/LineChartComponents/LineChart.tsx b/frontend/src/components/LineChartComponents/LineChart.tsx index 34eed868..e81de7a9 100644 --- a/frontend/src/components/LineChartComponents/LineChart.tsx +++ b/frontend/src/components/LineChartComponents/LineChart.tsx @@ -26,9 +26,8 @@ import useValueAxis from 'components/shared/LineChart/ValueAxis'; import {useDateSelectorFilter} from 'components/shared/LineChart/Filter'; import useDateAxisRange from 'components/shared/LineChart/AxisRange'; import useValueAxisRange from 'components/shared/LineChart/ValueAxisRange'; -import {useLineSeriesList} from 'components/shared/LineChart/LineSeries'; -import {LineSeries} from '@amcharts/amcharts5/.internal/charts/xy/series/LineSeries'; import {LineChartData} from 'types/lineChart'; +import {useSeriesRange} from 'components/shared/LineChart/SeriesRange'; interface LineChartProps { /** Optional unique identifier for the chart. Defaults to 'chartdiv'. */ @@ -86,7 +85,7 @@ export default function LineChart({ exportedFileName = 'Data', yAxisLabel, localization, - horizontalYAxisThreshold = 0, + horizontalYAxisThreshold = undefined, }: LineChartProps): JSX.Element { const {t: defaultT, i18n} = useTranslation(); @@ -364,28 +363,46 @@ export default function LineChart({ }); }, [lineChartData, root, xAxis, yAxis, chartId]); - useLineSeriesList( - root, - chart, - lineChartDataSettings, - useCallback( - (series: LineSeries) => { - if (!lineChartData) return; - const seriesSettings = lineChartData.find((line) => line.serieId === series.get('id')?.split('_')[1]); - series.strokes.template.setAll({ - strokeWidth: seriesSettings?.stroke.strokeWidth ?? 2, - strokeDasharray: seriesSettings?.stroke.strokeDasharray ?? undefined, - }); - if (seriesSettings?.fill) { - series.fills.template.setAll({ - fillOpacity: seriesSettings.fillOpacity ?? 1, - visible: true, - }); - } - }, - [lineChartData] - ) - ); + // useLineSeriesList( + // root, + // chart, + // lineChartDataSettings, + // useCallback( + // (series: LineSeries) => { + // if (!lineChartData) return; + + // const seriesSettings = lineChartData.find((line) => line.serieId === series.get('id')?.split('_')[1]); + + // series.strokes.template.setAll({ + // strokeWidth: seriesSettings?.stroke.strokeWidth ?? 2, + // strokeDasharray: seriesSettings?.stroke.strokeDasharray ?? undefined, + // }); + // if (seriesSettings?.fill) { + // series.fills.template.setAll({ + // fillOpacity: seriesSettings.fillOpacity ?? 1, + // visible: true, + // }); + // } + // }, + // [lineChartData] + // ) + // ); + + // Effect to add series range above threshold to chart + useSeriesRange(root, chart, lineChartDataSettings, yAxis, { + threshold: horizontalYAxisThreshold ?? 0, + fills: { + fill: color(theme.palette.error.main), + fillOpacity: 0.3, + visible: true, + }, + strokes: { + stroke: color(theme.palette.error.main), + strokeWidth: 2, + strokeOpacity: 1, + visible: true, + }, + }); // a horizontal line to limit the y-axis const targetLineSettings = useMemo(() => { @@ -406,11 +423,6 @@ export default function LineChart({ visible: true, location: 0, }, - axisFill: { - fill: color(theme.palette.error.main), // Use dynamic fill color based on the threshold - fillOpacity: 0.5, - visible: true, - }, label: { fill: color(theme.palette.divider), text: `Threshold: ${horizontalYAxisThreshold}`, diff --git a/frontend/src/components/shared/LineChart/SeriesRange.ts b/frontend/src/components/shared/LineChart/SeriesRange.ts new file mode 100644 index 00000000..d8debcd5 --- /dev/null +++ b/frontend/src/components/shared/LineChart/SeriesRange.ts @@ -0,0 +1,61 @@ +import {XYChart} from '@amcharts/amcharts5/.internal/charts/xy/XYChart'; +import {Root} from '@amcharts/amcharts5/.internal/core/Root'; +import {ILineSeriesSettings, LineSeries} from '@amcharts/amcharts5/.internal/charts/xy/series/LineSeries'; +import {useLineSeriesList} from './LineSeries'; +import {useLayoutEffect} from 'react'; +import {AxisRenderer, ValueAxis} from '@amcharts/amcharts5/xy'; +import {IGraphicsSettings} from '@amcharts/amcharts5'; +import {ILineSeriesAxisRange} from '@amcharts/amcharts5/.internal/charts/xy/series/LineSeries'; + +export function useSeriesRange( + root: Root | null, + chart: XYChart | null, + settings: Array, + yAxis: ValueAxis | null, // The yAxis for creating range + rangeSettings: { + threshold: number; // The threshold for the series range + fills: Partial; // Fill color for the range + strokes: Partial; // Stroke color for the range + }, + initializer?: (series: LineSeries, i: number) => void +) { + // Use the existing `useLineSeriesList` hook to create the series + const seriesList = useLineSeriesList(root, chart, settings, initializer); + + // Use `useLayoutEffect` to apply the series range logic after the series are created + useLayoutEffect(() => { + if (!seriesList || !yAxis || seriesList.length === 0) return; + + // Iterate over each series to create and apply the series range + seriesList.forEach((series: LineSeries) => { + const seriesRangeDataItem = yAxis.makeDataItem({ + value: rangeSettings.threshold, // Start of the range + endValue: 1e6, // End value of the range (adjust as needed) + }); + + const seriesRange = series.createAxisRange(seriesRangeDataItem); + + // Set the fill and stroke properties for the range + if (rangeSettings.fills) { + seriesRange.fills?.template.setAll(rangeSettings.fills); + } + + if (rangeSettings.strokes) { + seriesRange.strokes?.template.setAll(rangeSettings.strokes); + } + }); + + return () => { + // Dispose of the ranges when the component unmounts + seriesList.forEach((series: LineSeries) => { + series.axisRanges.each((range: ILineSeriesAxisRange) => { + if (series.axisRanges.contains(range)) { + series.axisRanges.removeValue(range); + } + }); + }); + }; + }, [seriesList, rangeSettings, yAxis]); + + return seriesList ?? null; +}