@cdc/chart 4.26.7 → 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 +502 -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 -97406
- 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/overlay-legend.json +485 -0
- package/examples/private/pie-test.json +469 -0
- package/examples/vega-remote.json +22 -0
- package/package.json +11 -5
- package/src/CdcChartComponent.tsx +405 -208
- 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 +4 -2
- 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/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/_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 +38 -6
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +12 -3
- package/src/components/BarChart/components/BarChart.StackedVertical.test.ts +28 -0
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +29 -25
- package/src/components/BarChart/components/BarChart.Vertical.tsx +37 -26
- package/src/components/BarChart/components/PortionPatternOverlay.tsx +61 -0
- package/src/components/BarChart/components/context.tsx +6 -0
- 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 +104 -0
- package/src/components/BarChart/helpers/useBarChart.ts +60 -59
- 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/helpers/index.ts +11 -82
- package/src/components/Brush/BrushSelector.tsx +9 -23
- 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 +1005 -760
- 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 +88 -54
- 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 +233 -33
- 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 +2 -2
- 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 +2 -1
- package/src/components/EditorPanel/useEditorPermissions.test.tsx +62 -0
- package/src/components/EditorPanel/useEditorPermissions.ts +70 -24
- package/src/components/Forecasting/Forecasting.tsx +15 -6
- 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 +110 -90
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +7 -0
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +47 -34
- 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 -4
- package/src/components/LineChart/index.tsx +69 -24
- 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 +81 -51
- 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 +9 -8
- 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 -4
- 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 +77 -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/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 +18 -37
- package/src/helpers/getChartTypeDefaultPalette.ts +29 -0
- package/src/helpers/getColorCodeCategoryColorMap.ts +26 -0
- package/src/helpers/getColorScale.ts +31 -22
- package/src/helpers/getDynamicYAxisCategories.ts +69 -0
- package/src/helpers/getMinMax.ts +9 -7
- package/src/helpers/getNewRuntime.ts +5 -2
- package/src/helpers/getStackedSeriesMax.ts +51 -0
- package/src/helpers/getV21ChartDistributionColors.ts +57 -0
- package/src/helpers/handleRankByValue.ts +15 -15
- package/src/helpers/seriesColumnSettings.ts +10 -0
- package/src/helpers/sizeHelpers.ts +4 -3
- 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/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 +23 -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/useTooltip.test.tsx +353 -1
- package/src/hooks/usePrefersReducedMotion.ts +22 -0
- package/src/hooks/useReduceData.ts +4 -36
- package/src/hooks/useScales.ts +15 -0
- package/src/hooks/useTooltip.tsx +95 -64
- package/src/scss/main.scss +74 -2
- package/src/store/chart.reducer.ts +4 -3
- package/src/test/CdcChart.dataTable.test.tsx +490 -16
- 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
|
@@ -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
|
+
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createDefaultSeriesColumnConfig,
|
|
3
3
|
findColumnConfigByName,
|
|
4
|
+
getAdditionalColumnFormattingParams,
|
|
4
5
|
getSeriesColumnConfig,
|
|
5
6
|
getSeriesColumnFormattingParams,
|
|
6
7
|
getSeriesOwnedColumnNames,
|
|
@@ -155,4 +156,26 @@ describe('seriesColumnSettings', () => {
|
|
|
155
156
|
it('returns undefined when no formatting overrides were explicitly configured', () => {
|
|
156
157
|
expect(getSeriesColumnFormattingParams({ label: 'Cases' })).toBeUndefined()
|
|
157
158
|
})
|
|
159
|
+
|
|
160
|
+
it('blocks global prefix and suffix fallback for additional columns', () => {
|
|
161
|
+
expect(getAdditionalColumnFormattingParams({ label: 'Count' })).toEqual({
|
|
162
|
+
addColPrefix: '',
|
|
163
|
+
addColSuffix: ''
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('preserves explicit additional column formatting while blocking missing affixes', () => {
|
|
168
|
+
expect(
|
|
169
|
+
getAdditionalColumnFormattingParams({
|
|
170
|
+
prefix: '$',
|
|
171
|
+
roundToPlace: 0,
|
|
172
|
+
commas: false
|
|
173
|
+
})
|
|
174
|
+
).toEqual({
|
|
175
|
+
addColPrefix: '$',
|
|
176
|
+
addColSuffix: '',
|
|
177
|
+
addColRoundTo: 0,
|
|
178
|
+
addColCommas: false
|
|
179
|
+
})
|
|
180
|
+
})
|
|
158
181
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { scaleOrdinal } from '@visx/scale'
|
|
2
2
|
import { describe, expect, it } from 'vitest'
|
|
3
|
-
import { createTileColorScale } from '../smallMultiplesHelpers'
|
|
3
|
+
import { applyTileOrder, createTileColorScale, getTileKeys } from '../smallMultiplesHelpers'
|
|
4
4
|
import { ChartConfig } from '../../types/ChartConfig'
|
|
5
5
|
|
|
6
6
|
const buildConfig = (overrides: Partial<ChartConfig> = {}): ChartConfig =>
|
|
@@ -97,3 +97,39 @@ describe('smallMultiplesHelpers createTileColorScale', () => {
|
|
|
97
97
|
expect(tileScale('Series B')).toBe('#aa0000')
|
|
98
98
|
})
|
|
99
99
|
})
|
|
100
|
+
|
|
101
|
+
describe('smallMultiplesHelpers tile ordering', () => {
|
|
102
|
+
it('sorts by-column tile keys in numeric-aware order', () => {
|
|
103
|
+
const config = buildConfig({
|
|
104
|
+
smallMultiples: {
|
|
105
|
+
mode: 'by-column',
|
|
106
|
+
tileColumn: 'Week'
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
const data = [{ Week: '10' }, { Week: '2' }, { Week: '1' }, { Week: '20' }, { Week: '3' }, { Week: null }]
|
|
110
|
+
|
|
111
|
+
expect(getTileKeys(config, data)).toEqual(['1', '2', '3', '10', '20'])
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('uses numeric-aware order when sorting tile display titles', () => {
|
|
115
|
+
const config = buildConfig({
|
|
116
|
+
smallMultiples: {
|
|
117
|
+
mode: 'by-column',
|
|
118
|
+
tileColumn: 'Week',
|
|
119
|
+
tileTitles: {
|
|
120
|
+
'1': 'Week 1',
|
|
121
|
+
'2': 'Week 2',
|
|
122
|
+
'10': 'Week 10'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
const tileItems = [
|
|
127
|
+
{ mode: 'by-column', tileValue: '10', key: '10' },
|
|
128
|
+
{ mode: 'by-column', tileValue: '2', key: '2' },
|
|
129
|
+
{ mode: 'by-column', tileValue: '1', key: '1' }
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
expect(applyTileOrder(tileItems, 'asc', [], config).map(item => item.tileValue)).toEqual(['1', '2', '10'])
|
|
133
|
+
expect(applyTileOrder(tileItems, 'desc', [], config).map(item => item.tileValue)).toEqual(['10', '2', '1'])
|
|
134
|
+
})
|
|
135
|
+
})
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
getTooltipMarkerColor,
|
|
5
5
|
getTooltipMarkerShape,
|
|
6
6
|
shouldUseTooltipLegendMarkers,
|
|
7
|
+
shouldShowTooltipSeriesRow,
|
|
7
8
|
tooltipHasMarkerColumn,
|
|
8
9
|
tooltipShouldUseMarkerColumn,
|
|
9
10
|
type TooltipRow
|
|
@@ -148,4 +149,83 @@ describe('tooltipHelpers', () => {
|
|
|
148
149
|
expect(ambiguousMarkers).not.toContain('tooltip-body--marker-layout')
|
|
149
150
|
expect(ambiguousMarkers).not.toContain('tooltip-marker-slot')
|
|
150
151
|
})
|
|
152
|
+
|
|
153
|
+
it('shows normal tooltip series rows by default when isolate has no legend selection', () => {
|
|
154
|
+
expect(
|
|
155
|
+
shouldShowTooltipSeriesRow({
|
|
156
|
+
legendBehavior: 'isolate',
|
|
157
|
+
seriesHighlight: [],
|
|
158
|
+
seriesKey: 'cases'
|
|
159
|
+
})
|
|
160
|
+
).toBe(true)
|
|
161
|
+
expect(
|
|
162
|
+
shouldShowTooltipSeriesRow({
|
|
163
|
+
seriesKey: 'deaths'
|
|
164
|
+
})
|
|
165
|
+
).toBe(true)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('limits normal tooltip series rows to one isolated legend selection', () => {
|
|
169
|
+
expect(
|
|
170
|
+
shouldShowTooltipSeriesRow({
|
|
171
|
+
legendBehavior: 'isolate',
|
|
172
|
+
seriesHighlight: ['cases'],
|
|
173
|
+
seriesKey: 'cases'
|
|
174
|
+
})
|
|
175
|
+
).toBe(true)
|
|
176
|
+
expect(
|
|
177
|
+
shouldShowTooltipSeriesRow({
|
|
178
|
+
legendBehavior: 'isolate',
|
|
179
|
+
seriesHighlight: ['cases'],
|
|
180
|
+
seriesKey: 'deaths'
|
|
181
|
+
})
|
|
182
|
+
).toBe(false)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('limits normal tooltip series rows to multiple isolated legend selections', () => {
|
|
186
|
+
expect(
|
|
187
|
+
shouldShowTooltipSeriesRow({
|
|
188
|
+
legendBehavior: 'isolate',
|
|
189
|
+
seriesHighlight: ['cases', 'hospitalizations'],
|
|
190
|
+
seriesKey: 'hospitalizations'
|
|
191
|
+
})
|
|
192
|
+
).toBe(true)
|
|
193
|
+
expect(
|
|
194
|
+
shouldShowTooltipSeriesRow({
|
|
195
|
+
legendBehavior: 'isolate',
|
|
196
|
+
seriesHighlight: ['cases', 'hospitalizations'],
|
|
197
|
+
seriesKey: 'deaths'
|
|
198
|
+
})
|
|
199
|
+
).toBe(false)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('keeps all normal tooltip series rows visible in highlight mode with selected series', () => {
|
|
203
|
+
expect(
|
|
204
|
+
shouldShowTooltipSeriesRow({
|
|
205
|
+
legendBehavior: 'highlight',
|
|
206
|
+
seriesHighlight: ['cases'],
|
|
207
|
+
seriesKey: 'deaths'
|
|
208
|
+
})
|
|
209
|
+
).toBe(true)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
it('can filter normal tooltip rows while preserving headings and additional columns', () => {
|
|
213
|
+
const rows: TooltipRow[] = [
|
|
214
|
+
{ key: 'Date', value: '2024-01-01', kind: 'heading' },
|
|
215
|
+
{ key: 'Cases', value: '10', kind: 'series', seriesKey: 'cases' },
|
|
216
|
+
{ key: 'Deaths', value: '2', kind: 'series', seriesKey: 'deaths' },
|
|
217
|
+
{ key: 'Source', value: 'CDC', kind: 'extra' }
|
|
218
|
+
]
|
|
219
|
+
const filteredRows = rows.filter(
|
|
220
|
+
row =>
|
|
221
|
+
row.kind !== 'series' ||
|
|
222
|
+
shouldShowTooltipSeriesRow({
|
|
223
|
+
legendBehavior: 'isolate',
|
|
224
|
+
seriesHighlight: ['cases'],
|
|
225
|
+
seriesKey: row.seriesKey
|
|
226
|
+
})
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
expect(filteredRows.map(row => row.key)).toEqual(['Date', 'Cases', 'Source'])
|
|
230
|
+
})
|
|
151
231
|
})
|
|
@@ -84,6 +84,22 @@ export const getTooltipSeriesMarker = (
|
|
|
84
84
|
|
|
85
85
|
export const buildTooltipRow = (row: TooltipRow): TooltipRow => row
|
|
86
86
|
|
|
87
|
+
export const shouldShowTooltipSeriesRow = ({
|
|
88
|
+
legendBehavior,
|
|
89
|
+
seriesHighlight = [],
|
|
90
|
+
seriesKey
|
|
91
|
+
}: {
|
|
92
|
+
legendBehavior?: string
|
|
93
|
+
seriesHighlight?: string[]
|
|
94
|
+
seriesKey?: string
|
|
95
|
+
}): boolean => {
|
|
96
|
+
if (legendBehavior === 'isolate' && seriesHighlight.length > 0 && seriesKey) {
|
|
97
|
+
return seriesHighlight.includes(seriesKey)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return true
|
|
101
|
+
}
|
|
102
|
+
|
|
87
103
|
const getMarkerSignature = ({
|
|
88
104
|
markerColor,
|
|
89
105
|
markerShape = 'circle'
|