@cdc/chart 4.26.4 → 4.26.6
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 +353 -29
- package/LICENSE +201 -0
- package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
- package/dist/cdcchart.js +37885 -35117
- package/examples/feature/heatmap/average-age-categorical.json +313 -0
- package/examples/feature/heatmap/calendar-heatmap.json +134 -0
- package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
- package/examples/feature/heatmap/sparse-aggregation.json +158 -0
- package/examples/private/bad-y-axis.json +543 -0
- package/examples/private/bar-chart-negative-value.json +455 -0
- package/examples/private/bump-chart.json +1116 -0
- package/examples/private/test-123.json +624 -0
- package/package.json +4 -3
- package/src/CdcChart.tsx +5 -4
- package/src/CdcChartComponent.tsx +166 -62
- package/src/_stories/Chart.AltText.stories.tsx +136 -0
- package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
- package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
- package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
- package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +29 -0
- package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
- package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
- package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
- package/src/_stories/ChartAxisTitles.smoke.stories.tsx +13 -0
- package/src/_stories/ChartBar.Editor.stories.tsx +63 -0
- package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
- package/src/_stories/ChartBrush.smoke.stories.tsx +13 -4
- package/src/_stories/_mock/alt_text_metadata.json +38 -0
- package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
- package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
- package/src/_stories/_mock/heatmap.json +156 -0
- package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
- package/src/_stories/_mock/sankey_mock.json +78 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
- package/src/components/Annotations/components/AnnotationDraggable.tsx +220 -120
- package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
- package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
- package/src/components/Axis/LeftAxis.tsx +17 -11
- package/src/components/Axis/LeftAxisGridlines.tsx +22 -12
- package/src/components/Axis/RightAxis.tsx +3 -0
- package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
- package/src/components/Brush/BrushSelector.tsx +88 -187
- package/src/components/Brush/brushInteraction.ts +22 -0
- package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
- package/src/components/EditorPanel/EditorPanel.tsx +677 -185
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +114 -52
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -0
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +5 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -1
- package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
- package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
- package/src/components/EditorPanel/components/panels.scss +10 -0
- package/src/components/EditorPanel/editor-panel.scss +47 -0
- package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +61 -0
- package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +74 -0
- package/src/components/EditorPanel/useEditorPermissions.test.tsx +315 -0
- package/src/components/EditorPanel/useEditorPermissions.ts +77 -21
- package/src/components/HeatMap/components/HeatMap.tsx +767 -0
- package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +128 -0
- package/src/components/HeatMap/heatmap.constants.ts +13 -0
- package/src/components/HeatMap/heatmap.css +85 -0
- package/src/components/HeatMap/helpers/index.ts +261 -0
- package/src/components/HeatMap/index.tsx +5 -0
- package/src/components/HeatMap/tests/HeatMap.test.tsx +1072 -0
- package/src/components/HeatMap/tests/helpers.test.ts +167 -0
- package/src/components/Legend/Legend.Component.tsx +2 -2
- package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +19 -22
- package/src/components/LineChart/helpers.test.ts +574 -0
- package/src/components/LineChart/helpers.ts +39 -16
- package/src/components/LineChart/index.tsx +28 -5
- package/src/components/LinearChart/tests/LinearChart.test.tsx +137 -33
- package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
- package/src/components/LinearChart.tsx +103 -47
- package/src/components/PieChart/PieChart.tsx +4 -1
- package/src/components/RadarChart/RadarChart.tsx +3 -1
- package/src/components/Regions/components/Regions.tsx +195 -41
- package/src/components/Sankey/components/Sankey.tsx +7 -3
- package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
- package/src/components/ScatterPlot/ScatterPlot.jsx +3 -3
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +33 -3
- package/src/components/SmallMultiples/SmallMultiples.css +12 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +50 -15
- package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
- package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
- package/src/components/Sparkline/components/SparkLine.tsx +4 -9
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
- package/src/data/initial-state.js +12 -0
- package/src/helpers/axisLabelFontSize.ts +8 -0
- package/src/helpers/bumpChartTooltip.ts +54 -0
- package/src/helpers/calculateLeftYAxisWidth.ts +13 -3
- package/src/helpers/colorAssignmentHelpers.ts +102 -0
- package/src/helpers/dataHelpers.ts +11 -1
- package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
- package/src/helpers/getAxisMaxOverride.ts +16 -0
- package/src/helpers/getCleanTopTickMax.ts +64 -0
- package/src/helpers/getColorScale.ts +18 -9
- package/src/helpers/getHasBoundarySuppression.ts +26 -0
- package/src/helpers/getMinMax.ts +26 -25
- package/src/helpers/getYAxisDomainData.ts +38 -0
- package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
- package/src/helpers/handleChartAriaLabels.ts +23 -10
- package/src/helpers/hasSpacedInlineLabel.ts +10 -0
- package/src/helpers/seriesColumnSettings.ts +5 -4
- package/src/helpers/seriesHighlight.ts +26 -0
- package/src/helpers/smallMultiplesHelpers.ts +5 -0
- package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
- package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
- package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
- package/src/helpers/tests/dataHelpers.test.ts +135 -0
- package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
- package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
- package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
- package/src/helpers/tests/getColorScale.test.ts +197 -0
- package/src/helpers/tests/getMinMax.test.ts +211 -0
- package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
- package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
- package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
- package/src/helpers/tests/hasSpacedInlineLabel.test.ts +75 -0
- package/src/helpers/tests/seriesColumnSettings.test.ts +16 -2
- package/src/helpers/tests/seriesHighlight.test.ts +61 -0
- package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
- package/src/hooks/tests/useRightAxis.test.tsx +127 -0
- package/src/hooks/tests/useScales.test.tsx +383 -0
- package/src/hooks/useRightAxis.ts +30 -13
- package/src/hooks/useScales.ts +48 -21
- package/src/hooks/useTooltip.tsx +3 -1
- package/src/index.jsx +5 -2
- package/src/scss/main.scss +32 -49
- package/src/test/CdcChart.dataTable.test.tsx +122 -0
- package/src/types/ChartConfig.ts +24 -1
- package/src/types/ChartContext.ts +5 -0
- package/src/helpers/getYAxisAutoPadding.ts +0 -53
package/src/scss/main.scss
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
@import '@cdc/core/styles/utils/breakpoints';
|
|
2
2
|
@import '@cdc/core/styles/layout/wrapper-padding';
|
|
3
|
+
@import '@cdc/core/styles/layout/callout';
|
|
3
4
|
|
|
4
5
|
.form-container {
|
|
5
6
|
overflow-y: auto;
|
|
@@ -24,33 +25,17 @@
|
|
|
24
25
|
background: transparent;
|
|
25
26
|
|
|
26
27
|
.cdc-callout {
|
|
27
|
-
|
|
28
|
-
border: 1px solid #dff2f6;
|
|
29
|
-
margin: 0;
|
|
30
|
-
padding: 1.25rem;
|
|
31
|
-
border-radius: 0.25rem;
|
|
32
|
-
position: relative;
|
|
33
|
-
background: transparent;
|
|
34
|
-
|
|
35
|
-
.cdc-callout__flag {
|
|
36
|
-
position: absolute;
|
|
37
|
-
top: -0.36rem;
|
|
38
|
-
right: 1.08rem;
|
|
39
|
-
width: 1.84rem;
|
|
40
|
-
height: auto;
|
|
41
|
-
}
|
|
28
|
+
--cdc-callout-background: transparent;
|
|
42
29
|
|
|
43
30
|
.cove-visualization__title,
|
|
44
31
|
.cove-visualization__header {
|
|
45
32
|
background: transparent;
|
|
46
33
|
border: 0;
|
|
47
|
-
color: var(--cool-gray-90, #1f2937);
|
|
48
34
|
margin: 0 0 1rem;
|
|
49
35
|
padding: 0;
|
|
50
36
|
border-radius: 0;
|
|
51
37
|
|
|
52
38
|
h2 {
|
|
53
|
-
color: var(--cool-gray-90, #1f2937);
|
|
54
39
|
font-family: var(--fonts-nunito, var(--app-font-secondary));
|
|
55
40
|
font-size: 1.1rem;
|
|
56
41
|
font-weight: 700;
|
|
@@ -64,11 +49,17 @@
|
|
|
64
49
|
margin-bottom: 0 !important;
|
|
65
50
|
}
|
|
66
51
|
|
|
52
|
+
.y-axis-top-title {
|
|
53
|
+
font-family: var(--fonts-nunito, var(--app-font-secondary));
|
|
54
|
+
font-weight: 700;
|
|
55
|
+
line-height: 1.4;
|
|
56
|
+
margin: 0 0 0.5rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
67
59
|
.legend-top {
|
|
68
60
|
.legend-wrapper .tooltip-boundary {
|
|
69
61
|
display: flex;
|
|
70
62
|
flex-wrap: wrap;
|
|
71
|
-
row-gap: var(--cove-visualization-section-gap, 1.5rem);
|
|
72
63
|
order: 2;
|
|
73
64
|
|
|
74
65
|
aside {
|
|
@@ -188,7 +179,7 @@
|
|
|
188
179
|
white-space: nowrap;
|
|
189
180
|
}
|
|
190
181
|
|
|
191
|
-
.legend-item
|
|
182
|
+
.legend-item > .legend-item {
|
|
192
183
|
display: inline-block;
|
|
193
184
|
flex: 0 0 auto;
|
|
194
185
|
}
|
|
@@ -222,11 +213,11 @@
|
|
|
222
213
|
left: 0%;
|
|
223
214
|
top: 108%;
|
|
224
215
|
|
|
225
|
-
|
|
216
|
+
& > * {
|
|
226
217
|
margin: 0;
|
|
227
218
|
}
|
|
228
219
|
|
|
229
|
-
|
|
220
|
+
& > p,
|
|
230
221
|
a {
|
|
231
222
|
margin-left: 5px;
|
|
232
223
|
}
|
|
@@ -235,7 +226,6 @@
|
|
|
235
226
|
}
|
|
236
227
|
|
|
237
228
|
.dynamic-legend-list {
|
|
238
|
-
|
|
239
229
|
// overide traditional legend item that uses !important
|
|
240
230
|
.legend-item {
|
|
241
231
|
align-items: flex-end !important;
|
|
@@ -268,7 +258,7 @@
|
|
|
268
258
|
font-size: 1em;
|
|
269
259
|
vertical-align: middle;
|
|
270
260
|
|
|
271
|
-
|
|
261
|
+
& > span {
|
|
272
262
|
display: flex;
|
|
273
263
|
justify-items: center;
|
|
274
264
|
align-items: center;
|
|
@@ -278,25 +268,25 @@
|
|
|
278
268
|
max-height: 1px;
|
|
279
269
|
}
|
|
280
270
|
|
|
281
|
-
|
|
271
|
+
& > span[class*='Asterisk'] {
|
|
282
272
|
transform: scale(1.8);
|
|
283
273
|
margin-top: 15px;
|
|
284
274
|
}
|
|
285
275
|
|
|
286
|
-
|
|
276
|
+
& > span[class*='Dagger'] {
|
|
287
277
|
margin-top: 2px;
|
|
288
278
|
}
|
|
289
279
|
|
|
290
|
-
|
|
280
|
+
& > span[class*='Sign'] {
|
|
291
281
|
margin-top: 1px;
|
|
292
282
|
}
|
|
293
283
|
|
|
294
|
-
|
|
284
|
+
& > svg {
|
|
295
285
|
width: 50px;
|
|
296
286
|
height: 23px;
|
|
297
287
|
}
|
|
298
288
|
|
|
299
|
-
|
|
289
|
+
& > p {
|
|
300
290
|
margin: 0;
|
|
301
291
|
}
|
|
302
292
|
}
|
|
@@ -325,8 +315,8 @@
|
|
|
325
315
|
min-width: 0;
|
|
326
316
|
max-width: 100%;
|
|
327
317
|
|
|
328
|
-
>div,
|
|
329
|
-
>aside {
|
|
318
|
+
> div,
|
|
319
|
+
> aside {
|
|
330
320
|
min-width: 0;
|
|
331
321
|
max-width: 100%;
|
|
332
322
|
}
|
|
@@ -339,7 +329,7 @@
|
|
|
339
329
|
|
|
340
330
|
&.legend-top:not(.legend-hidden) {
|
|
341
331
|
.legend-wrapper {
|
|
342
|
-
|
|
332
|
+
& > div {
|
|
343
333
|
order: 2;
|
|
344
334
|
width: 100%;
|
|
345
335
|
}
|
|
@@ -354,7 +344,7 @@
|
|
|
354
344
|
|
|
355
345
|
&.legend-left:not(.legend-hidden) {
|
|
356
346
|
.legend-wrapper {
|
|
357
|
-
|
|
347
|
+
& > div {
|
|
358
348
|
order: 2;
|
|
359
349
|
width: 75%;
|
|
360
350
|
}
|
|
@@ -369,7 +359,7 @@
|
|
|
369
359
|
|
|
370
360
|
&.legend-right:not(.legend-hidden) {
|
|
371
361
|
.legend-wrapper {
|
|
372
|
-
|
|
362
|
+
& > div {
|
|
373
363
|
order: 1;
|
|
374
364
|
width: 75%;
|
|
375
365
|
}
|
|
@@ -391,7 +381,7 @@
|
|
|
391
381
|
flex-wrap: nowrap;
|
|
392
382
|
flex-direction: column-reverse;
|
|
393
383
|
|
|
394
|
-
|
|
384
|
+
& > div.tooltip-boundary {
|
|
395
385
|
margin-top: 1.5em;
|
|
396
386
|
}
|
|
397
387
|
}
|
|
@@ -401,14 +391,10 @@
|
|
|
401
391
|
flex-direction: column;
|
|
402
392
|
}
|
|
403
393
|
|
|
404
|
-
&.legend-hidden>svg {
|
|
394
|
+
&.legend-hidden > svg {
|
|
405
395
|
width: 100% !important;
|
|
406
396
|
}
|
|
407
397
|
|
|
408
|
-
&.dashboard-brush {
|
|
409
|
-
margin-bottom: 2.5em;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
398
|
// Brush touch support
|
|
413
399
|
.brush-overlay {
|
|
414
400
|
touch-action: none;
|
|
@@ -434,7 +420,7 @@
|
|
|
434
420
|
pointer-events: none;
|
|
435
421
|
}
|
|
436
422
|
|
|
437
|
-
>svg {
|
|
423
|
+
> svg {
|
|
438
424
|
overflow: visible;
|
|
439
425
|
font-size: 14px;
|
|
440
426
|
margin: 1rem 0 2rem;
|
|
@@ -449,7 +435,7 @@
|
|
|
449
435
|
}
|
|
450
436
|
|
|
451
437
|
&.chart-line--hover {
|
|
452
|
-
>svg circle {
|
|
438
|
+
> svg circle {
|
|
453
439
|
opacity: 0;
|
|
454
440
|
|
|
455
441
|
&:hover {
|
|
@@ -459,12 +445,12 @@
|
|
|
459
445
|
}
|
|
460
446
|
|
|
461
447
|
&.chart-line--always {
|
|
462
|
-
>svg circle {
|
|
448
|
+
> svg circle {
|
|
463
449
|
opacity: 1;
|
|
464
450
|
}
|
|
465
451
|
|
|
466
452
|
// Animations for line chart and data points
|
|
467
|
-
>svg.animated {
|
|
453
|
+
> svg.animated {
|
|
468
454
|
circle {
|
|
469
455
|
opacity: 0;
|
|
470
456
|
animation: revealLolly 0.25s linear forwards;
|
|
@@ -525,7 +511,7 @@
|
|
|
525
511
|
|
|
526
512
|
@include breakpointClass(md) {
|
|
527
513
|
.visualization-container {
|
|
528
|
-
>svg {
|
|
514
|
+
> svg {
|
|
529
515
|
font-size: 16px;
|
|
530
516
|
width: 75%;
|
|
531
517
|
order: 1;
|
|
@@ -608,7 +594,6 @@
|
|
|
608
594
|
}
|
|
609
595
|
|
|
610
596
|
&.animated {
|
|
611
|
-
|
|
612
597
|
.vertical path,
|
|
613
598
|
.vertical rect,
|
|
614
599
|
.vertical foreignObject div {
|
|
@@ -626,7 +611,6 @@
|
|
|
626
611
|
}
|
|
627
612
|
|
|
628
613
|
&.animate {
|
|
629
|
-
|
|
630
614
|
path,
|
|
631
615
|
rect,
|
|
632
616
|
foreignObject div {
|
|
@@ -685,7 +669,7 @@
|
|
|
685
669
|
text-align: center;
|
|
686
670
|
transform: scale(1);
|
|
687
671
|
|
|
688
|
-
|
|
672
|
+
> .visx-group[style] {
|
|
689
673
|
transform: scale(1);
|
|
690
674
|
}
|
|
691
675
|
}
|
|
@@ -707,7 +691,7 @@
|
|
|
707
691
|
}
|
|
708
692
|
|
|
709
693
|
.cove-visualization.type-chart.type-sparkline {
|
|
710
|
-
&.lg .visualization-container>svg {
|
|
694
|
+
&.lg .visualization-container > svg {
|
|
711
695
|
width: 100%;
|
|
712
696
|
}
|
|
713
697
|
|
|
@@ -738,7 +722,6 @@
|
|
|
738
722
|
transform: translate(-20px, 0);
|
|
739
723
|
}
|
|
740
724
|
}
|
|
741
|
-
|
|
742
725
|
}
|
|
743
726
|
|
|
744
727
|
.subtext,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/react'
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
import CdcChart from '../CdcChartComponent'
|
|
5
|
+
|
|
6
|
+
const dataTableProps = vi.hoisted(() => {
|
|
7
|
+
Object.defineProperty((globalThis as any).HTMLCanvasElement.prototype, 'getContext', {
|
|
8
|
+
configurable: true,
|
|
9
|
+
value: () => ({
|
|
10
|
+
measureText: (text = '') => ({ width: String(text).length * 8 })
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
return [] as any[]
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
vi.mock('@cdc/core/components/DataTable', async () => {
|
|
18
|
+
const React = await vi.importActual<typeof import('react')>('react')
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
default: props => {
|
|
22
|
+
dataTableProps.push(props)
|
|
23
|
+
return React.createElement('div', { 'data-testid': 'data-table-probe' })
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
vi.mock('@visx/responsive/lib/components/ParentSize', () => ({
|
|
29
|
+
default: ({ children }) => children({ width: 640, height: 360 })
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
vi.mock('../components/LinearChart', async () => {
|
|
33
|
+
const React = await vi.importActual<typeof import('react')>('react')
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
default: React.forwardRef(() => React.createElement('div', { 'data-testid': 'mock-linear-chart' }))
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('CdcChart data table dataset wiring', () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
dataTableProps.length = 0
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('passes the selected dashboard dataset metadata to DataTable', async () => {
|
|
46
|
+
const dataset = {
|
|
47
|
+
data: [{ category: 'A', value: 1 }],
|
|
48
|
+
dataFileName: 'stale-chart-source.json',
|
|
49
|
+
dataFileSourceType: 'url',
|
|
50
|
+
dataUrl: '/wcms/vizdata/chart-source.json',
|
|
51
|
+
runtimeDataUrl: '/wcms/vizdata/chart-runtime.json'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
render(
|
|
55
|
+
<CdcChart
|
|
56
|
+
config={
|
|
57
|
+
{
|
|
58
|
+
type: 'chart',
|
|
59
|
+
visualizationType: 'Bar',
|
|
60
|
+
title: 'Dataset-backed Chart',
|
|
61
|
+
dataKey: 'chartDataset',
|
|
62
|
+
data: dataset.data,
|
|
63
|
+
xAxis: { dataKey: 'category' },
|
|
64
|
+
series: [{ dataKey: 'value' }],
|
|
65
|
+
table: {
|
|
66
|
+
show: true,
|
|
67
|
+
expanded: true,
|
|
68
|
+
download: true,
|
|
69
|
+
label: 'Data Table',
|
|
70
|
+
indexLabel: ''
|
|
71
|
+
}
|
|
72
|
+
} as any
|
|
73
|
+
}
|
|
74
|
+
datasets={{ chartDataset: dataset } as any}
|
|
75
|
+
isDashboard={true}
|
|
76
|
+
interactionLabel='chart-dataset-test'
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
await waitFor(() => expect(dataTableProps.length).toBeGreaterThan(0))
|
|
81
|
+
|
|
82
|
+
expect(dataTableProps.at(-1).dataConfig).toMatchObject({
|
|
83
|
+
runtimeDataUrl: '/wcms/vizdata/chart-runtime.json'
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('keeps chart footnotes visible when the data table is collapsed by default', async () => {
|
|
88
|
+
render(
|
|
89
|
+
<CdcChart
|
|
90
|
+
config={
|
|
91
|
+
{
|
|
92
|
+
type: 'chart',
|
|
93
|
+
visualizationType: 'Bar',
|
|
94
|
+
title: 'Footnote-backed Chart',
|
|
95
|
+
data: [{ category: 'A', value: 1 }],
|
|
96
|
+
xAxis: { dataKey: 'category' },
|
|
97
|
+
series: [{ dataKey: 'value' }],
|
|
98
|
+
legacyFootnotes: 'Legacy chart footnote',
|
|
99
|
+
footnotes: {
|
|
100
|
+
staticFootnotes: [{ text: 'Structured chart footnote' }]
|
|
101
|
+
},
|
|
102
|
+
table: {
|
|
103
|
+
show: true,
|
|
104
|
+
expanded: false,
|
|
105
|
+
download: true,
|
|
106
|
+
label: 'Data Table',
|
|
107
|
+
indexLabel: ''
|
|
108
|
+
}
|
|
109
|
+
} as any
|
|
110
|
+
}
|
|
111
|
+
interactionLabel='chart-footnote-collapse-test'
|
|
112
|
+
/>
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
await waitFor(() => {
|
|
116
|
+
expect(dataTableProps.at(-1)?.expandDataTable).toBe(false)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
expect(await screen.findByText('Legacy chart footnote')).toBeInTheDocument()
|
|
120
|
+
expect(await screen.findByText('Structured chart footnote')).toBeInTheDocument()
|
|
121
|
+
})
|
|
122
|
+
})
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Axis } from '@cdc/core/types/Axis'
|
|
1
|
+
import { type Axis } from '@cdc/core/types/Axis'
|
|
2
2
|
import { MarkupConfig } from '@cdc/core/types/MarkupVariable'
|
|
3
3
|
import { type ForestPlotConfigSettings } from './ForestPlot'
|
|
4
4
|
import { type HorizonConfigSettings } from './Horizon'
|
|
@@ -18,6 +18,8 @@ type General = CoreGeneral & {
|
|
|
18
18
|
isReversed?: boolean
|
|
19
19
|
customColors?: string[]
|
|
20
20
|
customColorsOrdered?: string[]
|
|
21
|
+
colorAssignmentMode?: 'ordered' | 'by-value'
|
|
22
|
+
colorAssignments?: { key: string; color: string }[]
|
|
21
23
|
}
|
|
22
24
|
useIntelligentLineChartLabels?: boolean
|
|
23
25
|
}
|
|
@@ -41,6 +43,7 @@ export type VisualizationType =
|
|
|
41
43
|
| 'Box Plot'
|
|
42
44
|
| 'Deviation Bar'
|
|
43
45
|
| 'Forest Plot'
|
|
46
|
+
| 'HeatMap'
|
|
44
47
|
| 'Horizon Chart'
|
|
45
48
|
| 'Line'
|
|
46
49
|
| 'Paired Bar'
|
|
@@ -53,6 +56,18 @@ export type VisualizationType =
|
|
|
53
56
|
| 'Sankey'
|
|
54
57
|
| 'Bump Chart'
|
|
55
58
|
| 'Warming Stripes'
|
|
59
|
+
|
|
60
|
+
export type HeatMapXAxisPosition = 'top' | 'bottom'
|
|
61
|
+
|
|
62
|
+
export type HeatMapConfig = {
|
|
63
|
+
cellPadding?: number
|
|
64
|
+
rowLabelGap?: number
|
|
65
|
+
columnLabelGap?: number
|
|
66
|
+
colorBucketCount?: number
|
|
67
|
+
xAxisPosition?: HeatMapXAxisPosition
|
|
68
|
+
showCellValues?: boolean
|
|
69
|
+
}
|
|
70
|
+
|
|
56
71
|
export interface PreliminaryDataItem {
|
|
57
72
|
column: string
|
|
58
73
|
displayLegend: boolean
|
|
@@ -70,6 +85,7 @@ export interface PreliminaryDataItem {
|
|
|
70
85
|
hideLineStyle: boolean
|
|
71
86
|
circleSize: number
|
|
72
87
|
displayGray: boolean
|
|
88
|
+
weight?: number
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
type DataFormat = {
|
|
@@ -143,7 +159,11 @@ type Visual = {
|
|
|
143
159
|
maximumShapeAmount: 7
|
|
144
160
|
}
|
|
145
161
|
|
|
162
|
+
import { type AltTextConfig } from '@cdc/core/types/AltText'
|
|
163
|
+
export type { AltTextConfig }
|
|
164
|
+
|
|
146
165
|
export type AllChartsConfig = {
|
|
166
|
+
altText?: AltTextConfig
|
|
147
167
|
annotations: Annotation[]
|
|
148
168
|
animate: boolean
|
|
149
169
|
general: General
|
|
@@ -174,6 +194,9 @@ export type AllChartsConfig = {
|
|
|
174
194
|
footnotes: Footnotes
|
|
175
195
|
forestPlot: ForestPlotConfigSettings
|
|
176
196
|
formattedData: Object[] & { urlFiltered: boolean }
|
|
197
|
+
originalFormattedData?: Object[]
|
|
198
|
+
yAxisDomainData?: Object[]
|
|
199
|
+
heatmap?: HeatMapConfig
|
|
177
200
|
heights: {
|
|
178
201
|
vertical: number
|
|
179
202
|
horizontal: number
|
|
@@ -20,6 +20,8 @@ type SharedChartContext = {
|
|
|
20
20
|
currentViewport?: 'lg' | 'md' | 'sm' | 'xs' | 'xxs'
|
|
21
21
|
vizViewport?: 'lg' | 'md' | 'sm' | 'xs' | 'xxs'
|
|
22
22
|
dashboardConfig?: DashboardConfig
|
|
23
|
+
excludedData?: Object[]
|
|
24
|
+
filteredData?: Object[]
|
|
23
25
|
// process top level chart aria label for each chart type
|
|
24
26
|
handleChartAriaLabels: (config: any) => string
|
|
25
27
|
handleDragStateChange: (isDragging: any) => void
|
|
@@ -37,6 +39,7 @@ type SharedChartContext = {
|
|
|
37
39
|
svgRef?: React.RefObject<SVGSVGElement>
|
|
38
40
|
handleSmallMultipleHover?: (xAxisValue: any, yCoordinate: number) => void
|
|
39
41
|
visibleAnnotations?: Annotation[]
|
|
42
|
+
yAxisTickValues?: number[]
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
// Line Chart Specific Context
|
|
@@ -56,6 +59,7 @@ type LineChartContext = SharedChartContext & {
|
|
|
56
59
|
transformedData: TransformedData[]
|
|
57
60
|
updateConfig: Function
|
|
58
61
|
visualizationType: 'Line'
|
|
62
|
+
yAxisDomainData?: Object[]
|
|
59
63
|
colorPalettes: Record<string, string[]>
|
|
60
64
|
twoColorPalette: Record<string, string[]>
|
|
61
65
|
}
|
|
@@ -86,4 +90,5 @@ export type ChartContext =
|
|
|
86
90
|
transformedData?: TransformedData[]
|
|
87
91
|
twoColorPalette: any
|
|
88
92
|
updateConfig?: Function
|
|
93
|
+
yAxisDomainData?: Object[]
|
|
89
94
|
})
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { ChartConfig } from '../types/ChartConfig'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Calculates the Y-axis auto padding to prevent data labels from overlapping with axis tick labels.
|
|
5
|
-
* This is used when inline labels are enabled and there's potential for overlap.
|
|
6
|
-
*
|
|
7
|
-
* @param yScale - The D3 scale object for the Y-axis (must have .ticks() method)
|
|
8
|
-
* @param handleNumTicks - The number of ticks to display on the axis
|
|
9
|
-
* @param maxValue - The maximum data value (from useReduceData)
|
|
10
|
-
* @param minValue - The minimum data value (from useReduceData)
|
|
11
|
-
* @param config - The chart configuration object
|
|
12
|
-
* @returns The calculated auto padding percentage (0-100+), or 0 if no padding needed
|
|
13
|
-
*/
|
|
14
|
-
export const getYAxisAutoPadding = (
|
|
15
|
-
yScale: any,
|
|
16
|
-
handleNumTicks: number,
|
|
17
|
-
maxValue: number,
|
|
18
|
-
minValue: number,
|
|
19
|
-
config: ChartConfig
|
|
20
|
-
): number => {
|
|
21
|
-
// Early returns for cases where auto padding is not needed
|
|
22
|
-
if (!yScale?.ticks || config.orientation === 'horizontal' || config.yAxis?.max) {
|
|
23
|
-
return 0
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const ticks = yScale.ticks(handleNumTicks)
|
|
27
|
-
|
|
28
|
-
if (!Array.isArray(ticks) || ticks.length === 0) {
|
|
29
|
-
return 0
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// minimum percentage of the max value that the distance should be from the top grid line
|
|
33
|
-
const MINIMUM_DISTANCE_PERCENTAGE = 0.025
|
|
34
|
-
|
|
35
|
-
const topGridLine = Math.max(...ticks)
|
|
36
|
-
const needsPaddingThreshold = topGridLine - maxValue * MINIMUM_DISTANCE_PERCENTAGE
|
|
37
|
-
const maxValueIsGreaterThanThreshold = maxValue > needsPaddingThreshold
|
|
38
|
-
|
|
39
|
-
if (!maxValueIsGreaterThanThreshold) return 0
|
|
40
|
-
|
|
41
|
-
const tickGap = ticks.length === 1 ? ticks[0] : ticks[1] - ticks[0]
|
|
42
|
-
const nextTick = Math.max(...ticks) + tickGap
|
|
43
|
-
const divideBy = minValue < 0 ? maxValue / 2 : maxValue
|
|
44
|
-
const calculatedPadding = (nextTick - maxValue) / divideBy
|
|
45
|
-
|
|
46
|
-
// if auto padding is too close to next tick, add one more ticks worth of padding
|
|
47
|
-
const newPadding =
|
|
48
|
-
calculatedPadding > MINIMUM_DISTANCE_PERCENTAGE ? calculatedPadding : calculatedPadding + tickGap / divideBy
|
|
49
|
-
|
|
50
|
-
/* sometimes even though the padding is getting to the next tick exactly,
|
|
51
|
-
d3 still doesn't show the tick. we add 0.1 to ensure to tip it over the edge */
|
|
52
|
-
return newPadding * 100 + 0.1
|
|
53
|
-
}
|