@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
|
@@ -98,6 +98,27 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
98
98
|
}
|
|
99
99
|
)
|
|
100
100
|
|
|
101
|
+
const hideHatchingCheckbox = canvas.getByLabelText(/hide diagonal hatching/i) as HTMLInputElement
|
|
102
|
+
const getBrushHatchingState = () => {
|
|
103
|
+
const brushExtent = canvasElement.querySelector('.visx-brush rect[class*="selection"]') as SVGRectElement
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
checked: hideHatchingCheckbox.checked,
|
|
107
|
+
fill: brushExtent?.getAttribute('fill') || brushExtent?.style.fill || ''
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
expect(hideHatchingCheckbox.checked).toBe(false)
|
|
112
|
+
expect(hideHatchingCheckbox.classList.contains('ms-4')).toBe(true)
|
|
113
|
+
expect(getBrushHatchingState().fill).toContain('brush_pattern')
|
|
114
|
+
|
|
115
|
+
await performAndAssert(
|
|
116
|
+
'Hide Diagonal Hatching - Brush selection becomes transparent',
|
|
117
|
+
getBrushHatchingState,
|
|
118
|
+
async () => await userEvent.click(hideHatchingCheckbox),
|
|
119
|
+
(before, after) => !before.checked && after.checked && after.fill === 'transparent'
|
|
120
|
+
)
|
|
121
|
+
|
|
101
122
|
// ============================================================================
|
|
102
123
|
// TEST: Default Recent Date Count Input
|
|
103
124
|
// Verifies: When "Show last X dates" is set, the brush selection changes
|
|
@@ -128,42 +149,34 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
128
149
|
const totalBrushWidth = brushSvg ? brushSvg.clientWidth || brushWidthAttr : 0
|
|
129
150
|
const countInput = canvasElement.querySelector('input[id*="brushDefaultRecentDateCount"]') as HTMLInputElement
|
|
130
151
|
|
|
131
|
-
// Get the visible data points in the main chart (lines or bars)
|
|
132
|
-
const chartSvg = canvasElement.querySelector('.linear-chart svg, .cove-chart svg') as SVGSVGElement
|
|
133
|
-
const dataPointsInChart = chartSvg?.querySelectorAll('circle, rect:not([fill="transparent"])').length || 0
|
|
134
|
-
|
|
135
152
|
return {
|
|
136
153
|
brushWidth: brushExtent ? parseFloat(brushExtent.getAttribute('width') || '0') : 0,
|
|
137
154
|
brushX: brushExtent ? parseFloat(brushExtent.getAttribute('x') || '0') : 0,
|
|
138
155
|
totalBrushWidth,
|
|
139
|
-
|
|
140
|
-
defaultRecentDateCountValue: countInput?.value || '',
|
|
141
|
-
selectionPercentage:
|
|
142
|
-
brushExtent && totalBrushWidth > 0
|
|
143
|
-
? (parseFloat(brushExtent.getAttribute('width') || '0') / totalBrushWidth) * 100
|
|
144
|
-
: 0
|
|
156
|
+
defaultRecentDateCountValue: countInput?.value || ''
|
|
145
157
|
}
|
|
146
158
|
}
|
|
147
159
|
|
|
148
160
|
const initialSelectionState = getBrushSelectionState()
|
|
161
|
+
const selectionMatchesRecentDateCount = (state: ReturnType<typeof getBrushSelectionState>, count: number) => {
|
|
162
|
+
const expectedWidth = (state.totalBrushWidth * count) / brushEnabledConfig.data.length
|
|
163
|
+
const rightEdge = state.brushX + state.brushWidth
|
|
164
|
+
|
|
165
|
+
return Math.abs(state.brushWidth - expectedWidth) <= 2 && Math.abs(rightEdge - state.totalBrushWidth) <= 2
|
|
166
|
+
}
|
|
149
167
|
|
|
150
168
|
// Default is ~35% of the width
|
|
151
|
-
// With
|
|
152
|
-
// Setting to 30 should make the selection
|
|
169
|
+
// With 253 data points in brush_enabled.json, 35% is about 89 points.
|
|
170
|
+
// Setting the count to 30 should make the selection narrower and update immediately.
|
|
153
171
|
await performAndAssert(
|
|
154
172
|
'Set Default Recent Date Count to 30 - Brush Updates Dynamically',
|
|
155
173
|
getBrushSelectionState,
|
|
156
174
|
async () => {
|
|
157
|
-
await userEvent.clear(recentDateCountInput)
|
|
158
175
|
await userEvent.type(recentDateCountInput, '30')
|
|
159
|
-
// Trigger change/blur to apply the value - this should update the brush immediately
|
|
160
176
|
await userEvent.tab()
|
|
161
177
|
},
|
|
162
178
|
(before, after) => {
|
|
163
|
-
|
|
164
|
-
// Since we have ~329 data points and default is 35% (~115 points),
|
|
165
|
-
// setting to 30 points should make the selection narrower
|
|
166
|
-
return after.brushWidth < before.brushWidth || after.selectionPercentage < before.selectionPercentage
|
|
179
|
+
return after.brushWidth < before.brushWidth && selectionMatchesRecentDateCount(after, 30)
|
|
167
180
|
}
|
|
168
181
|
)
|
|
169
182
|
|
|
@@ -172,66 +185,32 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
172
185
|
// Verifies: Multiple changes continue to update the brush dynamically
|
|
173
186
|
// ============================================================================
|
|
174
187
|
|
|
188
|
+
// Wait for the debounced clear to reach the chart before typing the next value.
|
|
189
|
+
// Otherwise the pending empty value can overwrite the newly typed count under CI load.
|
|
175
190
|
await performAndAssert(
|
|
176
|
-
'
|
|
191
|
+
'Clear Default Recent Date Count',
|
|
177
192
|
getBrushSelectionState,
|
|
178
193
|
async () => {
|
|
179
194
|
await userEvent.clear(recentDateCountInput)
|
|
180
|
-
await userEvent.type(recentDateCountInput, '50')
|
|
181
195
|
await userEvent.tab()
|
|
182
196
|
},
|
|
183
197
|
(before, after) => {
|
|
184
|
-
|
|
185
|
-
return after.
|
|
198
|
+
const widthDeltaFromInitial = Math.abs(after.brushWidth - initialSelectionState.brushWidth)
|
|
199
|
+
return after.brushWidth > before.brushWidth && widthDeltaFromInitial <= 2
|
|
186
200
|
}
|
|
187
201
|
)
|
|
188
202
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// Look for the number of data points (circles, bars, or line path points)
|
|
199
|
-
const chartContainer = canvasElement.querySelector('.linear-chart, .cove-chart')
|
|
200
|
-
const svg = chartContainer?.querySelector('svg')
|
|
201
|
-
|
|
202
|
-
// For line charts, count the line path data points
|
|
203
|
-
const linePaths = svg?.querySelectorAll('path[class*="line"], .visx-linepath')
|
|
204
|
-
let dataPointCount = 0
|
|
205
|
-
|
|
206
|
-
if (linePaths && linePaths.length > 0) {
|
|
207
|
-
// Count points in the path by looking at the rendered circles
|
|
208
|
-
const circles = svg?.querySelectorAll('circle')
|
|
209
|
-
dataPointCount = circles?.length || 0
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// For bar charts
|
|
213
|
-
const bars = svg?.querySelectorAll('rect[class*="bar"]')
|
|
214
|
-
if (bars && bars.length > 0) {
|
|
215
|
-
dataPointCount = bars.length
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
dataPointCount,
|
|
220
|
-
hasData: dataPointCount > 0
|
|
203
|
+
await performAndAssert(
|
|
204
|
+
'Set to 50 dates - Brush Updates Dynamically',
|
|
205
|
+
getBrushSelectionState,
|
|
206
|
+
async () => {
|
|
207
|
+
await userEvent.type(recentDateCountInput, '50')
|
|
208
|
+
await userEvent.tab()
|
|
209
|
+
},
|
|
210
|
+
(before, after) => {
|
|
211
|
+
return after.brushWidth < before.brushWidth && selectionMatchesRecentDateCount(after, 50)
|
|
221
212
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
// After setting to 30, the chart should show ~30 data points
|
|
225
|
-
// (exact count may vary based on how brush boundaries align with data points)
|
|
226
|
-
const afterSettingCount = getSelectedDataPointCount()
|
|
227
|
-
|
|
228
|
-
// The count should be close to 30 (allowing some tolerance for edge cases)
|
|
229
|
-
// Note: This assertion helps verify the feature works - if it fails,
|
|
230
|
-
// the implementation needs adjustment
|
|
231
|
-
if (afterSettingCount.hasData) {
|
|
232
|
-
expect(afterSettingCount.dataPointCount).toBeGreaterThan(0)
|
|
233
|
-
expect(afterSettingCount.dataPointCount).toBeLessThanOrEqual(35) // 30 + tolerance
|
|
234
|
-
}
|
|
213
|
+
)
|
|
235
214
|
}
|
|
236
215
|
}
|
|
237
216
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { expect, waitFor } from 'storybook/test'
|
|
3
|
+
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
4
|
+
import Chart from '../CdcChartComponent'
|
|
5
|
+
import brushEnabledConfig from './_mock/brush_enabled.json'
|
|
6
|
+
|
|
7
|
+
const brushEffectConfig = {
|
|
8
|
+
...brushEnabledConfig,
|
|
9
|
+
title: 'Brush Slider with Limited Coverage Markers',
|
|
10
|
+
xAxis: {
|
|
11
|
+
...brushEnabledConfig.xAxis,
|
|
12
|
+
type: 'date',
|
|
13
|
+
brushDefaultRecentDateCount: 4
|
|
14
|
+
},
|
|
15
|
+
data: brushEnabledConfig.data.slice(0, 8).map(row => ({
|
|
16
|
+
...row,
|
|
17
|
+
Coverage: 'Limited Coverage'
|
|
18
|
+
})),
|
|
19
|
+
preliminaryData: [
|
|
20
|
+
{
|
|
21
|
+
type: 'effect',
|
|
22
|
+
seriesKeys: ['Production'],
|
|
23
|
+
label: 'Limited Coverage',
|
|
24
|
+
column: 'Coverage',
|
|
25
|
+
value: 'Limited Coverage',
|
|
26
|
+
style: 'Open Circles',
|
|
27
|
+
displayTooltip: true,
|
|
28
|
+
displayLegend: true,
|
|
29
|
+
displayTable: true,
|
|
30
|
+
circleSize: 4
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const brushSuppressionConfig = {
|
|
36
|
+
...brushEnabledConfig,
|
|
37
|
+
title: 'Brush Slider with Suppressed Bars',
|
|
38
|
+
visualizationType: 'Bar',
|
|
39
|
+
visualizationSubType: 'regular',
|
|
40
|
+
xAxis: {
|
|
41
|
+
...brushEnabledConfig.xAxis,
|
|
42
|
+
type: 'date',
|
|
43
|
+
brushDefaultRecentDateCount: 4
|
|
44
|
+
},
|
|
45
|
+
general: {
|
|
46
|
+
showMissingDataLabel: true,
|
|
47
|
+
showSuppressedSymbol: true,
|
|
48
|
+
showZeroValueData: true
|
|
49
|
+
},
|
|
50
|
+
data: brushEnabledConfig.data.slice(0, 8).map((row, index) => ({
|
|
51
|
+
...row,
|
|
52
|
+
Production: index === 0 ? 'Suppressed' : row.Production
|
|
53
|
+
})),
|
|
54
|
+
series: brushEnabledConfig.series.slice(0, 2).map(series => ({
|
|
55
|
+
...series,
|
|
56
|
+
type: 'Bar'
|
|
57
|
+
})),
|
|
58
|
+
preliminaryData: [
|
|
59
|
+
{
|
|
60
|
+
type: 'suppression',
|
|
61
|
+
seriesKeys: ['Production'],
|
|
62
|
+
label: 'Suppressed',
|
|
63
|
+
column: 'Production',
|
|
64
|
+
value: 'Suppressed',
|
|
65
|
+
style: '',
|
|
66
|
+
displayTooltip: true,
|
|
67
|
+
displayLegend: true,
|
|
68
|
+
displayTable: true,
|
|
69
|
+
symbol: 'Dagger',
|
|
70
|
+
iconCode: '†',
|
|
71
|
+
hideBarSymbol: false
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const meta: Meta<typeof Chart> = {
|
|
77
|
+
title: 'Components/Templates/Chart/BrushSlider/Regression',
|
|
78
|
+
component: Chart
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default meta
|
|
82
|
+
|
|
83
|
+
type Story = StoryObj<typeof Chart>
|
|
84
|
+
|
|
85
|
+
export const EffectMarkersStayInsideSelection: Story = {
|
|
86
|
+
args: {
|
|
87
|
+
config: brushEffectConfig,
|
|
88
|
+
isEditor: false
|
|
89
|
+
},
|
|
90
|
+
parameters: {
|
|
91
|
+
docs: {
|
|
92
|
+
description: {
|
|
93
|
+
story: 'Effect markers render only for dates inside the active brush selection.'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
play: async ({ canvasElement }) => {
|
|
98
|
+
await assertVisualizationRendered(canvasElement)
|
|
99
|
+
|
|
100
|
+
await waitFor(() => {
|
|
101
|
+
const effectCircles = Array.from(canvasElement.querySelectorAll('.line-chart-group > g > circle'))
|
|
102
|
+
|
|
103
|
+
expect(effectCircles).toHaveLength(4)
|
|
104
|
+
effectCircles.forEach(circle => {
|
|
105
|
+
expect(Number.isFinite(Number(circle.getAttribute('cx')))).toBe(true)
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const SuppressedBarsStayInsideSelection: Story = {
|
|
112
|
+
args: {
|
|
113
|
+
config: brushSuppressionConfig,
|
|
114
|
+
isEditor: false
|
|
115
|
+
},
|
|
116
|
+
parameters: {
|
|
117
|
+
docs: {
|
|
118
|
+
description: {
|
|
119
|
+
story: 'Suppression metadata does not cause bars outside the active brush selection to render at the origin.'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
play: async ({ canvasElement }) => {
|
|
124
|
+
await assertVisualizationRendered(canvasElement)
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
const barGroups = Array.from(canvasElement.querySelectorAll('g[class*="bar-group-"]'))
|
|
128
|
+
|
|
129
|
+
expect(barGroups).toHaveLength(4)
|
|
130
|
+
barGroups.forEach(group => {
|
|
131
|
+
expect(group.getAttribute('transform')).not.toContain('NaN')
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -46,6 +46,19 @@ export const GeneralSectionTests: Story = {
|
|
|
46
46
|
},
|
|
47
47
|
play: async ({ canvasElement }) => {
|
|
48
48
|
const canvas = within(canvasElement)
|
|
49
|
+
const documentCanvas = within(canvasElement.ownerDocument.body)
|
|
50
|
+
|
|
51
|
+
const expectTooltipContent = async (field: HTMLElement, expectedText: string) => {
|
|
52
|
+
const tooltipTarget = field.closest('label')?.querySelector('.cove-tooltip--target') as HTMLElement
|
|
53
|
+
expect(tooltipTarget).toBeTruthy()
|
|
54
|
+
|
|
55
|
+
await userEvent.hover(tooltipTarget)
|
|
56
|
+
|
|
57
|
+
const tooltipContent = await documentCanvas.findByText(expectedText)
|
|
58
|
+
expect(tooltipContent).toBeTruthy()
|
|
59
|
+
|
|
60
|
+
await userEvent.unhover(tooltipTarget)
|
|
61
|
+
}
|
|
49
62
|
|
|
50
63
|
// Wait for editor to load
|
|
51
64
|
await waitForEditor(canvas)
|
|
@@ -232,6 +245,11 @@ export const GeneralSectionTests: Story = {
|
|
|
232
245
|
})() as HTMLInputElement
|
|
233
246
|
|
|
234
247
|
if (superTitleInput) {
|
|
248
|
+
await expectTooltipContent(
|
|
249
|
+
superTitleInput,
|
|
250
|
+
'To keep the main title as short as possible, consider adding extra details in a super title, which displays in small font just above the main title in the visualization’s title bar. (If you hide the regular title, the super title does not display.)'
|
|
251
|
+
)
|
|
252
|
+
|
|
235
253
|
await performAndAssert(
|
|
236
254
|
'Super Title Text Change',
|
|
237
255
|
getSuperTitleText,
|
|
@@ -295,6 +313,11 @@ export const GeneralSectionTests: Story = {
|
|
|
295
313
|
})() as HTMLTextAreaElement
|
|
296
314
|
expect(messageInput).toBeTruthy()
|
|
297
315
|
|
|
316
|
+
await expectTooltipContent(
|
|
317
|
+
messageInput,
|
|
318
|
+
'Explain how to use the chart, introduce any special concepts, etc. This text displays above the visualization (and below the title bar, if displayed).'
|
|
319
|
+
)
|
|
320
|
+
|
|
298
321
|
await performAndAssert(
|
|
299
322
|
'Message Text Change',
|
|
300
323
|
getMessageText,
|
|
@@ -406,6 +429,11 @@ export const GeneralSectionTests: Story = {
|
|
|
406
429
|
})() as HTMLTextAreaElement
|
|
407
430
|
|
|
408
431
|
if (footnotesInput) {
|
|
432
|
+
await expectTooltipContent(
|
|
433
|
+
footnotesInput,
|
|
434
|
+
'Use this text element for any supplemental information that should display below the data table.'
|
|
435
|
+
)
|
|
436
|
+
|
|
409
437
|
await performAndAssert(
|
|
410
438
|
'Footnotes Text Change',
|
|
411
439
|
getFootnotesText,
|
|
@@ -670,9 +698,11 @@ export const ComboRightValueAxisSectionTests: Story = {
|
|
|
670
698
|
await waitForEditor(canvas)
|
|
671
699
|
await openAccordion(canvas, 'Right Value Axis')
|
|
672
700
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
701
|
+
expect(canvas.queryByLabelText(/^label offset$/i)).toBeFalsy()
|
|
702
|
+
|
|
703
|
+
const labelPlacementSelect = canvasElement.querySelector('select[name="rightTitlePlacement"]') as HTMLSelectElement
|
|
704
|
+
expect(labelPlacementSelect).toBeTruthy()
|
|
705
|
+
expect(labelPlacementSelect.value).toBe('side')
|
|
676
706
|
}
|
|
677
707
|
}
|
|
678
708
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { expect, userEvent, within } from 'storybook/test'
|
|
3
|
+
import { assertVisualizationRendered, openAccordion, performAndAssert, waitForEditor } from '@cdc/core/helpers/testing'
|
|
4
|
+
import Chart from '../CdcChartComponent'
|
|
5
|
+
import baseConfig from './_mock/line_chart_dashed_dates.json'
|
|
6
|
+
|
|
7
|
+
const config = {
|
|
8
|
+
...baseConfig,
|
|
9
|
+
animate: false,
|
|
10
|
+
title: 'Preliminary line effect compatibility',
|
|
11
|
+
data: [
|
|
12
|
+
{ date: '2024-10-01', Value: '52', Status: 'final' },
|
|
13
|
+
{ date: '2025-01-01', Value: '57', Status: 'preliminary' },
|
|
14
|
+
{ date: '2025-04-01', Value: '54', Status: 'preliminary' }
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const getIncomingPath = (canvasElement: HTMLElement) =>
|
|
19
|
+
canvasElement.querySelector<SVGPathElement>('.line-chart-group path.visx-linepath')
|
|
20
|
+
|
|
21
|
+
const meta: Meta<typeof Chart> = {
|
|
22
|
+
title: 'Components/Templates/Chart/Special Lines/Compatibility',
|
|
23
|
+
component: Chart
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default meta
|
|
27
|
+
type Story = StoryObj<typeof Chart>
|
|
28
|
+
|
|
29
|
+
export const ExistingPreliminaryRule: Story = {
|
|
30
|
+
args: { config, isEditor: true },
|
|
31
|
+
play: async ({ canvasElement }) => {
|
|
32
|
+
const canvas = within(canvasElement)
|
|
33
|
+
await waitForEditor(canvas)
|
|
34
|
+
await assertVisualizationRendered(canvasElement)
|
|
35
|
+
const incomingPath = getIncomingPath(canvasElement)
|
|
36
|
+
expect(incomingPath).toHaveAttribute('stroke-dasharray', '5 5')
|
|
37
|
+
expect(incomingPath.getTotalLength()).toBeGreaterThan(1)
|
|
38
|
+
const originalPath = incomingPath.getAttribute('d')
|
|
39
|
+
|
|
40
|
+
await openAccordion(canvas, 'Data Series')
|
|
41
|
+
const effect = within(
|
|
42
|
+
canvasElement.querySelector<HTMLElement>('[data-rfd-draggable-id="preliminaryData-0"] .accordion')
|
|
43
|
+
)
|
|
44
|
+
await openAccordion(effect, 'Effect Data 1')
|
|
45
|
+
expect(effect.getByLabelText('Apply style to')).toHaveValue('')
|
|
46
|
+
await performAndAssert(
|
|
47
|
+
'Editing an existing rule preserves its incoming dashed segment',
|
|
48
|
+
() => canvasElement.querySelector('.legend-preliminary')?.textContent,
|
|
49
|
+
async () => {
|
|
50
|
+
const label = effect.getByLabelText('Label', { exact: true })
|
|
51
|
+
await userEvent.clear(label)
|
|
52
|
+
await userEvent.type(label, 'Updated preliminary')
|
|
53
|
+
},
|
|
54
|
+
(_, after) => after?.includes('Updated preliminary'),
|
|
55
|
+
() => {
|
|
56
|
+
expect(getIncomingPath(canvasElement)).toHaveAttribute('stroke-dasharray', '5 5')
|
|
57
|
+
expect(getIncomingPath(canvasElement)).toHaveAttribute('d', originalPath)
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const SavedOutgoingRule: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
config: {
|
|
66
|
+
...config,
|
|
67
|
+
preliminaryData: config.preliminaryData.map(rule => ({ ...rule, lineEffectScope: 'outgoing' }))
|
|
68
|
+
},
|
|
69
|
+
isEditor: false
|
|
70
|
+
},
|
|
71
|
+
play: async ({ canvasElement }) => {
|
|
72
|
+
await assertVisualizationRendered(canvasElement)
|
|
73
|
+
expect(getIncomingPath(canvasElement)).toHaveAttribute('stroke-dasharray', '0')
|
|
74
|
+
const outgoingPath = canvasElement.querySelector<SVGPathElement>('.line-chart-group path[stroke-dasharray="5 5"]')
|
|
75
|
+
expect(outgoingPath).not.toBeNull()
|
|
76
|
+
expect(outgoingPath.getTotalLength()).toBeGreaterThan(1)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const NewlyAddedRule: Story = {
|
|
81
|
+
args: { config: { ...config, preliminaryData: [] }, isEditor: true },
|
|
82
|
+
play: async ({ canvasElement }) => {
|
|
83
|
+
const canvas = within(canvasElement)
|
|
84
|
+
await waitForEditor(canvas)
|
|
85
|
+
await assertVisualizationRendered(canvasElement)
|
|
86
|
+
await openAccordion(canvas, 'Data Series')
|
|
87
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Add Special Line' }))
|
|
88
|
+
const effect = within(
|
|
89
|
+
canvasElement.querySelector<HTMLElement>('[data-rfd-draggable-id="preliminaryData-0"] .accordion')
|
|
90
|
+
)
|
|
91
|
+
await openAccordion(effect, 'Effect Data 1')
|
|
92
|
+
await userEvent.click(effect.getByRole('button', { name: 'Expand', exact: true }))
|
|
93
|
+
await userEvent.click(within(effect.getByRole('list')).getByRole('option', { name: 'Value', exact: true }))
|
|
94
|
+
await userEvent.selectOptions(effect.getByLabelText('COLUMN WITH CONFIGURATION VALUE'), 'Status')
|
|
95
|
+
await userEvent.type(effect.getByLabelText(/VALUE TO TRIGGER/), 'preliminary')
|
|
96
|
+
await performAndAssert(
|
|
97
|
+
'A newly added rule styles only the outgoing interval',
|
|
98
|
+
() => canvasElement.querySelectorAll('.line-chart-group path[stroke-dasharray="5 5"]').length,
|
|
99
|
+
() => userEvent.selectOptions(effect.getByLabelText('Style', { exact: true }), 'Dashed Small'),
|
|
100
|
+
(before, after) => before === 0 && after > 0,
|
|
101
|
+
() => {
|
|
102
|
+
expect(getIncomingPath(canvasElement)).toHaveAttribute('stroke-dasharray', '0')
|
|
103
|
+
const outgoingPath = canvasElement.querySelector<SVGPathElement>(
|
|
104
|
+
'.line-chart-group path[stroke-dasharray="5 5"]'
|
|
105
|
+
)
|
|
106
|
+
expect(outgoingPath.getTotalLength()).toBeGreaterThan(1)
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
expect(effect.getByLabelText('Apply style to')).toHaveValue('outgoing')
|
|
110
|
+
await performAndAssert(
|
|
111
|
+
'A newly added rule can also style the incoming interval',
|
|
112
|
+
() => getIncomingPath(canvasElement)?.getAttribute('stroke-dasharray'),
|
|
113
|
+
() => userEvent.selectOptions(effect.getByLabelText('Apply style to'), ''),
|
|
114
|
+
(before, after) => before === '0' && after === '5 5',
|
|
115
|
+
() => expect(getIncomingPath(canvasElement).getTotalLength()).toBeGreaterThan(1)
|
|
116
|
+
)
|
|
117
|
+
await userEvent.selectOptions(effect.getByLabelText('Style', { exact: true }), 'Open Circles')
|
|
118
|
+
expect(effect.queryByLabelText('Apply style to')).not.toBeInTheDocument()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -283,23 +283,29 @@
|
|
|
283
283
|
"visualizationType": "Sankey",
|
|
284
284
|
"theme": "theme-purple",
|
|
285
285
|
"fontSize": "medium",
|
|
286
|
+
"enableTooltips": true,
|
|
287
|
+
"general": {
|
|
288
|
+
"palette": {
|
|
289
|
+
"isReversed": true,
|
|
290
|
+
"version": "2.0",
|
|
291
|
+
"name": "sequential_bluereverse"
|
|
292
|
+
}
|
|
293
|
+
},
|
|
286
294
|
"sankey": {
|
|
287
|
-
"title": {
|
|
288
|
-
"defaultColor": "black"
|
|
289
|
-
},
|
|
290
295
|
"iterations": 1,
|
|
291
296
|
"rxValue": 0.9,
|
|
292
|
-
"
|
|
293
|
-
"width": 900,
|
|
294
|
-
"height": 700
|
|
295
|
-
},
|
|
297
|
+
"horizontalScrollWidth": 900,
|
|
296
298
|
"margin": {
|
|
297
299
|
"margin_y": 25,
|
|
298
300
|
"margin_x": 0
|
|
299
301
|
},
|
|
302
|
+
"columns": {
|
|
303
|
+
"source": "example_source",
|
|
304
|
+
"target": "example_target",
|
|
305
|
+
"value": "example_value"
|
|
306
|
+
},
|
|
300
307
|
"nodeSize": {
|
|
301
|
-
"nodeWidth": 26
|
|
302
|
-
"nodeHeight": 40
|
|
308
|
+
"nodeWidth": 26
|
|
303
309
|
},
|
|
304
310
|
"nodePadding": 55,
|
|
305
311
|
"nodeFontColor": "black",
|
|
@@ -314,8 +320,12 @@
|
|
|
314
320
|
"opacity": {
|
|
315
321
|
"nodeOpacityDefault": 1,
|
|
316
322
|
"nodeOpacityInactive": 0.1,
|
|
317
|
-
"LinkOpacityDefault":
|
|
323
|
+
"LinkOpacityDefault": 0.6,
|
|
318
324
|
"LinkOpacityInactive": 0.1
|
|
325
|
+
},
|
|
326
|
+
"nodeValueStyle": {
|
|
327
|
+
"textBefore": "(",
|
|
328
|
+
"textAfter": ")"
|
|
319
329
|
}
|
|
320
330
|
},
|
|
321
331
|
"visual": {
|
|
@@ -346,48 +346,44 @@
|
|
|
346
346
|
|
|
347
347
|
"sankey_test_data": [
|
|
348
348
|
{
|
|
349
|
-
"
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
"target": "No Recovery",
|
|
388
|
-
"value": 200
|
|
389
|
-
}
|
|
390
|
-
]
|
|
349
|
+
"example_source": "Initial Population",
|
|
350
|
+
"example_target": "Screened",
|
|
351
|
+
"example_value": 10000
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"example_source": "Initial Population",
|
|
355
|
+
"example_target": "Not Screened",
|
|
356
|
+
"example_value": 5000
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"example_source": "Screened",
|
|
360
|
+
"example_target": "Positive Result",
|
|
361
|
+
"example_value": 1500
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
"example_source": "Screened",
|
|
365
|
+
"example_target": "Negative Result",
|
|
366
|
+
"example_value": 8500
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"example_source": "Positive Result",
|
|
370
|
+
"example_target": "Treated",
|
|
371
|
+
"example_value": 1200
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"example_source": "Positive Result",
|
|
375
|
+
"example_target": "Not Treated",
|
|
376
|
+
"example_value": 300
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"example_source": "Treated",
|
|
380
|
+
"example_target": "Recovery",
|
|
381
|
+
"example_value": 1000
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"example_source": "Treated",
|
|
385
|
+
"example_target": "No Recovery",
|
|
386
|
+
"example_value": 200
|
|
391
387
|
}
|
|
392
388
|
],
|
|
393
389
|
|