@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
|
@@ -5,7 +5,7 @@ import heatMapAverageAgeCategoricalConfig from './_mock/heatmap-average-age-cate
|
|
|
5
5
|
import heatMapSparseAggregationConfig from '../../examples/feature/heatmap/sparse-aggregation.json'
|
|
6
6
|
import heatMapCellValuesBottomAxisConfig from '../../examples/feature/heatmap/cell-values-bottom-axis.json'
|
|
7
7
|
import heatMapCalendarConfig from '../../examples/feature/heatmap/calendar-heatmap.json'
|
|
8
|
-
import { assertVisualizationRendered, waitForPresence } from '@cdc/core/helpers/testing'
|
|
8
|
+
import { assertVisualizationRendered, performAndAssert, waitForPresence } from '@cdc/core/helpers/testing'
|
|
9
9
|
|
|
10
10
|
const meta: Meta<typeof Chart> = {
|
|
11
11
|
title: 'Components/Templates/Chart/HeatMap',
|
|
@@ -22,6 +22,40 @@ const heatMapTopYAxisLabelConfig = {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
const heatMapHorizontalScrollConfig = {
|
|
26
|
+
...heatMapCalendarConfig,
|
|
27
|
+
title: 'Scrollable Calendar HeatMap',
|
|
28
|
+
heatmap: {
|
|
29
|
+
...heatMapCalendarConfig.heatmap,
|
|
30
|
+
horizontalScroll: true,
|
|
31
|
+
minColumnWidth: 44
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const heatMapHorizontalScrollBottomAxisConfig = {
|
|
36
|
+
...heatMapAverageAgeCategoricalConfig,
|
|
37
|
+
title: 'Scrollable Bottom Axis HeatMap',
|
|
38
|
+
data: heatMapAverageAgeCategoricalConfig.data.map((row, index) =>
|
|
39
|
+
index === 0 ? { ...row, communityType: 'Extremely Long Urban Community Classification' } : row
|
|
40
|
+
),
|
|
41
|
+
xAxis: {
|
|
42
|
+
...heatMapAverageAgeCategoricalConfig.xAxis,
|
|
43
|
+
tickRotation: 45
|
|
44
|
+
},
|
|
45
|
+
yAxis: {
|
|
46
|
+
...heatMapAverageAgeCategoricalConfig.yAxis,
|
|
47
|
+
label: 'Geographic region category',
|
|
48
|
+
titlePlacement: 'top'
|
|
49
|
+
},
|
|
50
|
+
heatmap: {
|
|
51
|
+
...heatMapAverageAgeCategoricalConfig.heatmap,
|
|
52
|
+
horizontalScroll: true,
|
|
53
|
+
minColumnWidth: 220,
|
|
54
|
+
rowLabelGap: 18,
|
|
55
|
+
xAxisPosition: 'bottom'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
25
59
|
const getTooltipHtmlValues = (canvasElement: HTMLElement) =>
|
|
26
60
|
Array.from(canvasElement.querySelectorAll('[data-tooltip-html]')).map(
|
|
27
61
|
element => element.getAttribute('data-tooltip-html') || ''
|
|
@@ -93,18 +127,17 @@ export const HeatMap_Average_Age_Categorical_Demo: Story = {
|
|
|
93
127
|
const cityLabelBox = getSvgTextBox(chartSvg, 'Atlanta')
|
|
94
128
|
const rowAxisTitle = getSvgText(chartSvg, 'City')
|
|
95
129
|
const columnLabelBox = getSvgTextBox(chartSvg, 'Urban Core')
|
|
130
|
+
const xAxisLine = chartSvg.querySelector('.cdc-heatmap__x-axis-line')
|
|
96
131
|
const svgBox = chartSvg.getBoundingClientRect()
|
|
97
132
|
const blockLeft = Math.min(cityLabelBox?.left || firstCellBox.left, firstCellBox.left)
|
|
98
133
|
const blockRight = lastCellBox.right
|
|
99
134
|
const blockCenterDelta = Math.abs((blockLeft + blockRight) / 2 - (svgBox.left + svgBox.width / 2))
|
|
100
|
-
const rowLabelGap = cityLabelBox ? firstCellBox.left - cityLabelBox.right : 0
|
|
101
135
|
const columnLabelGap = columnLabelBox ? firstCellBox.top - columnLabelBox.bottom : 0
|
|
102
136
|
|
|
103
137
|
expect(cells.length).toBe(60)
|
|
104
138
|
expect(firstCellAriaLabel).toContain('Community Type: Urban Core')
|
|
105
139
|
expect(firstCellAriaLabel).toContain('City: Atlanta')
|
|
106
|
-
expect(
|
|
107
|
-
expect(rowLabelGap).toBeLessThan(80)
|
|
140
|
+
expect(Number(firstCell.getAttribute('x'))).toBe(Number(xAxisLine?.getAttribute('x1')))
|
|
108
141
|
expect(columnLabelGap).toBeGreaterThan(0)
|
|
109
142
|
expect(rowAxisTitle?.getAttribute('transform')).toContain('rotate(-90)')
|
|
110
143
|
expect(columnLabelBox?.top).toBeGreaterThanOrEqual(svgBox.top - 1)
|
|
@@ -184,4 +217,137 @@ export const HeatMap_Calendar_Demo: Story = {
|
|
|
184
217
|
}
|
|
185
218
|
}
|
|
186
219
|
|
|
220
|
+
export const HeatMap_Horizontal_Scroll_Demo: Story = {
|
|
221
|
+
args: {
|
|
222
|
+
config: heatMapHorizontalScrollConfig,
|
|
223
|
+
isEditor: false
|
|
224
|
+
},
|
|
225
|
+
play: async ({ canvasElement }) => {
|
|
226
|
+
await assertVisualizationRendered(canvasElement)
|
|
227
|
+
await waitForPresence('.cdc-heatmap__scroll-area', canvasElement)
|
|
228
|
+
|
|
229
|
+
const scrollArea = canvasElement.querySelector('.cdc-heatmap__scroll-area') as HTMLElement
|
|
230
|
+
const fixedAxis = canvasElement.querySelector('.cdc-heatmap__fixed-axis-svg')
|
|
231
|
+
const fixedXAxisTitle = canvasElement.querySelector('.cdc-heatmap__fixed-x-title text') as SVGTextElement
|
|
232
|
+
const firstCell = scrollArea.querySelector('.visx-heatmap-rect') as SVGRectElement
|
|
233
|
+
const leftScrollCue = canvasElement.querySelector('.cdc-heatmap__scroll-cue--left') as HTMLElement
|
|
234
|
+
const rightScrollCue = canvasElement.querySelector('.cdc-heatmap__scroll-cue--right') as HTMLElement
|
|
235
|
+
const scrollInstructionsId = scrollArea.getAttribute('aria-describedby') || ''
|
|
236
|
+
|
|
237
|
+
expect(scrollArea).toHaveAttribute('role', 'region')
|
|
238
|
+
expect(scrollArea).toHaveAttribute('tabindex', '0')
|
|
239
|
+
expect(scrollArea.scrollLeft).toBe(0)
|
|
240
|
+
expect(scrollArea.scrollWidth).toBeGreaterThan(scrollArea.clientWidth)
|
|
241
|
+
expect(fixedAxis).toBeTruthy()
|
|
242
|
+
expect(scrollArea.contains(fixedAxis)).toBe(false)
|
|
243
|
+
expect(leftScrollCue).toHaveAttribute('aria-hidden', 'true')
|
|
244
|
+
expect(rightScrollCue).toHaveAttribute('aria-hidden', 'true')
|
|
245
|
+
expect(leftScrollCue).not.toHaveClass('is-visible')
|
|
246
|
+
expect(rightScrollCue).toHaveClass('is-visible')
|
|
247
|
+
expect(canvasElement.querySelector(`#${scrollInstructionsId}`)).toHaveTextContent(
|
|
248
|
+
'Scroll horizontally to view additional columns.'
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
await performAndAssert(
|
|
252
|
+
'HeatMap horizontal scrolling',
|
|
253
|
+
() => ({
|
|
254
|
+
scrollLeft: scrollArea.scrollLeft,
|
|
255
|
+
cellLeft: firstCell.getBoundingClientRect().left,
|
|
256
|
+
fixedAxisLeft: fixedAxis?.getBoundingClientRect().left || 0,
|
|
257
|
+
fixedTitleLeft: fixedXAxisTitle.getBoundingClientRect().left,
|
|
258
|
+
canScrollLeft: leftScrollCue.classList.contains('is-visible'),
|
|
259
|
+
canScrollRight: rightScrollCue.classList.contains('is-visible')
|
|
260
|
+
}),
|
|
261
|
+
() => {
|
|
262
|
+
scrollArea.scrollLeft = Math.min(200, scrollArea.scrollWidth - scrollArea.clientWidth)
|
|
263
|
+
scrollArea.dispatchEvent(new Event('scroll'))
|
|
264
|
+
},
|
|
265
|
+
(before, after) =>
|
|
266
|
+
after.scrollLeft > before.scrollLeft &&
|
|
267
|
+
after.cellLeft < before.cellLeft &&
|
|
268
|
+
Math.abs(after.fixedAxisLeft - before.fixedAxisLeft) < 1 &&
|
|
269
|
+
Math.abs(after.fixedTitleLeft - before.fixedTitleLeft) < 1 &&
|
|
270
|
+
after.canScrollLeft &&
|
|
271
|
+
after.canScrollRight
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
await performAndAssert(
|
|
275
|
+
'HeatMap horizontal scroll end cue',
|
|
276
|
+
() => ({
|
|
277
|
+
canScrollLeft: leftScrollCue.classList.contains('is-visible'),
|
|
278
|
+
canScrollRight: rightScrollCue.classList.contains('is-visible')
|
|
279
|
+
}),
|
|
280
|
+
() => {
|
|
281
|
+
scrollArea.scrollLeft = scrollArea.scrollWidth - scrollArea.clientWidth
|
|
282
|
+
scrollArea.dispatchEvent(new Event('scroll'))
|
|
283
|
+
},
|
|
284
|
+
(before, after) => before.canScrollRight && after.canScrollLeft && !after.canScrollRight
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export const HeatMap_Horizontal_Scroll_Bottom_Axis_Demo: Story = {
|
|
290
|
+
args: {
|
|
291
|
+
config: heatMapHorizontalScrollBottomAxisConfig,
|
|
292
|
+
isEditor: false
|
|
293
|
+
},
|
|
294
|
+
play: async ({ canvasElement }) => {
|
|
295
|
+
await assertVisualizationRendered(canvasElement)
|
|
296
|
+
await waitForPresence('.cdc-heatmap__scroll-area', canvasElement)
|
|
297
|
+
|
|
298
|
+
const scrollArea = canvasElement.querySelector('.cdc-heatmap__scroll-area') as HTMLElement
|
|
299
|
+
const firstCell = scrollArea.querySelector('.visx-heatmap-rect') as SVGRectElement
|
|
300
|
+
const firstTickLabel = scrollArea.querySelector('.visx-axis-bottom .visx-axis-tick text') as SVGTextElement
|
|
301
|
+
const xAxisLine = scrollArea.querySelector('.cdc-heatmap__x-axis-line')
|
|
302
|
+
const fixedAxis = canvasElement.querySelector('.cdc-heatmap__fixed-axis-svg') as SVGSVGElement
|
|
303
|
+
const scrollAreaBox = scrollArea.getBoundingClientRect()
|
|
304
|
+
const firstCellBox = firstCell.getBoundingClientRect()
|
|
305
|
+
const firstTickLabelBox = firstTickLabel.getBoundingClientRect()
|
|
306
|
+
|
|
307
|
+
expect(canvasElement.querySelector('.visx-axis-bottom')).toBeTruthy()
|
|
308
|
+
expect(Number(firstCell.getAttribute('x'))).toBeGreaterThan(18)
|
|
309
|
+
expect(firstCellBox.left).toBeLessThan(scrollAreaBox.right)
|
|
310
|
+
expect(firstTickLabelBox.left).toBeGreaterThanOrEqual(scrollAreaBox.left - 1)
|
|
311
|
+
expect(xAxisLine).toHaveAttribute('x1', '0')
|
|
312
|
+
expect(getComputedStyle(fixedAxis).overflow).toBe('visible')
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export const HeatMap_QA_Spacing_And_Cell_Values: Story = {
|
|
317
|
+
args: {
|
|
318
|
+
config: {
|
|
319
|
+
...heatMapAverageAgeCategoricalConfig,
|
|
320
|
+
heights: { ...heatMapAverageAgeCategoricalConfig.heights, vertical: 600 },
|
|
321
|
+
xAxis: { ...heatMapAverageAgeCategoricalConfig.xAxis, size: 0, tickRotation: 0, maxTickRotation: 0 },
|
|
322
|
+
heatmap: {
|
|
323
|
+
...heatMapAverageAgeCategoricalConfig.heatmap,
|
|
324
|
+
rowLabelGap: 18,
|
|
325
|
+
columnLabelGap: 20,
|
|
326
|
+
xAxisPosition: 'bottom',
|
|
327
|
+
showCellValues: true
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
isEditor: false
|
|
331
|
+
},
|
|
332
|
+
play: async ({ canvasElement }) => {
|
|
333
|
+
await assertVisualizationRendered(canvasElement)
|
|
334
|
+
await waitForPresence('.cdc-heatmap__cell-value', canvasElement)
|
|
335
|
+
const cell = canvasElement.querySelector('.visx-heatmap-rect') as SVGRectElement
|
|
336
|
+
const svg = cell.ownerSVGElement as SVGSVGElement
|
|
337
|
+
const rowLabel = svg.querySelector('.visx-axis-left text') as SVGTextElement
|
|
338
|
+
const title = getSvgText(svg, 'Community Type') as SVGTextElement
|
|
339
|
+
const values = Array.from(svg.querySelectorAll<SVGTextElement>('.cdc-heatmap__cell-value'))
|
|
340
|
+
|
|
341
|
+
expect(Number(cell.getAttribute('x'))).toBe(0)
|
|
342
|
+
expect(Number(rowLabel.getAttribute('x'))).toBe(-26)
|
|
343
|
+
expect(svg.getBoundingClientRect().bottom - title.getBoundingClientRect().bottom).toBeLessThan(16)
|
|
344
|
+
expect(title.getBoundingClientRect().bottom).toBeLessThan(svg.getBoundingClientRect().bottom)
|
|
345
|
+
expect(values.length).toBeGreaterThan(0)
|
|
346
|
+
for (const value of values) {
|
|
347
|
+
expect(Number(value.getAttribute('font-size'))).toBe(16)
|
|
348
|
+
expect(value.getBoundingClientRect().width).toBeLessThan(cell.getBoundingClientRect().width)
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
187
353
|
export default meta
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import Chart from '../CdcChartComponent'
|
|
3
|
+
import axisAlignStackedBar from './_mock/legend-axis-align-stacked-bar.json'
|
|
4
|
+
import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
|
|
5
|
+
import { assertVisualizationRendered, openAccordion, waitForEditor } from '@cdc/core/helpers/testing'
|
|
6
|
+
import { expect, waitFor, within } from 'storybook/test'
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Chart> = {
|
|
9
|
+
title: 'Components/Templates/Chart/Legend/Axis Align',
|
|
10
|
+
component: Chart,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default meta
|
|
17
|
+
type Story = StoryObj<typeof Chart>
|
|
18
|
+
|
|
19
|
+
const isolatedSeries = 'Sub-1 Rate'
|
|
20
|
+
|
|
21
|
+
const getConfig = (axisAlign: boolean) =>
|
|
22
|
+
editConfigKeys(axisAlignStackedBar, [
|
|
23
|
+
{ path: ['title'], value: axisAlign ? 'Sub-1 values start at zero' : 'Sub-1 values keep stack offset' },
|
|
24
|
+
{ path: ['legend', 'axisAlign'], value: axisAlign },
|
|
25
|
+
{ path: ['legend', 'seriesHighlight'], value: [isolatedSeries] }
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
const getPathYValues = (path: SVGPathElement) => {
|
|
29
|
+
const values = [...(path.getAttribute('d') || '').matchAll(/-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi)].map(match =>
|
|
30
|
+
Number(match[0])
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return values.filter((_value, index) => index % 2 === 1).filter(Number.isFinite)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const getVisibleBarBounds = (panel: Element) => {
|
|
37
|
+
const bars = Array.from(panel.querySelectorAll<SVGPathElement>('.stack.vertical path')).filter(
|
|
38
|
+
bar => getComputedStyle(bar).display !== 'none'
|
|
39
|
+
)
|
|
40
|
+
const bounds = bars
|
|
41
|
+
.map(getPathYValues)
|
|
42
|
+
.filter(yValues => yValues.length)
|
|
43
|
+
.map(yValues => ({
|
|
44
|
+
top: Math.min(...yValues),
|
|
45
|
+
bottom: Math.max(...yValues)
|
|
46
|
+
}))
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
count: bounds.length,
|
|
50
|
+
top: Math.min(...bounds.map(bound => bound.top)),
|
|
51
|
+
bottom: Math.max(...bounds.map(bound => bound.bottom)),
|
|
52
|
+
height: Math.max(...bounds.map(bound => bound.bottom)) - Math.min(...bounds.map(bound => bound.top))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const panelStyle = {
|
|
57
|
+
border: '1px solid #d9dfe7',
|
|
58
|
+
borderRadius: 6,
|
|
59
|
+
padding: 16,
|
|
60
|
+
minWidth: 0,
|
|
61
|
+
background: '#fff'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const Stacked_Bar_Isolate_Comparison: Story = {
|
|
65
|
+
render: () => (
|
|
66
|
+
<div
|
|
67
|
+
style={{
|
|
68
|
+
display: 'grid',
|
|
69
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
|
|
70
|
+
gap: 16,
|
|
71
|
+
padding: 16,
|
|
72
|
+
background: '#f7f8fa'
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<section style={panelStyle} data-axis-align='true'>
|
|
76
|
+
<Chart config={getConfig(true)} isEditor={false} />
|
|
77
|
+
</section>
|
|
78
|
+
<section style={panelStyle} data-axis-align='false'>
|
|
79
|
+
<Chart config={getConfig(false)} isEditor={false} />
|
|
80
|
+
</section>
|
|
81
|
+
</div>
|
|
82
|
+
),
|
|
83
|
+
play: async ({ canvasElement }) => {
|
|
84
|
+
await assertVisualizationRendered(canvasElement)
|
|
85
|
+
|
|
86
|
+
await waitFor(() => {
|
|
87
|
+
const alignedPanel = canvasElement.querySelector('[data-axis-align="true"]')
|
|
88
|
+
const offsetPanel = canvasElement.querySelector('[data-axis-align="false"]')
|
|
89
|
+
|
|
90
|
+
expect(alignedPanel).toBeTruthy()
|
|
91
|
+
expect(offsetPanel).toBeTruthy()
|
|
92
|
+
|
|
93
|
+
const alignedBarBounds = getVisibleBarBounds(alignedPanel!)
|
|
94
|
+
const offsetBarBounds = getVisibleBarBounds(offsetPanel!)
|
|
95
|
+
|
|
96
|
+
expect(alignedBarBounds.count).toBeGreaterThan(0)
|
|
97
|
+
expect(offsetBarBounds.count).toBeGreaterThan(0)
|
|
98
|
+
expect(alignedBarBounds.bottom).toBeGreaterThan(offsetBarBounds.bottom)
|
|
99
|
+
expect(alignedBarBounds.height).toBeGreaterThanOrEqual(2.5)
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const Sub_One_Left_Axis_100_Editor: Story = {
|
|
105
|
+
args: {
|
|
106
|
+
config: getConfig(true),
|
|
107
|
+
isEditor: true
|
|
108
|
+
},
|
|
109
|
+
play: async ({ canvasElement }) => {
|
|
110
|
+
const canvas = within(canvasElement)
|
|
111
|
+
|
|
112
|
+
await waitForEditor(canvas)
|
|
113
|
+
await openAccordion(canvas, 'Legend')
|
|
114
|
+
await assertVisualizationRendered(canvasElement)
|
|
115
|
+
|
|
116
|
+
const axisAlignCheckbox = canvas.getByLabelText(/align to axis on isolate/i) as HTMLInputElement
|
|
117
|
+
expect(axisAlignCheckbox).toBeChecked()
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { expect, fireEvent, userEvent, within } from 'storybook/test'
|
|
3
|
+
import { assertVisualizationRendered, openAccordion, performAndAssert, waitForEditor } from '@cdc/core/helpers/testing'
|
|
4
|
+
import Chart from '../CdcChartComponent'
|
|
5
|
+
import lineRaceExample from '../../examples/feature/line/line-chart-race.json'
|
|
6
|
+
|
|
7
|
+
const lineRaceStyledExample = {
|
|
8
|
+
...lineRaceExample,
|
|
9
|
+
series: lineRaceExample.series.map((series, index) =>
|
|
10
|
+
index === 0 ? { ...series, type: 'dashed-md', weight: 7 } : series
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const newestFirstLineRaceExample = {
|
|
15
|
+
...lineRaceExample,
|
|
16
|
+
title: 'Newest-first population trends',
|
|
17
|
+
xAxis: {
|
|
18
|
+
...lineRaceExample.xAxis,
|
|
19
|
+
type: 'date',
|
|
20
|
+
dataKey: 'Date',
|
|
21
|
+
dateParseFormat: '%Y-%m-%d',
|
|
22
|
+
dateDisplayFormat: '%Y-%m-%d',
|
|
23
|
+
sortByRecentDate: true
|
|
24
|
+
},
|
|
25
|
+
data: lineRaceExample.data.map(({ Year, ...row }) => ({ Date: `${Year}-01-01`, ...row }))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const meta: Meta<typeof Chart> = {
|
|
29
|
+
title: 'Components/Templates/Chart/Line Race',
|
|
30
|
+
component: Chart,
|
|
31
|
+
parameters: { layout: 'fullscreen' }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default meta
|
|
35
|
+
type Story = StoryObj<typeof Chart>
|
|
36
|
+
|
|
37
|
+
export const ChangesOverTime: Story = {
|
|
38
|
+
name: 'Changes Over Time',
|
|
39
|
+
args: {
|
|
40
|
+
config: lineRaceStyledExample as any,
|
|
41
|
+
isEditor: false,
|
|
42
|
+
interactionLabel: 'Population trends Line race'
|
|
43
|
+
},
|
|
44
|
+
play: async ({ canvasElement }) => {
|
|
45
|
+
const canvas = within(canvasElement)
|
|
46
|
+
await assertVisualizationRendered(canvasElement)
|
|
47
|
+
expect(canvasElement.querySelector('.line-chart-race__frame')).toHaveTextContent('1950')
|
|
48
|
+
expect(canvasElement.querySelector('.bottom-axis')).toHaveTextContent('1950')
|
|
49
|
+
expect(canvasElement.querySelector('.component--has-accent')).not.toBeInTheDocument()
|
|
50
|
+
expect(canvas.getByRole('button', { name: 'Play' })).toBeInTheDocument()
|
|
51
|
+
expect(canvasElement.querySelector('[data-line-race-series-path]')).toHaveAttribute('stroke-dasharray', '10 5')
|
|
52
|
+
expect(canvasElement.querySelector('[data-line-race-series-path]')).toHaveAttribute('stroke-width', '7')
|
|
53
|
+
expect(canvasElement.querySelector('[data-line-race-series-path]')).not.toHaveAttribute('pathLength')
|
|
54
|
+
expect(canvasElement.querySelector('[data-line-race-reveal-path]')).toHaveAttribute('pathLength', '1')
|
|
55
|
+
|
|
56
|
+
await performAndAssert(
|
|
57
|
+
'Draw the styled Line path forward without pausing playback',
|
|
58
|
+
() => ({
|
|
59
|
+
frame: canvasElement.querySelector('.line-chart-race__frame')?.textContent?.trim(),
|
|
60
|
+
revealDash: canvasElement.querySelector('[data-line-race-reveal-path]')?.getAttribute('stroke-dasharray'),
|
|
61
|
+
seriesDash: canvasElement.querySelector('[data-line-race-series-path]')?.getAttribute('stroke-dasharray'),
|
|
62
|
+
seriesWeight: canvasElement.querySelector('[data-line-race-series-path]')?.getAttribute('stroke-width'),
|
|
63
|
+
axis: canvasElement.querySelector('.bottom-axis')?.textContent
|
|
64
|
+
}),
|
|
65
|
+
async () => userEvent.click(canvas.getByRole('button', { name: 'Play' })),
|
|
66
|
+
(before, after) =>
|
|
67
|
+
before.frame === '1950' &&
|
|
68
|
+
after.frame === '1951' &&
|
|
69
|
+
after.revealDash !== before.revealDash &&
|
|
70
|
+
after.seriesDash === before.seriesDash &&
|
|
71
|
+
after.seriesDash === '10 5' &&
|
|
72
|
+
after.seriesWeight === '7' &&
|
|
73
|
+
after.axis === before.axis
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const NewestFirstDates: Story = {
|
|
79
|
+
name: 'Newest-first dates',
|
|
80
|
+
args: {
|
|
81
|
+
config: newestFirstLineRaceExample as any,
|
|
82
|
+
isEditor: false,
|
|
83
|
+
interactionLabel: 'Newest-first population trends Line race'
|
|
84
|
+
},
|
|
85
|
+
play: async ({ canvasElement }) => {
|
|
86
|
+
const canvas = within(canvasElement)
|
|
87
|
+
await assertVisualizationRendered(canvasElement)
|
|
88
|
+
expect(canvasElement.querySelector('.line-chart-race__frame')).toHaveTextContent('1955-01-01')
|
|
89
|
+
|
|
90
|
+
const getRaceState = () => {
|
|
91
|
+
const path = canvasElement.querySelector('[data-line-race-series-path]') as SVGPathElement | null
|
|
92
|
+
expect(path).not.toBeNull()
|
|
93
|
+
if (!path) throw new Error('Expected the Line race series path to render')
|
|
94
|
+
const length = path.getAttribute('d') ? path.getTotalLength() : 0
|
|
95
|
+
return {
|
|
96
|
+
frame: canvasElement.querySelector('.line-chart-race__frame')?.textContent?.trim(),
|
|
97
|
+
startsLeft: length > 0 && path.getPointAtLength(0).x < path.getPointAtLength(length).x
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
await performAndAssert(
|
|
102
|
+
'Advance newest-first playback while drawing left to right',
|
|
103
|
+
getRaceState,
|
|
104
|
+
async () => userEvent.click(canvas.getByRole('button', { name: 'Play' })),
|
|
105
|
+
(before, after) =>
|
|
106
|
+
before.frame === '1955-01-01' && after.frame === '1954-01-01' && before.startsLeft && after.startsLeft
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const GeneralSectionTests: Story = {
|
|
112
|
+
name: 'Editor: General Section',
|
|
113
|
+
parameters: { test: { timeout: 30000 } },
|
|
114
|
+
args: {
|
|
115
|
+
config: { ...lineRaceExample, visualizationSubType: 'regular' } as any,
|
|
116
|
+
isEditor: true,
|
|
117
|
+
interactionLabel: 'Line race editor story'
|
|
118
|
+
},
|
|
119
|
+
play: async ({ canvasElement }) => {
|
|
120
|
+
const canvas = within(canvasElement)
|
|
121
|
+
await waitForEditor(canvas)
|
|
122
|
+
await openAccordion(canvas, 'General')
|
|
123
|
+
expect(canvasElement.querySelector('.line-chart-race')).not.toBeInTheDocument()
|
|
124
|
+
const subtype = canvas.getByLabelText(/chart subtype/i) as HTMLSelectElement
|
|
125
|
+
expect(Array.from(subtype.options).map(option => option.value)).toEqual(['regular', 'racing'])
|
|
126
|
+
|
|
127
|
+
await performAndAssert(
|
|
128
|
+
'Enable Line racing mode',
|
|
129
|
+
() => Boolean(canvasElement.querySelector('.line-chart-race')),
|
|
130
|
+
async () => userEvent.selectOptions(subtype, 'racing'),
|
|
131
|
+
(_before, after) => after
|
|
132
|
+
)
|
|
133
|
+
expect(canvasElement.querySelector('.line-chart-race__frame')).toHaveTextContent('1950')
|
|
134
|
+
const timing = canvas.getByRole('slider', { name: /seconds per time step/i }) as HTMLInputElement
|
|
135
|
+
expect(timing.valueAsNumber).toBe(0.5)
|
|
136
|
+
expect(timing).toHaveAttribute('min', '0')
|
|
137
|
+
expect(timing).toHaveAttribute('max', '1.5')
|
|
138
|
+
expect(timing).toHaveAttribute('step', '0.5')
|
|
139
|
+
|
|
140
|
+
await fireEvent.change(timing, { target: { value: '0' } })
|
|
141
|
+
await performAndAssert(
|
|
142
|
+
'Apply instant playback timing',
|
|
143
|
+
() => canvasElement.querySelector('.line-chart-race__frame')?.textContent?.trim(),
|
|
144
|
+
async () => userEvent.click(canvas.getByRole('button', { name: 'Play' })),
|
|
145
|
+
(before, after) => before === '1950' && after === '1955'
|
|
146
|
+
)
|
|
147
|
+
expect(canvas.getByRole('button', { name: 'Replay' })).toBeInTheDocument()
|
|
148
|
+
}
|
|
149
|
+
}
|