@cdc/chart 4.26.6 → 4.26.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONFIG.md +504 -368
- package/dist/cdcchart-CYc-Kayd.es.js +22488 -0
- package/dist/cdcchart-DCKn8NmI.es.js +20695 -0
- package/dist/cdcchart-Dyui9nk_.es.js +45828 -0
- package/dist/cdcchart.js +4 -96498
- package/examples/__data__/vega-remote-data.json +6 -0
- package/examples/dendrogram.json +18 -0
- package/examples/feature/bar/bar-chart-race-annual-change.json +68 -0
- package/examples/feature/heatmap/average-age-categorical.json +2 -2
- package/examples/feature/heatmap/calendar-heatmap.json +2 -2
- package/examples/feature/heatmap/cell-values-bottom-axis.json +2 -2
- package/examples/feature/heatmap/sparse-aggregation.json +2 -2
- package/examples/feature/line/line-chart-race.json +50 -0
- package/examples/feature/sankey/sankey-example-data.json +40 -1441
- package/examples/feature/sankey/sankey_chart_data.csv +9 -20
- package/examples/network.json +31 -0
- package/examples/private/box-plot.json +573 -0
- package/examples/private/custom-color-issue.json +625 -0
- package/examples/private/custom-colors.json +522 -0
- package/examples/private/cutoff.json +10750 -0
- package/examples/private/flueview.json +22051 -0
- package/examples/private/overlay-legend.json +485 -0
- package/examples/private/pie-test.json +469 -0
- package/examples/vega-remote.json +22 -0
- package/package.json +11 -13
- package/src/CdcChart.tsx +2 -2
- package/src/CdcChartComponent.tsx +444 -217
- package/src/_stories/Chart.BarRace.stories.tsx +443 -0
- package/src/_stories/Chart.BoxPlotNumericSort.stories.tsx +189 -0
- package/src/_stories/Chart.BoxPlotStatsParity.stories.tsx +207 -0
- package/src/_stories/Chart.ColorDistribution.stories.tsx +299 -0
- package/src/_stories/Chart.DataCutoff.stories.tsx +147 -0
- package/src/_stories/Chart.DataTableDownloadFilename.stories.tsx +60 -0
- package/src/_stories/Chart.Dendrogram.stories.tsx +373 -0
- package/src/_stories/Chart.Forecast.CILegend.stories.tsx +236 -0
- package/src/_stories/Chart.HeatMap.stories.tsx +170 -4
- package/src/_stories/Chart.Legend.AxisAlign.stories.tsx +119 -0
- package/src/_stories/Chart.LineRace.stories.tsx +149 -0
- package/src/_stories/Chart.Network.stories.tsx +432 -0
- package/src/_stories/Chart.PaletteConversion.Editor.stories.tsx +208 -0
- package/src/_stories/Chart.Patterns.smoke.stories.tsx +31 -0
- package/src/_stories/Chart.PercentageValue.stories.tsx +311 -0
- package/src/_stories/Chart.PieLabels.stories.tsx +49 -0
- package/src/_stories/Chart.RankByValueMutation.stories.tsx +206 -0
- package/src/_stories/Chart.RequiredFields.stories.tsx +681 -0
- package/src/_stories/Chart.Sankey.stories.tsx +417 -0
- package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +47 -0
- package/src/_stories/Chart.SmallMultiplesNumericTileOrder.stories.tsx +137 -0
- package/src/_stories/Chart.TooltipSeriesLabels.stories.tsx +43 -0
- package/src/_stories/Chart.VegaRemoteData.stories.tsx +31 -0
- package/src/_stories/Chart.smoke.stories.tsx +14 -1
- package/src/_stories/ChartAnnotation.Editor.stories.tsx +78 -0
- package/src/_stories/ChartAxisTitles.smoke.stories.tsx +48 -0
- package/src/_stories/ChartBar.Editor.stories.tsx +499 -57
- package/src/_stories/ChartBrush.Editor.stories.tsx +46 -67
- package/src/_stories/ChartBrush.Regression.stories.tsx +135 -0
- package/src/_stories/ChartEditor.Editor.stories.tsx +33 -3
- package/src/_stories/ChartLine.EffectCompatibility.stories.tsx +120 -0
- package/src/_stories/ChartPrefixSuffix.smoke.stories.tsx +28 -1
- package/src/_stories/_mock/annotation_event-line_mock.json +2 -2
- package/src/_stories/_mock/editor-test-configs.json +20 -10
- package/src/_stories/_mock/editor-test-datasets.json +38 -42
- package/src/_stories/_mock/heatmap-average-age-categorical.json +2 -2
- package/src/_stories/_mock/heatmap.json +2 -2
- package/src/_stories/_mock/legend-axis-align-stacked-bar.json +125 -0
- package/src/_stories/_mock/sankey_mock.json +23 -27
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +52 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +639 -139
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +44 -4
- package/src/components/Annotations/components/AnnotationDropdown.tsx +10 -32
- package/src/components/Annotations/helpers/resolveAnnotationLayout.ts +212 -0
- package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +612 -19
- package/src/components/Annotations/tests/AnnotationDropdown.test.tsx +50 -0
- package/src/components/Annotations/tests/resolveAnnotationLayout.test.ts +203 -0
- package/src/components/Axis/BottomAxis.tsx +1 -1
- package/src/components/Axis/Categorical.Axis.tsx +3 -3
- package/src/components/Axis/RightAxis.tsx +21 -13
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -8
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +13 -4
- package/src/components/BarChart/components/BarChart.StackedVertical.test.ts +28 -0
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +30 -26
- package/src/components/BarChart/components/BarChart.Vertical.tsx +38 -28
- package/src/components/BarChart/components/PortionPatternOverlay.tsx +61 -0
- package/src/components/BarChart/components/context.tsx +6 -0
- package/src/components/BarChart/helpers/getBarData.ts +28 -28
- package/src/components/BarChart/helpers/getBarHeights.ts +2 -2
- package/src/components/BarChart/helpers/getPatternUrl.ts +2 -5
- package/src/components/BarChart/helpers/index.ts +8 -0
- package/src/components/BarChart/helpers/portionPattern.ts +243 -0
- package/src/components/BarChart/helpers/tests/addMinimumBarHeights.test.ts +42 -0
- package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +13 -0
- package/src/components/BarChart/helpers/tests/portionPattern.test.ts +280 -0
- package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +202 -0
- package/src/components/BarChart/helpers/useBarChart.ts +60 -60
- package/src/components/BarChartRace/BarChartRace.test.tsx +199 -0
- package/src/components/BarChartRace/BarChartRace.tsx +230 -0
- package/src/components/BarChartRace/BarChartRaceFallback.test.tsx +61 -0
- package/src/components/BarChartRace/BarChartRaceFallback.tsx +48 -0
- package/src/components/BarChartRace/bar-chart-race.css +160 -0
- package/src/components/BarChartRace/helpers.test.ts +114 -0
- package/src/components/BarChartRace/helpers.ts +185 -0
- package/src/components/BarChartRace/index.ts +3 -0
- package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +7 -6
- package/src/components/BoxPlot/BoxPlot.Vertical.tsx +9 -7
- package/src/components/BoxPlot/helpers/index.ts +13 -83
- package/src/components/Brush/BrushSelector.tsx +10 -24
- package/src/components/Brush/MiniChartPreview.tsx +33 -1
- package/src/components/Dendrogram/components/Dendrogram.tsx +374 -0
- package/src/components/Dendrogram/dendrogram.css +113 -0
- package/src/components/Dendrogram/helpers/layoutDendrogram.test.ts +95 -0
- package/src/components/Dendrogram/helpers/layoutDendrogram.ts +56 -0
- package/src/components/Dendrogram/helpers/prepareDendrogramData.test.ts +135 -0
- package/src/components/Dendrogram/helpers/prepareDendrogramData.ts +166 -0
- package/src/components/Dendrogram/helpers/resolveDendrogramLabels.test.ts +196 -0
- package/src/components/Dendrogram/helpers/resolveDendrogramLabels.ts +418 -0
- package/src/components/Dendrogram/index.tsx +1 -0
- package/src/components/Dendrogram/types/index.ts +66 -0
- package/src/components/EditorPanel/EditorPanel.tsx +1111 -805
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +50 -5
- package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.css +10 -0
- package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.tsx +211 -0
- package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +19 -8
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +104 -61
- package/src/components/EditorPanel/components/Panels/Panel.Network.css +9 -0
- package/src/components/EditorPanel/components/Panels/Panel.Network.tsx +202 -0
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +236 -36
- package/src/components/EditorPanel/components/Panels/Panel.Radar.tsx +6 -1
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +89 -105
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +21 -6
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +8 -66
- package/src/components/EditorPanel/components/Panels/RacingControls.test.tsx +131 -0
- package/src/components/EditorPanel/components/Panels/RacingControls.tsx +185 -0
- package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/index.tsx +4 -0
- package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +20 -7
- package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +25 -2
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +5 -4
- package/src/components/EditorPanel/useEditorPermissions.test.tsx +94 -0
- package/src/components/EditorPanel/useEditorPermissions.ts +75 -25
- package/src/components/Forecasting/Forecasting.tsx +16 -7
- package/src/components/HeatMap/components/HeatMap.tsx +511 -178
- package/src/components/HeatMap/heatmap.constants.ts +7 -3
- package/src/components/HeatMap/heatmap.css +101 -2
- package/src/components/HeatMap/helpers/layout.ts +80 -0
- package/src/components/HeatMap/tests/HeatMap.test.tsx +339 -16
- package/src/components/HeatMap/tests/helpers.test.ts +79 -0
- package/src/components/Legend/Legend.Component.tsx +163 -148
- package/src/components/Legend/Legend.Suppression.tsx +3 -3
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +7 -0
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +47 -35
- package/src/components/Legend/helpers/createFormatLabels.test.ts +226 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +45 -51
- package/src/components/LineChart/components/LineChart.Circle.tsx +3 -3
- package/src/components/LineChart/helpers.test.ts +126 -38
- package/src/components/LineChart/helpers.ts +9 -6
- package/src/components/LineChart/index.tsx +71 -27
- package/src/components/LineChart/tests/LineChart.test.tsx +630 -0
- package/src/components/LineChartRace/LineChartRace.test.tsx +275 -0
- package/src/components/LineChartRace/LineChartRace.tsx +134 -0
- package/src/components/LineChartRace/LineChartRaceFallback.tsx +28 -0
- package/src/components/LineChartRace/helpers.test.ts +88 -0
- package/src/components/LineChartRace/helpers.ts +157 -0
- package/src/components/LineChartRace/index.ts +3 -0
- package/src/components/LineChartRace/line-chart-race.css +16 -0
- package/src/components/LinearChart/ValueAxisAnchors.tsx +58 -0
- package/src/components/LinearChart/VisualizationRenderer.tsx +18 -23
- package/src/components/LinearChart/tests/LinearChart.test.tsx +412 -13
- package/src/components/LinearChart/tests/VisualizationRenderer.test.tsx +141 -0
- package/src/components/LinearChart/tests/mockConfigContext.ts +2 -1
- package/src/components/LinearChart.tsx +85 -54
- package/src/components/Network/components/Network.tsx +372 -0
- package/src/components/Network/helpers/layoutNetwork.test.ts +68 -0
- package/src/components/Network/helpers/layoutNetwork.ts +87 -0
- package/src/components/Network/helpers/prepareNetworkData.test.ts +116 -0
- package/src/components/Network/helpers/prepareNetworkData.ts +101 -0
- package/src/components/Network/helpers/resolveNetworkLabels.test.ts +112 -0
- package/src/components/Network/helpers/resolveNetworkLabels.ts +206 -0
- package/src/components/Network/index.tsx +3 -0
- package/src/components/Network/network.css +107 -0
- package/src/components/Network/types/index.ts +56 -0
- package/src/components/PairedBarChart.jsx +5 -10
- package/src/components/PairedBarChart.test.tsx +71 -0
- package/src/components/PieChart/PieChart.tsx +121 -13
- package/src/components/PieChart/helpers/labelPlacement.test.ts +88 -0
- package/src/components/PieChart/helpers/labelPlacement.ts +95 -0
- package/src/components/RacingChartRenderer.tsx +44 -0
- package/src/components/Regions/components/Regions.test.tsx +179 -0
- package/src/components/Regions/components/Regions.tsx +104 -69
- package/src/components/Regions/index.tsx +2 -3
- package/src/components/Sankey/components/Sankey.tsx +264 -437
- package/src/components/Sankey/helpers/getSankeyTooltip.ts +12 -0
- package/src/components/Sankey/helpers/prepareSankeyData.test.ts +71 -0
- package/src/components/Sankey/helpers/prepareSankeyData.ts +90 -0
- package/src/components/Sankey/sankey.scss +57 -116
- package/src/components/Sankey/types/index.ts +41 -4
- package/src/components/ScatterPlot/ScatterPlot.jsx +28 -12
- package/src/components/ScatterPlot/ScatterPlot.test.tsx +60 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +12 -12
- package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +7 -5
- package/src/components/raceTiming.ts +18 -0
- package/src/data/initial-state.js +79 -31
- package/src/helpers/applyChartTypeContract.ts +71 -0
- package/src/helpers/axisLabelFontSize.ts +2 -2
- package/src/helpers/boxPlotStats.ts +60 -0
- package/src/helpers/bumpChartTooltip.ts +2 -1
- package/src/helpers/calculateHorizontalBarCategoryLabelWidth.test.ts +37 -0
- package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +3 -2
- package/src/helpers/calculateRightYAxisWidth.ts +60 -0
- package/src/helpers/categoryOrder.ts +60 -0
- package/src/helpers/colorAssignmentHelpers.ts +2 -2
- package/src/helpers/createNewChartConfig.ts +56 -0
- package/src/helpers/dataDrivenYAxisCategories.ts +18 -0
- package/src/helpers/forecastLegend.ts +88 -0
- package/src/helpers/getBoxPlotConfig.ts +26 -38
- package/src/helpers/getChartTypeDefaultPalette.ts +29 -0
- package/src/helpers/getColorCodeCategoryColorMap.ts +26 -0
- package/src/helpers/getColorScale.ts +31 -22
- package/src/helpers/getComboChartConfig.ts +0 -1
- package/src/helpers/getDynamicYAxisCategories.ts +69 -0
- package/src/helpers/getExcludedData.ts +0 -1
- package/src/helpers/getHasBoundarySuppression.ts +4 -3
- package/src/helpers/getMinMax.ts +11 -8
- package/src/helpers/getNewRuntime.ts +4 -3
- package/src/helpers/getPiePercent.ts +3 -3
- package/src/helpers/getStackedSeriesMax.ts +51 -0
- package/src/helpers/getV21ChartDistributionColors.ts +57 -0
- package/src/helpers/handleRankByValue.ts +15 -15
- package/src/helpers/isConvertLineToBarGraph.ts +2 -2
- package/src/helpers/seriesColumnSettings.ts +31 -3
- package/src/helpers/sizeHelpers.ts +4 -5
- package/src/helpers/smallMultiplesHelpers.ts +10 -13
- package/src/helpers/tests/applyChartTypeContract.test.ts +37 -0
- package/src/helpers/tests/boxPlotStats.test.ts +31 -0
- package/src/helpers/tests/bumpChartTooltip.test.ts +29 -0
- package/src/helpers/tests/calculateRightYAxisWidth.test.ts +105 -0
- package/src/helpers/tests/categoryOrder.test.ts +57 -0
- package/src/helpers/tests/countNumOfTicks.test.ts +11 -0
- package/src/helpers/tests/createNewChartConfig.test.ts +182 -0
- package/src/helpers/tests/getBoxPlotConfig.test.ts +70 -0
- package/src/helpers/tests/getColorCodeCategoryColorMap.test.ts +113 -0
- package/src/helpers/tests/getColorScale.test.ts +226 -1
- package/src/helpers/tests/getDynamicYAxisCategories.test.ts +61 -0
- package/src/helpers/tests/getMinMax.test.ts +41 -0
- package/src/helpers/tests/getStackedSeriesMax.test.ts +26 -0
- package/src/helpers/tests/handleRankByValue.test.ts +55 -37
- package/src/helpers/tests/seriesColumnSettings.test.ts +83 -0
- package/src/helpers/tests/smallMultiplesHelpers.test.ts +37 -1
- package/src/helpers/tests/tooltipHelpers.test.ts +80 -0
- package/src/helpers/tooltipHelpers.ts +16 -0
- package/src/hooks/tests/useRightAxis.test.tsx +143 -2
- package/src/hooks/tests/useScales.test.tsx +3 -6
- package/src/hooks/tests/useTooltip.test.tsx +484 -0
- package/src/hooks/usePrefersReducedMotion.ts +22 -0
- package/src/hooks/useReduceData.ts +4 -36
- package/src/hooks/useRightAxis.ts +19 -26
- package/src/hooks/useScales.ts +15 -0
- package/src/hooks/useTooltip.tsx +106 -71
- package/src/scss/main.scss +74 -2
- package/src/store/chart.reducer.ts +4 -4
- package/src/test/CdcChart.dataTable.test.tsx +582 -14
- package/src/test/CdcChart.dendrogram.test.tsx +277 -0
- package/src/test/CdcChart.finalization.test.tsx +143 -0
- package/src/test/CdcChart.network.test.tsx +271 -0
- package/src/types/ChartConfig.ts +91 -54
- package/src/types/ChartContext.ts +5 -0
- package/src/types/Horizon.ts +1 -1
- package/LICENSE +0 -201
- package/dist/cdcchart-BWVIUcAF.es.js +0 -4802
- package/src/_stories/Chart.Sankey.smoke.stories.tsx +0 -62
- package/src/components/Sankey/components/ColumnList.tsx +0 -19
- package/src/components/Sankey/helpers/getSankeyTooltip.tsx +0 -34
- package/src/components/Sankey/useSankeyAlert.tsx +0 -60
- package/src/data/legacy-defaults.ts +0 -18
- package/src/helpers/ensureSpecialChartAxisTypes.ts +0 -11
- package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +0 -30
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { getBoxPlotConfig } from '../getBoxPlotConfig'
|
|
4
|
+
import { ChartConfig } from '../../types/ChartConfig'
|
|
5
|
+
|
|
6
|
+
const createBoxPlotConfig = (): ChartConfig =>
|
|
7
|
+
({
|
|
8
|
+
xAxis: {
|
|
9
|
+
dataKey: 'Group'
|
|
10
|
+
},
|
|
11
|
+
series: [
|
|
12
|
+
{
|
|
13
|
+
dataKey: 'Score'
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
dataFormat: {
|
|
17
|
+
roundTo: 0
|
|
18
|
+
}
|
|
19
|
+
} as ChartConfig)
|
|
20
|
+
|
|
21
|
+
describe('getBoxPlotConfig', () => {
|
|
22
|
+
it('sorts generated value arrays numerically for numeric strings', () => {
|
|
23
|
+
const data = [
|
|
24
|
+
{ Group: 'Group A', Score: '1' },
|
|
25
|
+
{ Group: 'Group A', Score: '2' },
|
|
26
|
+
{ Group: 'Group A', Score: '3' },
|
|
27
|
+
{ Group: 'Group A', Score: '10' },
|
|
28
|
+
{ Group: 'Group A', Score: '20' },
|
|
29
|
+
{ Group: 'Group A', Score: '100' }
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const [plots] = getBoxPlotConfig(createBoxPlotConfig(), data)
|
|
33
|
+
|
|
34
|
+
expect(plots[0].values).toEqual([1, 2, 3, 10, 20, 100])
|
|
35
|
+
expect(plots[0].columnNonOutliers).toEqual([1, 2, 3, 10, 20])
|
|
36
|
+
expect(plots[0].columnOutliers).toEqual([100])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('parses formatted numeric strings before sorting', () => {
|
|
40
|
+
const data = [
|
|
41
|
+
{ Group: 'Group A', Score: '1,234.5' },
|
|
42
|
+
{ Group: 'Group A', Score: '20' },
|
|
43
|
+
{ Group: 'Group A', Score: '3' }
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
const [plots] = getBoxPlotConfig(createBoxPlotConfig(), data)
|
|
47
|
+
|
|
48
|
+
expect(plots[0].values).toEqual([3, 20, 1234.5])
|
|
49
|
+
expect(plots[0].columnCount).toBe(3)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('ignores blank, null, and nonnumeric values when generating box plot stats', () => {
|
|
53
|
+
const data = [
|
|
54
|
+
{ Group: 'Group A', Score: '1' },
|
|
55
|
+
{ Group: 'Group A', Score: '' },
|
|
56
|
+
{ Group: 'Group A', Score: null },
|
|
57
|
+
{ Group: 'Group A', Score: undefined },
|
|
58
|
+
{ Group: 'Group A', Score: 'n/a' },
|
|
59
|
+
{ Group: 'Group A', Score: '2' },
|
|
60
|
+
{ Group: 'Group A', Score: '3' }
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
const [plots] = getBoxPlotConfig(createBoxPlotConfig(), data)
|
|
64
|
+
|
|
65
|
+
expect(plots[0].values).toEqual([1, 2, 3])
|
|
66
|
+
expect(plots[0].columnCount).toBe(3)
|
|
67
|
+
expect(plots[0].columnNonOutliers).toEqual([1, 2, 3])
|
|
68
|
+
expect(plots[0].columnOutliers).toEqual([])
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { ChartConfig } from '../../types/ChartConfig'
|
|
3
|
+
import { getColorCodeCategoryColorMap } from '../getColorCodeCategoryColorMap'
|
|
4
|
+
|
|
5
|
+
const buildConfig = (
|
|
6
|
+
colorCode = 'Group',
|
|
7
|
+
paletteOverrides: Partial<ChartConfig['general']['palette']> = {}
|
|
8
|
+
): ChartConfig =>
|
|
9
|
+
({
|
|
10
|
+
visualizationType: 'Bar',
|
|
11
|
+
general: {
|
|
12
|
+
palette: {
|
|
13
|
+
name: 'sequential_blue',
|
|
14
|
+
version: '2.0',
|
|
15
|
+
...paletteOverrides
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
legend: { colorCode }
|
|
19
|
+
} as ChartConfig)
|
|
20
|
+
|
|
21
|
+
const colorPalettes = {
|
|
22
|
+
sequential_blue: Array.from({ length: 9 }, (_, index) => `#00000${index}`),
|
|
23
|
+
sequential_bluereverse: Array.from({ length: 9 }, (_, index) => `#00000${8 - index}`),
|
|
24
|
+
qualitative_standard: Array.from({ length: 9 }, (_, index) => `qualitative-${index}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe('getColorCodeCategoryColorMap', () => {
|
|
28
|
+
it('assigns colors to unique categories in encounter order', () => {
|
|
29
|
+
const result = getColorCodeCategoryColorMap(
|
|
30
|
+
buildConfig(),
|
|
31
|
+
[{ Group: 'Group A' }, { Group: 'Group B' }, { Group: 'Group A' }],
|
|
32
|
+
colorPalettes
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
expect(Array.from(result.entries())).toEqual([
|
|
36
|
+
['Group A', '#000000'],
|
|
37
|
+
['Group B', '#000001']
|
|
38
|
+
])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('uses the 2.1 chart distribution for two categories in a sequential palette', () => {
|
|
42
|
+
const result = getColorCodeCategoryColorMap(
|
|
43
|
+
buildConfig('Group', { version: '2.1' }),
|
|
44
|
+
[{ Group: 'Group A' }, { Group: 'Group B' }, { Group: 'Group A' }],
|
|
45
|
+
colorPalettes
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
expect(Array.from(result.entries())).toEqual([
|
|
49
|
+
['Group A', '#000004'],
|
|
50
|
+
['Group B', '#000008']
|
|
51
|
+
])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('uses the full V2 chart distribution for three categories in a sequential palette', () => {
|
|
55
|
+
const result = getColorCodeCategoryColorMap(
|
|
56
|
+
buildConfig('Group', { version: '2.1' }),
|
|
57
|
+
[{ Group: 'Group A' }, { Group: 'Group B' }, { Group: 'Group C' }],
|
|
58
|
+
colorPalettes
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
expect(Array.from(result.values())).toEqual(['#000000', '#000004', '#000008'])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('uses the V2 qualitative distribution for color-coded categories', () => {
|
|
65
|
+
const result = getColorCodeCategoryColorMap(
|
|
66
|
+
buildConfig('Group', { name: 'qualitative_standard', version: '2.1' }),
|
|
67
|
+
[{ Group: 'Group A' }, { Group: 'Group B' }, { Group: 'Group C' }],
|
|
68
|
+
colorPalettes
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
expect(Array.from(result.values())).toEqual(['qualitative-0', 'qualitative-4', 'qualitative-6'])
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('uses the V2 sequential colors in reverse order for a reversed palette', () => {
|
|
75
|
+
const rows = [{ Group: 'Group A' }, { Group: 'Group B' }]
|
|
76
|
+
const reversed = getColorCodeCategoryColorMap(
|
|
77
|
+
buildConfig('Group', {
|
|
78
|
+
name: 'sequential_bluereverse',
|
|
79
|
+
version: '2.1',
|
|
80
|
+
isReversed: true
|
|
81
|
+
}),
|
|
82
|
+
rows,
|
|
83
|
+
colorPalettes
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
expect(Array.from(reversed.values())).toEqual(['#000008', '#000004'])
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('preserves raw palette order for custom palettes', () => {
|
|
90
|
+
const rows = [{ Group: 'Group A' }, { Group: 'Group B' }]
|
|
91
|
+
const custom = getColorCodeCategoryColorMap(
|
|
92
|
+
buildConfig('Group', { version: '2.1', customColors: ['#111111', '#222222'] }),
|
|
93
|
+
rows,
|
|
94
|
+
colorPalettes
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
expect(Array.from(custom.values())).toEqual(['#111111', '#222222'])
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('repeats the palette when there are more categories than colors', () => {
|
|
101
|
+
const result = getColorCodeCategoryColorMap(
|
|
102
|
+
buildConfig(),
|
|
103
|
+
[{ Group: 'Group A' }, { Group: 'Group B' }, { Group: 'Group C' }],
|
|
104
|
+
colorPalettes
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
expect(Array.from(result.values())).toEqual(['#000000', '#000001', '#000002'])
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('returns an empty map without a color-code column', () => {
|
|
111
|
+
expect(getColorCodeCategoryColorMap(buildConfig(''), [{ Group: 'Group A' }], colorPalettes).size).toBe(0)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
import { getColorScale } from '../getColorScale'
|
|
3
3
|
import { ChartConfig } from '../../types/ChartConfig'
|
|
4
|
+
import { colorPalettesChartV2 } from '@cdc/core/data/colorPalettes'
|
|
5
|
+
import {
|
|
6
|
+
colorblindColorDistribution,
|
|
7
|
+
chartV21ColorDistribution,
|
|
8
|
+
divergentColorDistribution,
|
|
9
|
+
qualitativeStandardColorDistribution,
|
|
10
|
+
v2ColorDistribution
|
|
11
|
+
} from '@cdc/core/helpers/palettes/colorDistributions'
|
|
4
12
|
|
|
5
13
|
const buildConfig = (overrides: Partial<ChartConfig> = {}): ChartConfig =>
|
|
6
14
|
({
|
|
@@ -177,6 +185,63 @@ describe('getColorScale series color assignments', () => {
|
|
|
177
185
|
expect(colorScale('Series C')).toBe('#303030')
|
|
178
186
|
})
|
|
179
187
|
|
|
188
|
+
it('fills invalid customColorsOrdered entries with black', () => {
|
|
189
|
+
const colorScale = getColorScale(
|
|
190
|
+
buildConfig({
|
|
191
|
+
general: {
|
|
192
|
+
palette: {
|
|
193
|
+
name: 'qualitative_standard',
|
|
194
|
+
version: '2.0',
|
|
195
|
+
customColorsOrdered: ['', '#222222', 'whyte']
|
|
196
|
+
}
|
|
197
|
+
} as any
|
|
198
|
+
})
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
expect(colorScale('Series A')).toBe('#000000')
|
|
202
|
+
expect(colorScale('Series B')).toBe('#222222')
|
|
203
|
+
expect(colorScale('Series C')).toBe('#000000')
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('uses black when saved customColors are all invalid', () => {
|
|
207
|
+
const colorScale = getColorScale(
|
|
208
|
+
buildConfig({
|
|
209
|
+
general: {
|
|
210
|
+
palette: {
|
|
211
|
+
name: 'qualitative_standard',
|
|
212
|
+
version: '2.0',
|
|
213
|
+
customColors: ['', 'whyte']
|
|
214
|
+
}
|
|
215
|
+
} as any
|
|
216
|
+
})
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
expect(colorScale('Series A')).toBe('#000000')
|
|
220
|
+
expect(colorScale('Series B')).toBe('#000000')
|
|
221
|
+
expect(colorScale('Series C')).toBe('#000000')
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('uses black when the named palette cannot be resolved', () => {
|
|
225
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
226
|
+
const colorScale = getColorScale(
|
|
227
|
+
buildConfig({
|
|
228
|
+
general: {
|
|
229
|
+
palette: {
|
|
230
|
+
name: 'unknown_palette',
|
|
231
|
+
version: '2.0'
|
|
232
|
+
}
|
|
233
|
+
} as any
|
|
234
|
+
})
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
expect(warn).toHaveBeenCalledWith('Palette "unknown_palette" not found, falling back to black')
|
|
238
|
+
expect(colorScale('Series A')).toBe('#000000')
|
|
239
|
+
expect(colorScale('Series B')).toBe('#000000')
|
|
240
|
+
expect(colorScale('Series C')).toBe('#000000')
|
|
241
|
+
|
|
242
|
+
warn.mockRestore()
|
|
243
|
+
})
|
|
244
|
+
|
|
180
245
|
it('falls back to the named palette when customColors is empty', () => {
|
|
181
246
|
const colorScale = getColorScale(
|
|
182
247
|
buildConfig({
|
|
@@ -195,3 +260,163 @@ describe('getColorScale series color assignments', () => {
|
|
|
195
260
|
expect(colorScale('Series C')).toBe('#5A8E3F')
|
|
196
261
|
})
|
|
197
262
|
})
|
|
263
|
+
|
|
264
|
+
const buildDistributionConfig = (
|
|
265
|
+
numberOfSeries: number,
|
|
266
|
+
paletteName = 'qualitative_standard',
|
|
267
|
+
paletteVersion: '2.0' | '2.1' = '2.0',
|
|
268
|
+
overrides: Partial<ChartConfig> = {}
|
|
269
|
+
) => {
|
|
270
|
+
const seriesKeys = Array.from({ length: numberOfSeries }, (_, index) => `series_${index + 1}`)
|
|
271
|
+
const seriesLabelsAll = seriesKeys.map((_, index) => `Series ${index + 1}`)
|
|
272
|
+
|
|
273
|
+
return buildConfig({
|
|
274
|
+
general: {
|
|
275
|
+
palette: {
|
|
276
|
+
name: paletteName,
|
|
277
|
+
version: paletteVersion
|
|
278
|
+
}
|
|
279
|
+
} as any,
|
|
280
|
+
series: seriesKeys.map((dataKey, index) => ({ dataKey, name: seriesLabelsAll[index], type: 'Line' })) as any,
|
|
281
|
+
runtime: {
|
|
282
|
+
seriesKeys,
|
|
283
|
+
seriesLabels: Object.fromEntries(seriesKeys.map((key, index) => [key, seriesLabelsAll[index]])),
|
|
284
|
+
seriesLabelsAll
|
|
285
|
+
} as any,
|
|
286
|
+
...overrides
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const getScaleColors = (config: ChartConfig) => {
|
|
291
|
+
const scale = getColorScale(config)
|
|
292
|
+
return config.runtime.seriesLabelsAll.map(label => scale(label))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
describe('getColorScale distribution profiles', () => {
|
|
296
|
+
it.each(Object.keys(qualitativeStandardColorDistribution).map(Number))(
|
|
297
|
+
'uses released colorblind colors for %i series with palette version 2.0',
|
|
298
|
+
count => {
|
|
299
|
+
const expected = colorblindColorDistribution[count].map(index => colorPalettesChartV2.qualitative_standard[index])
|
|
300
|
+
|
|
301
|
+
expect(getScaleColors(buildDistributionConfig(count))).toEqual(expected)
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
it.each(Object.keys(qualitativeStandardColorDistribution).map(Number))(
|
|
306
|
+
'uses improved colorblind colors for %i series with palette version 2.1',
|
|
307
|
+
count => {
|
|
308
|
+
const expected = qualitativeStandardColorDistribution[count].map(
|
|
309
|
+
index => colorPalettesChartV2.qualitative_standard[index]
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
expect(getScaleColors(buildDistributionConfig(count, 'qualitative_standard', '2.1'))).toEqual(expected)
|
|
313
|
+
}
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
it('uses the V2 forward colors in reverse order for a reversed palette', () => {
|
|
317
|
+
const count = 5
|
|
318
|
+
const expected = qualitativeStandardColorDistribution[count]
|
|
319
|
+
.map(index => colorPalettesChartV2.qualitative_standard[index])
|
|
320
|
+
.reverse()
|
|
321
|
+
|
|
322
|
+
expect(getScaleColors(buildDistributionConfig(count, 'qualitative_standardreverse', '2.1'))).toEqual(expected)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('uses the chart 2.1 distribution for a two-series sequential palette', () => {
|
|
326
|
+
const expected = chartV21ColorDistribution[2].map(index => colorPalettesChartV2.sequential_blue[index])
|
|
327
|
+
|
|
328
|
+
expect(getScaleColors(buildDistributionConfig(2, 'sequential_blue', '2.1'))).toEqual(expected)
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
it('preserves the released sequential distribution for palette version 2.0', () => {
|
|
332
|
+
const expected = v2ColorDistribution[2].map(index => colorPalettesChartV2.sequential_blue[index])
|
|
333
|
+
|
|
334
|
+
expect(getScaleColors(buildDistributionConfig(2, 'sequential_blue', '2.0'))).toEqual(expected)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('uses the 2.1 sequential colors in reverse order for a reversed palette', () => {
|
|
338
|
+
const expected = chartV21ColorDistribution[2].map(index => colorPalettesChartV2.sequential_blue[index]).reverse()
|
|
339
|
+
|
|
340
|
+
expect(
|
|
341
|
+
getScaleColors(
|
|
342
|
+
buildDistributionConfig(2, 'sequential_bluereverse', '2.1', {
|
|
343
|
+
general: {
|
|
344
|
+
palette: {
|
|
345
|
+
name: 'sequential_bluereverse',
|
|
346
|
+
version: '2.1',
|
|
347
|
+
isReversed: true
|
|
348
|
+
}
|
|
349
|
+
} as any
|
|
350
|
+
})
|
|
351
|
+
)
|
|
352
|
+
).toEqual(expected)
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
it('does not change divergent colors between palette versions', () => {
|
|
356
|
+
const count = 5
|
|
357
|
+
const expected = divergentColorDistribution[count].map(index => colorPalettesChartV2.divergent_blue_orange[index])
|
|
358
|
+
|
|
359
|
+
expect(getScaleColors(buildDistributionConfig(count, 'divergent_blue_orange', '2.0'))).toEqual(expected)
|
|
360
|
+
expect(getScaleColors(buildDistributionConfig(count, 'divergent_blue_orange', '2.1'))).toEqual(expected)
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('bypasses distribution profiles for non-empty custom colors', () => {
|
|
364
|
+
const customColors = Array.from({ length: 9 }, (_, index) => `#00000${index}`)
|
|
365
|
+
const config = buildDistributionConfig(5, 'qualitative_standard', '2.1', {
|
|
366
|
+
general: {
|
|
367
|
+
palette: {
|
|
368
|
+
name: 'qualitative_standard',
|
|
369
|
+
version: '2.1',
|
|
370
|
+
customColors
|
|
371
|
+
}
|
|
372
|
+
} as any
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
expect(getScaleColors(config)).toEqual(customColors.slice(0, 5))
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
it('treats empty custom color arrays as inactive', () => {
|
|
379
|
+
const config = buildDistributionConfig(3, 'qualitative_standard', '2.1', {
|
|
380
|
+
general: {
|
|
381
|
+
palette: {
|
|
382
|
+
name: 'qualitative_standard',
|
|
383
|
+
version: '2.1',
|
|
384
|
+
customColors: [],
|
|
385
|
+
customColorsOrdered: []
|
|
386
|
+
}
|
|
387
|
+
} as any
|
|
388
|
+
})
|
|
389
|
+
const expected = qualitativeStandardColorDistribution[3].map(
|
|
390
|
+
index => colorPalettesChartV2.qualitative_standard[index]
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
expect(getScaleColors(config)).toEqual(expected)
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
it('retains slice and repeat behavior outside the supported item range', () => {
|
|
397
|
+
const expected = [...colorPalettesChartV2.qualitative_standard, colorPalettesChartV2.qualitative_standard[0]]
|
|
398
|
+
|
|
399
|
+
expect(getScaleColors(buildDistributionConfig(10, 'qualitative_standard', '2.1'))).toEqual(expected)
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
it('does not apply the 2.1 distribution to an unsupported chart type', () => {
|
|
403
|
+
const config = buildDistributionConfig(3, 'qualitative_standard', '2.1', {
|
|
404
|
+
visualizationType: 'Horizon Chart'
|
|
405
|
+
})
|
|
406
|
+
const expected = colorblindColorDistribution[3].map(index => colorPalettesChartV2.qualitative_standard[index])
|
|
407
|
+
|
|
408
|
+
expect(getScaleColors(config)).toEqual(expected)
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
it('applies the 2.1 distribution to a color-coded bar chart', () => {
|
|
412
|
+
const config = buildDistributionConfig(3, 'qualitative_standard', '2.1', {
|
|
413
|
+
visualizationType: 'Bar',
|
|
414
|
+
legend: { colorCode: 'category' } as any
|
|
415
|
+
})
|
|
416
|
+
const expected = qualitativeStandardColorDistribution[3].map(
|
|
417
|
+
index => colorPalettesChartV2.qualitative_standard[index]
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
expect(getScaleColors(config)).toEqual(expected)
|
|
421
|
+
})
|
|
422
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getDynamicYAxisCategories } from '../getDynamicYAxisCategories'
|
|
3
|
+
|
|
4
|
+
const config = {
|
|
5
|
+
categories: [
|
|
6
|
+
{ label: 'Very Low', upperBoundKey: 'very_low_max' },
|
|
7
|
+
{ label: 'Low', upperBoundKey: 'low_max' },
|
|
8
|
+
{ label: 'Moderate', upperBoundKey: 'moderate_max' },
|
|
9
|
+
{ label: 'High', upperBoundKey: 'high_max' },
|
|
10
|
+
{ label: 'Very High', upperBoundKey: 'very_high_max' }
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('getDynamicYAxisCategories', () => {
|
|
15
|
+
it('converts cumulative upper bounds into category heights and uses configured colors', () => {
|
|
16
|
+
config.categories = config.categories.map((category, index) => ({ ...category, color: `color-${index}` }))
|
|
17
|
+
const result = getDynamicYAxisCategories({
|
|
18
|
+
config,
|
|
19
|
+
data: [{ very_low_max: 12.5, low_max: 16, moderate_max: 18, high_max: 21, very_high_max: 35 }]
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
expect(result).toEqual({
|
|
23
|
+
axisMax: 35,
|
|
24
|
+
categories: [
|
|
25
|
+
{ label: 'Very Low', height: '12.5', color: 'color-0' },
|
|
26
|
+
{ label: 'Low', height: '3.5', color: 'color-1' },
|
|
27
|
+
{ label: 'Moderate', height: '2', color: 'color-2' },
|
|
28
|
+
{ label: 'High', height: '3', color: 'color-3' },
|
|
29
|
+
{ label: 'Very High', height: '14', color: 'color-4' }
|
|
30
|
+
]
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('returns null for missing, invalid, or non-increasing current-row data', () => {
|
|
35
|
+
expect(getDynamicYAxisCategories({ config, data: [{ very_low_max: 12 }] })).toBeNull()
|
|
36
|
+
expect(
|
|
37
|
+
getDynamicYAxisCategories({
|
|
38
|
+
config,
|
|
39
|
+
data: [{ very_low_max: 12, low_max: 10, moderate_max: 18, high_max: 21, very_high_max: 35 }]
|
|
40
|
+
})
|
|
41
|
+
).toBeNull()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('returns null while filtered chart data is temporarily empty', () => {
|
|
45
|
+
expect(getDynamicYAxisCategories({ config, data: [] })).toBeNull()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('leaves the final category open-ended when it has no upper-bound key', () => {
|
|
49
|
+
const categories = config.categories.map((category, index) =>
|
|
50
|
+
index === config.categories.length - 1 ? { ...category, upperBoundKey: undefined } : category
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const result = getDynamicYAxisCategories({
|
|
54
|
+
config: { categories },
|
|
55
|
+
data: [{ very_low_max: 12.5, low_max: 16, moderate_max: 18, high_max: 21 }]
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
expect(result?.axisMax).toBeNull()
|
|
59
|
+
expect(result?.categories.at(-1)).toEqual({ label: 'Very High', height: '', color: 'color-4' })
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -155,6 +155,47 @@ describe('getMinMax automatic max strategy', () => {
|
|
|
155
155
|
expect(result.rightMax).toBe(89)
|
|
156
156
|
})
|
|
157
157
|
|
|
158
|
+
it('uses stacked row totals for combo left-axis bar series and keeps right-axis line max independent', () => {
|
|
159
|
+
const barSeriesA = { dataKey: 'DoseOne', type: 'Bar', axis: 'Left', tooltip: true }
|
|
160
|
+
const barSeriesB = { dataKey: 'DoseTwo', type: 'Bar', axis: 'Left', tooltip: true }
|
|
161
|
+
const rightLineSeries = { dataKey: 'Rate', type: 'Line', axis: 'Right', tooltip: true }
|
|
162
|
+
const data = [
|
|
163
|
+
{ DoseOne: 520, DoseTwo: 80, Rate: 900 },
|
|
164
|
+
{ DoseOne: 0, DoseTwo: 600, Rate: 725 }
|
|
165
|
+
]
|
|
166
|
+
const config = createConfig({
|
|
167
|
+
visualizationType: 'Combo',
|
|
168
|
+
visualizationSubType: 'stacked',
|
|
169
|
+
series: [barSeriesA, barSeriesB, rightLineSeries],
|
|
170
|
+
runtime: {
|
|
171
|
+
...createConfig().runtime,
|
|
172
|
+
yAxis: {
|
|
173
|
+
...createConfig().runtime.yAxis,
|
|
174
|
+
min: '',
|
|
175
|
+
max: ''
|
|
176
|
+
},
|
|
177
|
+
series: [barSeriesA, barSeriesB, rightLineSeries],
|
|
178
|
+
seriesKeys: ['DoseOne', 'DoseTwo', 'Rate'],
|
|
179
|
+
barSeriesKeys: ['DoseOne', 'DoseTwo'],
|
|
180
|
+
lineSeriesKeys: ['Rate']
|
|
181
|
+
} as any
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const result = getMinMax({
|
|
185
|
+
config,
|
|
186
|
+
minValue: 0,
|
|
187
|
+
maxValue: 900,
|
|
188
|
+
existPositiveValue: true,
|
|
189
|
+
data,
|
|
190
|
+
tableData: data,
|
|
191
|
+
isAllLine: false
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
expect(result.leftMax).toBe(600)
|
|
195
|
+
expect(result.leftMax).not.toBe(1120)
|
|
196
|
+
expect(result.rightMax).toBe(900)
|
|
197
|
+
})
|
|
198
|
+
|
|
158
199
|
it('forces a zero min for line charts when boundary suppression is present', () => {
|
|
159
200
|
const config = createConfig({
|
|
160
201
|
visualizationType: 'Line',
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import getStackedSeriesMax from '../getStackedSeriesMax'
|
|
3
|
+
|
|
4
|
+
describe('getStackedSeriesMax', () => {
|
|
5
|
+
it('uses the tallest row sum instead of summing independent series maxima', () => {
|
|
6
|
+
const data = [
|
|
7
|
+
{ apples: 400, oranges: 10 },
|
|
8
|
+
{ apples: 50, oranges: 300 }
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
expect(getStackedSeriesMax(data, ['apples', 'oranges'])).toBe(410)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('accepts series objects and dynamic category original data keys', () => {
|
|
15
|
+
const data = [
|
|
16
|
+
{ apples: 125, oranges: 75, dynamicFruit: 999 },
|
|
17
|
+
{ apples: 10, oranges: 50, dynamicFruit: 999 }
|
|
18
|
+
]
|
|
19
|
+
const series = [
|
|
20
|
+
{ dataKey: 'apples' },
|
|
21
|
+
{ dataKey: 'dynamicFruit', originalDataKey: 'oranges', dynamicCategory: true }
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
expect(getStackedSeriesMax(data, series)).toBe(200)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -1,37 +1,55 @@
|
|
|
1
|
-
import { handleRankByValue } from '../handleRankByValue'
|
|
2
|
-
import { ChartConfig } from '../../types/ChartConfig'
|
|
3
|
-
|
|
4
|
-
describe('handleRankByValue', () => {
|
|
5
|
-
it('should sort the data in ascending order when rankByValue is "asc"', () => {
|
|
6
|
-
const data = [{ value: 3 }, { value: 1 }, { value: 2 }]
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
1
|
+
import { handleRankByValue } from '../handleRankByValue'
|
|
2
|
+
import { ChartConfig } from '../../types/ChartConfig'
|
|
3
|
+
|
|
4
|
+
describe('handleRankByValue', () => {
|
|
5
|
+
it('should sort the data in ascending order when rankByValue is "asc"', () => {
|
|
6
|
+
const data = [{ value: 3 }, { value: 1 }, { value: 2 }]
|
|
7
|
+
const originalData = [...data]
|
|
8
|
+
const config: ChartConfig = {
|
|
9
|
+
rankByValue: 'asc',
|
|
10
|
+
series: [{ dataKey: 'value' }]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const result = handleRankByValue(data, config)
|
|
14
|
+
expect(result).toEqual([{ value: 1 }, { value: 2 }, { value: 3 }])
|
|
15
|
+
expect(result).not.toBe(data)
|
|
16
|
+
expect(data).toEqual(originalData)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should sort the data in descending order when rankByValue is "desc"', () => {
|
|
20
|
+
const data = [{ value: 3 }, { value: 1 }, { value: 2 }]
|
|
21
|
+
const originalData = [...data]
|
|
22
|
+
const config: ChartConfig = {
|
|
23
|
+
rankByValue: 'desc',
|
|
24
|
+
series: [{ dataKey: 'value' }]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const result = handleRankByValue(data, config)
|
|
28
|
+
expect(result).toEqual([{ value: 3 }, { value: 2 }, { value: 1 }])
|
|
29
|
+
expect(result).not.toBe(data)
|
|
30
|
+
expect(data).toEqual(originalData)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should handle numeric strings correctly', () => {
|
|
34
|
+
const data = [{ value: '3' }, { value: '1' }, { value: '2' }]
|
|
35
|
+
const config: ChartConfig = {
|
|
36
|
+
rankByValue: 'asc',
|
|
37
|
+
series: [{ dataKey: 'value' }]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const result = handleRankByValue(data, config)
|
|
41
|
+
expect(result).toEqual([{ value: '1' }, { value: '2' }, { value: '3' }])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should return the original data reference when rankByValue is not set', () => {
|
|
45
|
+
const data = [{ value: 3 }, { value: 1 }, { value: 2 }]
|
|
46
|
+
const config: ChartConfig = {
|
|
47
|
+
rankByValue: undefined,
|
|
48
|
+
series: [{ dataKey: 'value' }]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = handleRankByValue(data, config)
|
|
52
|
+
expect(result).toBe(data)
|
|
53
|
+
expect(result).toEqual([{ value: 3 }, { value: 1 }, { value: 2 }])
|
|
54
|
+
})
|
|
55
|
+
})
|