From 5304930f2f79b85fe7212aeccfb4aedf2a6ddfeb Mon Sep 17 00:00:00 2001 From: kunkoala Date: Tue, 10 Dec 2024 17:25:48 +0100 Subject: [PATCH] :tada: added alternating stroke color to distinguish values above threshold and below threshold --- frontend/src/DataContext.tsx | 2 +- .../LineChartComponents/LineChart.tsx | 60 ++++++++++++------- .../shared/LineChart/SeriesRange.ts | 43 ++++++++----- frontend/src/types/lineChart.ts | 10 ++++ 4 files changed, 77 insertions(+), 38 deletions(-) diff --git a/frontend/src/DataContext.tsx b/frontend/src/DataContext.tsx index 56143502..fbde3c22 100644 --- a/frontend/src/DataContext.tsx +++ b/frontend/src/DataContext.tsx @@ -540,7 +540,7 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => { visible: true, fill: color(getScenarioPrimaryColor(selectedScenario, theme)), fillOpacity: 0.3, - stroke: {strokeWidth: 0}, + stroke: {strokeWidth: 0, visible: false}, parentId: selectedScenario, }; } diff --git a/frontend/src/components/LineChartComponents/LineChart.tsx b/frontend/src/components/LineChartComponents/LineChart.tsx index 2698be18..090b111c 100644 --- a/frontend/src/components/LineChartComponents/LineChart.tsx +++ b/frontend/src/components/LineChartComponents/LineChart.tsx @@ -364,29 +364,43 @@ export default function LineChart({ }); }, [lineChartData, root, xAxis, yAxis, chartId]); - // Effect to add series range above threshold to chart + // this sets the chart settings above the threshold const seriesRangeSettings = useMemo(() => { - if (!root || !horizontalYAxisThreshold || horizontalYAxisThreshold === 0) { - return {}; + if (!root || !horizontalYAxisThreshold || horizontalYAxisThreshold === 0 || !lineChartData) { + return []; } - return { - threshold: horizontalYAxisThreshold, - fills: { - fill: color(theme.palette.error.main), - fillOpacity: 0.3, - visible: true, - }, - strokes: { - stroke: color(theme.palette.error.main), - strokeWidth: 2, - strokeOpacity: 1, - strokeDasharray: [6, 4], - visible: true, - }, - }; - }, [root, horizontalYAxisThreshold, theme.palette.error.main]); + return lineChartData.map((line) => { + const lineColor = line.stroke.color ?? color(theme.palette.error.main); + const fillColor = line.fill ?? color(theme.palette.error.main); + + return { + serieId: line.serieId ?? '', + threshold: horizontalYAxisThreshold, + fills: { + fill: fillColor, // change the fill of the range above threshold + visible: true, // visibility of the fill + fillOpacity: line.fillOpacity ?? 0.15, + }, + strokes: { + stroke: color(theme.palette.error.main), // change the stroke for points above threshold + strokeWidth: line.stroke.strokeWidth ?? 2, + strokeOpacity: 1, + visible: line.stroke.visible ?? true, // use the one from the lineChartData if it is defined + }, + alternatingStrokes: { + stroke: lineColor, + strokeWidth: 2, + layer: 1, + strokeDasharray: [10, 10], + strokeOpacity: 1, + visible: line.stroke.visible ?? true, + }, + }; + }); + }, [root, horizontalYAxisThreshold, theme.palette.error.main, lineChartData]); + // add linechart and series. The lineSeries will be initialized using the initializer, whereas the seriesRange will be initialized using the seriesRangeSettings useSeriesRange( root, chart, @@ -398,13 +412,17 @@ export default function LineChart({ if (!lineChartData) return; const seriesSettings = lineChartData.find((line) => line.serieId === series.get('id')?.split('_')[1]); - console.log(seriesSettings); + + // set stroke settings from original line chart data below the threshold series.strokes.template.setAll({ strokeWidth: seriesSettings?.stroke.strokeWidth ?? 2, strokeDasharray: seriesSettings?.stroke.strokeDasharray ?? undefined, }); + + // set fill settings from original line chart data below the threshold if (seriesSettings?.fill) { series.fills.template.setAll({ + fill: seriesSettings.fill, fillOpacity: seriesSettings.fillOpacity ?? 1, visible: true, }); @@ -429,7 +447,7 @@ export default function LineChart({ grid: { stroke: color(theme.palette.error.main), // Use dynamic stroke color based on the threshold strokeOpacity: 0.8, - strokeWidth: 1.5, + strokeWidth: 2, visible: true, location: 0, }, diff --git a/frontend/src/components/shared/LineChart/SeriesRange.ts b/frontend/src/components/shared/LineChart/SeriesRange.ts index c1aeff8a..d8123fe5 100644 --- a/frontend/src/components/shared/LineChart/SeriesRange.ts +++ b/frontend/src/components/shared/LineChart/SeriesRange.ts @@ -14,12 +14,14 @@ 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 - }, + yAxis: ValueAxis | null, + rangeSettings: Array<{ + serieId?: string | number; + threshold?: number; + fills?: Partial; + strokes?: Partial; + alternatingStrokes?: Partial; + }>, // Update to accept an array of settings initializer?: (series: LineSeries, i: number) => void ) { // Use the existing `useLineSeriesList` hook to create the series @@ -27,24 +29,33 @@ export function useSeriesRange( // Use `useLayoutEffect` to apply the series range logic after the series are created useLayoutEffect(() => { - if (!seriesList || !yAxis || seriesList.length === 0) return; + if (!seriesList || !yAxis || seriesList.length === 0 || !rangeSettings) return; + + // Iterate over each series passed on and match the corresponding range settings + seriesList.forEach((series: LineSeries, index: number) => { + const rangeSetting = rangeSettings[index]; // Match range settings by index + if (!rangeSetting || !rangeSetting.threshold) 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 + value: rangeSetting.threshold, // Start of the range endValue: 1e6, // End value of the range (adjust as needed) }); - const seriesRange = series.createAxisRange(seriesRangeDataItem); + const aboveThresholdRange = series.createAxisRange(seriesRangeDataItem); + + // Apply the fill settings + if (rangeSetting.fills) { + aboveThresholdRange.fills?.template.setAll(rangeSetting.fills); + } - // Set the fill and stroke properties for the range - if (rangeSettings.fills) { - seriesRange.fills?.template.setAll(rangeSettings.fills); + // Apply the stroke settings + if (rangeSetting.strokes) { + aboveThresholdRange.strokes?.template.setAll(rangeSetting.strokes); } - if (rangeSettings.strokes) { - seriesRange.strokes?.template.setAll(rangeSettings.strokes); + if (rangeSetting.alternatingStrokes) { + const alternatingStrokeSeriesRange = series.createAxisRange(seriesRangeDataItem); + alternatingStrokeSeriesRange.strokes?.template.setAll(rangeSetting.alternatingStrokes); } }); diff --git a/frontend/src/types/lineChart.ts b/frontend/src/types/lineChart.ts index 3231cf99..21d3eb64 100644 --- a/frontend/src/types/lineChart.ts +++ b/frontend/src/types/lineChart.ts @@ -60,6 +60,16 @@ export interface LineChartData { * The dash array for the stroke. */ strokeDasharray?: number[]; + + /** + * The opacity of the stroke. + */ + strokeOpacity?: number; + + /** + * visibility of the stroke + */ + visible?: boolean; }; /**