diff --git a/packages/app/src/components/time-series-chart/logic/series.ts b/packages/app/src/components/time-series-chart/logic/series.ts index 8bbbd580b2..1c29fbb654 100644 --- a/packages/app/src/components/time-series-chart/logic/series.ts +++ b/packages/app/src/components/time-series-chart/logic/series.ts @@ -186,6 +186,7 @@ export interface StackedBarSeriesDefinition extends shortLabel?: string; color: string; fillOpacity?: number; + order: number; } /** diff --git a/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts b/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts index 64cd45edcb..1d633ff2d1 100644 --- a/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts +++ b/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts @@ -20,7 +20,7 @@ export function getVariantBarChartData(variants: NlVariants) { return EMPTY_VALUES; } - const sortedVariants = variants.values.sort((a, b) => b.last_value.order - a.last_value.order); + const sortedVariants = variants.values.sort((a, b) => a.last_value.order - b.last_value.order); const firstVariantInList = sortedVariants.shift(); diff --git a/packages/app/src/domain/variants/data-selection/get-variant-orders.ts b/packages/app/src/domain/variants/data-selection/get-variant-orders.ts new file mode 100644 index 0000000000..d3a6a5d4eb --- /dev/null +++ b/packages/app/src/domain/variants/data-selection/get-variant-orders.ts @@ -0,0 +1,21 @@ +import { NlVariants } from '@corona-dashboard/common'; +import { OrderMatch } from '~/domain/variants/data-selection/types'; +import { isDefined } from 'ts-is-present'; + +export const getVariantOrders = (variants: NlVariants): OrderMatch[] => { + if (!isDefined(variants) || !isDefined(variants.values)) { + return []; + } + + const order = variants.values + .sort((a, b) => a.last_value.order - b.last_value.order) + .map((variant) => { + const variantOrder = variant.last_value.order; + return { + variant: variant.variant_code, + order: variantOrder, + }; + }); + + return order; +}; diff --git a/packages/app/src/domain/variants/data-selection/index.ts b/packages/app/src/domain/variants/data-selection/index.ts index 7589614493..4e7e3b7772 100644 --- a/packages/app/src/domain/variants/data-selection/index.ts +++ b/packages/app/src/domain/variants/data-selection/index.ts @@ -2,3 +2,4 @@ export * from './get-variant-bar-chart-data'; export * from './get-archived-variant-chart-data'; export * from './get-variant-order-colors'; export * from './get-variant-table-data'; +export * from './get-variant-orders'; diff --git a/packages/app/src/domain/variants/data-selection/types.ts b/packages/app/src/domain/variants/data-selection/types.ts index 682bbc6651..79a9f442d1 100644 --- a/packages/app/src/domain/variants/data-selection/types.ts +++ b/packages/app/src/domain/variants/data-selection/types.ts @@ -9,6 +9,11 @@ export type ColorMatch = { color: string; }; +export type OrderMatch = { + variant: VariantCode; + order: number; +}; + export type VariantTableData = ReturnType; export type VariantChartValue = { diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index 983bb63249..3d4b7cdaf7 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -17,18 +17,33 @@ const hasMetricProperty = (config: any): config is { metricProperty: string } => * @param selectionOptions - Currently selected variants */ export const reorderAndFilter = (context: TooltipData, selectionOptions: P[]) => { - const hasSelectedMetrics = context.config.length !== selectionOptions.length; // Check whether the user has selected any variants from the interactive legend. + const filterSelectionActive = context.config.length !== selectionOptions.length; // Check whether the user has selected any variants from the interactive legend. - /* Filter out any variants that have an occcurrence value of 0 */ - const filteredValues = Object.fromEntries( + // If the user has no filter selected -> Filter out any variants that have an occurrence value of 0 + const valuesFromContext = Object.fromEntries( Object.entries(context.value).filter(([key, value]) => (key.includes('occurrence') ? value !== 0 && isPresent(value) && !isNaN(Number(value)) : value)) ) as VariantChartValue; - /* Rebuild tooltip data context with filtered values */ + // If the user has no filter selected -> Filter out configs that do not contain a 'metricProperty' key OR have an occurrence value of 0 + const filteredConfigs = context.config + .filter((value) => { + return !hasMetricProperty(value) || valuesFromContext[value.metricProperty] || filterSelectionActive; + }) + .filter(isDefined); + + // Sort variants by occurrence, always put 'other variants' at the end + const sortedConfigs = filteredConfigs.sort((a: any, b: any) => { + if (a.metricProperty.includes('other_variants')) return 1; + if (b.metricProperty.includes('other_variants')) return -1; + if (context.value[a.metricProperty] === context.value[b.metricProperty]) return b.order - a.order; + return context.value[b.metricProperty] - context.value[a.metricProperty]; + }); + + // Generate filtered tooltip context const reorderContext = { ...context, - config: [...context.config.filter((value) => !hasMetricProperty(value) || filteredValues[value.metricProperty] || hasSelectedMetrics)].filter(isDefined), - value: !hasSelectedMetrics ? filteredValues : context.value, + config: sortedConfigs, + value: !filterSelectionActive ? valuesFromContext : context.value, }; return reorderContext as TooltipData; diff --git a/packages/app/src/domain/variants/logic/use-bar-config.ts b/packages/app/src/domain/variants/logic/use-bar-config.ts index 966d672936..2ee46bc239 100644 --- a/packages/app/src/domain/variants/logic/use-bar-config.ts +++ b/packages/app/src/domain/variants/logic/use-bar-config.ts @@ -1,4 +1,4 @@ -import { ColorMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; +import { ColorMatch, OrderMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; import { useMemo } from 'react'; import { getValuesInTimeframe, TimeframeOption } from '@corona-dashboard/common'; import { isPresent } from 'ts-is-present'; @@ -25,6 +25,7 @@ export const useBarConfig = ( variantLabels: VariantDynamicLabels, tooltipLabels: VariantsOverTimeGraphText, colors: ColorMatch[], + orders: OrderMatch[], timeframe: TimeframeOption, today: Date ) => { @@ -54,6 +55,8 @@ export const useBarConfig = ( const color = colors.find((variantColors) => variantColors.variant === variantCodeName)?.color; + const order = orders.find((varianOrders) => varianOrders.variant === variantCodeName)?.order; + if (variantDynamicLabel) { const barChartConfigEntry = { type: 'stacked-bar', @@ -62,6 +65,7 @@ export const useBarConfig = ( label: variantDynamicLabel, fillOpacity: 1, shape: 'gapped-area', + order: order, }; barChartConfig.push(barChartConfigEntry as StackedBarSeriesDefinition); @@ -69,5 +73,5 @@ export const useBarConfig = ( }); return barChartConfig; - }, [values, tooltipLabels.tooltip_labels.other_percentage, variantLabels, colors, timeframe, today]); + }, [values, tooltipLabels.tooltip_labels.other_percentage, variantLabels, colors, orders, timeframe, today]); }; diff --git a/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx b/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx index 85116b018c..07aff84a78 100644 --- a/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx +++ b/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx @@ -2,7 +2,7 @@ import { ChartTile, MetadataProps, TimeSeriesChart } from '~/components'; import { Spacer } from '~/components/base'; import { TimeframeOption, TimeframeOptionsList } from '@corona-dashboard/common'; import { useState } from 'react'; -import { ColorMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; +import { ColorMatch, OrderMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; import { useBarConfig } from '~/domain/variants/logic/use-bar-config'; import { InteractiveLegend, SelectOption } from '~/components/interactive-legend'; import { useList } from '~/utils/use-list'; @@ -13,13 +13,14 @@ import { reorderAndFilter } from '~/domain/variants/logic/reorder-and-filter'; import { useIntl } from '~/intl'; interface VariantsStackedBarChartTileProps { - title: string; description: string; - values: VariantChartValue[]; + metadata: MetadataProps; + title: string; tooltipLabels: VariantsOverTimeGraphText; - variantLabels: VariantDynamicLabels; + values: VariantChartValue[]; variantColors: ColorMatch[]; - metadata: MetadataProps; + variantLabels: VariantDynamicLabels; + variantOrders: OrderMatch[]; } const alwaysEnabled: (keyof VariantChartValue)[] = []; @@ -35,12 +36,21 @@ const alwaysEnabled: (keyof VariantChartValue)[] = []; * @param metadata - Metadata block * @constructor */ -export const VariantsStackedBarChartTile = ({ title, description, tooltipLabels, values, variantLabels, variantColors, metadata }: VariantsStackedBarChartTileProps) => { +export const VariantsStackedBarChartTile = ({ + title, + description, + tooltipLabels, + values, + variantLabels, + variantColors, + variantOrders, + metadata, +}: VariantsStackedBarChartTileProps) => { const today = useCurrentDate(); const { commonTexts } = useIntl(); const { list, toggle, clear } = useList(alwaysEnabled); const [variantTimeFrame, setVariantTimeFrame] = useState(TimeframeOption.THIRTY_DAYS); - const barSeriesConfig = useBarConfig(values, variantLabels, tooltipLabels, variantColors, variantTimeFrame, today); + const barSeriesConfig = useBarConfig(values, variantLabels, tooltipLabels, variantColors, variantOrders, variantTimeFrame, today); const text = commonTexts.variants_page; @@ -59,7 +69,7 @@ export const VariantsStackedBarChartTile = ({ title, description, tooltipLabels, timeframeInitialValue={TimeframeOption.THIRTY_DAYS} onSelectTimeframe={setVariantTimeFrame} > - + { @@ -83,6 +86,7 @@ export default function CovidVariantenPage(props: StaticProps