@cdc/chart 4.22.10 → 4.23.1
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/README.md +5 -5
- package/dist/495.js +3 -0
- package/dist/703.js +1 -0
- package/dist/cdcchart.js +723 -6
- package/examples/age-adjusted-rates.json +1486 -1218
- package/examples/box-plot-data.json +71 -0
- package/examples/box-plot.csv +5 -0
- package/examples/{private/yaxis-test.json → box-plot.json} +46 -54
- package/examples/case-rate-example-config.json +1 -1
- package/examples/covid-confidence-example-config.json +33 -33
- package/examples/covid-example-config.json +34 -34
- package/examples/covid-example-data-confidence.json +30 -30
- package/examples/covid-example-data.json +20 -20
- package/examples/cutoff-example-config.json +36 -36
- package/examples/cutoff-example-data.json +36 -36
- package/examples/date-exclusions-config.json +1 -1
- package/examples/dynamic-legends.json +124 -124
- package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +191 -197
- package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +230 -240
- package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +239 -247
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +138 -136
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +79 -79
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +80 -80
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +67 -67
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +179 -110
- package/examples/gallery/lollipop/lollipop-style-horizontal.json +215 -219
- package/examples/gallery/paired-bar/paired-bar-chart.json +195 -195
- package/examples/horizontal-chart.json +35 -35
- package/examples/horizontal-stacked-bar-chart.json +34 -34
- package/examples/line-chart.json +75 -75
- package/examples/new-data.csv +17 -0
- package/examples/newdata.json +90 -0
- package/examples/paired-bar-data.json +16 -14
- package/examples/paired-bar-example.json +48 -48
- package/examples/paired-bar-formatted.json +36 -36
- package/examples/planet-chart-horizontal-example-config.json +33 -33
- package/examples/planet-combo-example-config.json +34 -31
- package/examples/planet-example-config.json +35 -33
- package/examples/planet-example-data.json +56 -56
- package/examples/planet-pie-example-config.json +28 -28
- package/examples/stacked-vertical-bar-example.json +1 -1
- package/examples/temp-example-config.json +61 -54
- package/examples/temp-example-data.json +1 -1
- package/package.json +3 -2
- package/src/CdcChart.tsx +449 -434
- package/src/components/BarChart.tsx +383 -497
- package/src/components/BoxPlot.js +92 -0
- package/src/components/DataTable.tsx +182 -197
- package/src/components/EditorPanel.js +1068 -722
- package/src/components/Filters.js +131 -0
- package/src/components/Legend.js +286 -329
- package/src/components/LineChart.tsx +143 -81
- package/src/components/LinearChart.tsx +432 -451
- package/src/components/PairedBarChart.tsx +197 -213
- package/src/components/PieChart.tsx +105 -151
- package/src/components/SparkLine.js +179 -201
- package/src/components/useIntersectionObserver.tsx +19 -20
- package/src/context.tsx +3 -3
- package/src/data/initial-state.js +44 -17
- package/src/hooks/useActiveElement.js +13 -13
- package/src/hooks/useChartClasses.js +34 -28
- package/src/hooks/useColorPalette.ts +56 -63
- package/src/hooks/useLegendClasses.js +18 -10
- package/src/hooks/useReduceData.ts +64 -77
- package/src/hooks/useRightAxis.js +25 -0
- package/src/hooks/useTopAxis.js +6 -0
- package/src/index.html +19 -19
- package/src/index.tsx +13 -16
- package/src/scss/DataTable.scss +6 -5
- package/src/scss/editor-panel.scss +71 -69
- package/src/scss/main.scss +188 -114
- package/src/scss/variables.scss +1 -1
- package/examples/private/line-test-data.json +0 -22
- package/examples/private/line-test-two.json +0 -216
- package/examples/private/line-test.json +0 -102
- package/examples/private/newtest.csv +0 -101
- package/examples/private/shawn.json +0 -1296
- package/examples/private/test.json +0 -10124
- package/examples/private/yaxis-testing.csv +0 -27
- package/examples/private/yaxis.json +0 -28
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { useContext, useEffect } from 'react'
|
|
2
|
+
import { BoxPlot } from '@visx/stats'
|
|
3
|
+
import { Group } from '@visx/group'
|
|
4
|
+
import { scaleBand, scaleLinear } from '@visx/scale'
|
|
5
|
+
import Context from '../context'
|
|
6
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
|
+
import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
|
|
8
|
+
import ReactTooltip from 'react-tooltip'
|
|
9
|
+
|
|
10
|
+
const CoveBoxPlot = ({ xScale, yScale }) => {
|
|
11
|
+
const { transformedData: data, config } = useContext(Context)
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
boxplot: { columnFirstQuartile, columnThirdQuartile, columnMax, columnMin, columnMedian, columnOutliers },
|
|
15
|
+
width,
|
|
16
|
+
height
|
|
17
|
+
} = config
|
|
18
|
+
|
|
19
|
+
const yMax = config.height - config.runtime.xAxis.size
|
|
20
|
+
const xMax = config.width - config.runtime.yAxis.size - config.yAxis.rightAxisSize
|
|
21
|
+
const boxWidth = xScale.bandwidth()
|
|
22
|
+
const constrainedWidth = Math.min(20, boxWidth)
|
|
23
|
+
const color_0 = colorPalettesChart[config?.palette][0] ? colorPalettesChart[config?.palette][0] : '#000'
|
|
24
|
+
|
|
25
|
+
// tooltips
|
|
26
|
+
const tooltip_id = `cdc-open-viz-tooltip-${config.runtime.uniqueId}`
|
|
27
|
+
const handleTooltip = d => {
|
|
28
|
+
return `
|
|
29
|
+
<strong>${d.columnCategory}</strong></br>
|
|
30
|
+
Q1: ${d.columnFirstQuartile}<br/>
|
|
31
|
+
Q3: ${d.columnThirdQuartile}<br/>
|
|
32
|
+
IQR: ${d.columnIqr}<br/>
|
|
33
|
+
Median: ${d.columnMedian}
|
|
34
|
+
`
|
|
35
|
+
}
|
|
36
|
+
return (
|
|
37
|
+
<ErrorBoundary component='BoxPlot'>
|
|
38
|
+
<Group className='boxplot' key='boxplot-wrapper'>
|
|
39
|
+
{config.boxplot.map((d, i) => {
|
|
40
|
+
const offset = boxWidth - constrainedWidth
|
|
41
|
+
return (
|
|
42
|
+
<BoxPlot
|
|
43
|
+
key={`box-plot-${i}`}
|
|
44
|
+
min={d.columnMin}
|
|
45
|
+
max={d.columnMax}
|
|
46
|
+
left={xScale(d.columnCategory) + config.yAxis.size + offset / 2 + 0.5}
|
|
47
|
+
firstQuartile={d.columnFirstQuartile}
|
|
48
|
+
thirdQuartile={d.columnThirdQuartile}
|
|
49
|
+
median={d.columnMedian}
|
|
50
|
+
boxWidth={constrainedWidth}
|
|
51
|
+
fill={color_0}
|
|
52
|
+
fillOpacity={0.5}
|
|
53
|
+
stroke='black'
|
|
54
|
+
strokeWidth={1}
|
|
55
|
+
valueScale={yScale}
|
|
56
|
+
outliers={d.columnOutliers}
|
|
57
|
+
outlierProps={{
|
|
58
|
+
style: {
|
|
59
|
+
fill: `${color_0}`,
|
|
60
|
+
opacity: 1
|
|
61
|
+
}
|
|
62
|
+
}}
|
|
63
|
+
medianProps={{
|
|
64
|
+
style: {
|
|
65
|
+
stroke: 'black'
|
|
66
|
+
}
|
|
67
|
+
}}
|
|
68
|
+
boxProps={{
|
|
69
|
+
style: {
|
|
70
|
+
stroke: 'black'
|
|
71
|
+
},
|
|
72
|
+
'data-tip': 'cool'
|
|
73
|
+
}}
|
|
74
|
+
maxProps={{
|
|
75
|
+
style: {
|
|
76
|
+
stroke: 'black'
|
|
77
|
+
}
|
|
78
|
+
}}
|
|
79
|
+
container
|
|
80
|
+
containerProps={{
|
|
81
|
+
'data-tip': handleTooltip(d),
|
|
82
|
+
'data-for': tooltip_id
|
|
83
|
+
}}
|
|
84
|
+
/>
|
|
85
|
+
)
|
|
86
|
+
})}
|
|
87
|
+
</Group>
|
|
88
|
+
</ErrorBoundary>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default CoveBoxPlot
|
|
@@ -1,244 +1,229 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
useBlockLayout
|
|
13
|
-
} from 'react-table';
|
|
14
|
-
import Papa from 'papaparse';
|
|
15
|
-
import { Base64 } from 'js-base64';
|
|
16
|
-
|
|
17
|
-
import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
|
|
18
|
-
import LegendCircle from '@cdc/core/components/LegendCircle';
|
|
19
|
-
|
|
20
|
-
import Context from '../context';
|
|
1
|
+
import React, { useContext, useEffect, useState, useMemo, memo, Fragment } from 'react'
|
|
2
|
+
import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
|
|
3
|
+
import Papa from 'papaparse'
|
|
4
|
+
import { Base64 } from 'js-base64'
|
|
5
|
+
|
|
6
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
|
+
import LegendCircle from '@cdc/core/components/LegendCircle'
|
|
8
|
+
|
|
9
|
+
import Context from '../context'
|
|
10
|
+
|
|
11
|
+
import CoveMediaControls from '@cdc/core/helpers/CoveMediaControls'
|
|
21
12
|
|
|
22
13
|
export default function DataTable() {
|
|
23
|
-
const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber:numberFormatter, colorPalettes } = useContext<any>(Context)
|
|
14
|
+
const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes, imageId } = useContext<any>(Context)
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const section = config.orientation ==='horizontal' ? 'yAxis' :'xAxis';
|
|
28
|
-
const [tableExpanded, setTableExpanded] = useState<boolean>(config.table.expanded);
|
|
29
|
-
const [accessibilityLabel, setAccessibilityLabel] = useState('');
|
|
16
|
+
// Debugging.
|
|
17
|
+
// if (config.visualizationType === 'Box Plot') return null
|
|
30
18
|
|
|
31
|
-
const
|
|
32
|
-
|
|
19
|
+
const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
|
|
20
|
+
const [tableExpanded, setTableExpanded] = useState<boolean>(config.table.expanded)
|
|
21
|
+
const [accessibilityLabel, setAccessibilityLabel] = useState('')
|
|
33
22
|
|
|
34
|
-
|
|
23
|
+
const DownloadButton = ({ data }: any, type) => {
|
|
24
|
+
const fileName = `${config.title.substring(0, 50)}.csv`
|
|
25
|
+
|
|
26
|
+
const csvData = Papa.unparse(data)
|
|
35
27
|
|
|
36
28
|
const saveBlob = () => {
|
|
37
29
|
//@ts-ignore
|
|
38
30
|
if (typeof window.navigator.msSaveBlob === 'function') {
|
|
39
|
-
const dataBlob = new Blob([csvData], { type:
|
|
31
|
+
const dataBlob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' })
|
|
40
32
|
//@ts-ignore
|
|
41
|
-
window.navigator.msSaveBlob(dataBlob, fileName)
|
|
33
|
+
window.navigator.msSaveBlob(dataBlob, fileName)
|
|
42
34
|
}
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
download={fileName}
|
|
48
|
-
onClick={saveBlob}
|
|
49
|
-
href={`data:text/csv;base64,${Base64.encode(csvData)}`}
|
|
50
|
-
aria-label="Download this data in a CSV file format."
|
|
51
|
-
className={`btn btn-download no-border`}
|
|
52
|
-
>
|
|
53
|
-
Download Data (CSV)
|
|
54
|
-
</a>
|
|
55
|
-
)
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// Creates columns structure for the table
|
|
59
|
-
const tableColumns = useMemo(() => {
|
|
60
|
-
const newTableColumns = config.visualizationType === 'Pie' ? [] : [{
|
|
61
|
-
Header: '',
|
|
62
|
-
Cell: ({ row }) => {
|
|
63
|
-
const seriesLabel = config.runtime.seriesLabels ? config.runtime.seriesLabels[row.original] : row.original;
|
|
37
|
+
switch (type) {
|
|
38
|
+
case 'download':
|
|
64
39
|
return (
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
fill={
|
|
69
|
-
// non dynamic leged
|
|
70
|
-
!config.legend.dynamicLegend ? colorScale(seriesLabel)
|
|
71
|
-
// dynamic legend
|
|
72
|
-
: config.legend.dynamicLegend ? colorPalettes[config.palette][row.index]
|
|
73
|
-
// fallback
|
|
74
|
-
: '#000'} />}
|
|
75
|
-
<span>{seriesLabel}</span>
|
|
76
|
-
</Fragment>
|
|
40
|
+
<a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`btn btn-download no-border`}>
|
|
41
|
+
Download Data (CSV)
|
|
42
|
+
</a>
|
|
77
43
|
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<>
|
|
88
|
-
{numberFormatter(d[row.original])}
|
|
89
|
-
</>
|
|
90
|
-
);
|
|
91
|
-
},
|
|
92
|
-
id: d[config.runtime.originalXAxis.dataKey],
|
|
93
|
-
canSort: true
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
newTableColumns.push(newCol);
|
|
97
|
-
});
|
|
44
|
+
default:
|
|
45
|
+
return (
|
|
46
|
+
<a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`no-border`}>
|
|
47
|
+
Download Data (CSV)
|
|
48
|
+
</a>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
98
52
|
|
|
99
|
-
|
|
100
|
-
|
|
53
|
+
// Creates columns structure for the table
|
|
54
|
+
const tableColumns = useMemo(() => {
|
|
55
|
+
const newTableColumns =
|
|
56
|
+
config.visualizationType === 'Pie'
|
|
57
|
+
? []
|
|
58
|
+
: [
|
|
59
|
+
{
|
|
60
|
+
Header: '',
|
|
61
|
+
Cell: ({ row }) => {
|
|
62
|
+
const seriesLabel = config.runtime.seriesLabels ? config.runtime.seriesLabels[row.original] : row.original
|
|
63
|
+
return (
|
|
64
|
+
<Fragment>
|
|
65
|
+
{config.visualizationType !== 'Pie' && (
|
|
66
|
+
<LegendCircle
|
|
67
|
+
fill={
|
|
68
|
+
// non dynamic leged
|
|
69
|
+
!config.legend.dynamicLegend
|
|
70
|
+
? colorScale(seriesLabel)
|
|
71
|
+
: // dynamic legend
|
|
72
|
+
config.legend.dynamicLegend
|
|
73
|
+
? colorPalettes[config.palette][row.index]
|
|
74
|
+
: // fallback
|
|
75
|
+
'#000'
|
|
76
|
+
}
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
<span>{seriesLabel}</span>
|
|
80
|
+
</Fragment>
|
|
81
|
+
)
|
|
82
|
+
},
|
|
83
|
+
id: 'series-label'
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
data.forEach((d, index) => {
|
|
88
|
+
const newCol = {
|
|
89
|
+
Header: config.runtime[section].type === 'date' ? formatDate(parseDate(d[config.runtime.originalXAxis.dataKey])) : d[config.runtime.originalXAxis.dataKey],
|
|
90
|
+
Cell: ({ row }) => {
|
|
91
|
+
return <>{numberFormatter(d[row.original])}</>
|
|
92
|
+
},
|
|
93
|
+
id: `${d[config.runtime.originalXAxis.dataKey]}--${index}`,
|
|
94
|
+
canSort: true
|
|
95
|
+
}
|
|
101
96
|
|
|
97
|
+
newTableColumns.push(newCol)
|
|
98
|
+
})
|
|
102
99
|
|
|
100
|
+
return newTableColumns
|
|
101
|
+
}, [config, colorScale])
|
|
103
102
|
|
|
104
|
-
const tableData = useMemo(
|
|
105
|
-
() => config.visualizationType === 'Pie' ? [config.yAxis.dataKey] : config.runtime.seriesKeys,
|
|
106
|
-
[config.runtime.seriesKeys]
|
|
107
|
-
);
|
|
103
|
+
const tableData = useMemo(() => (config.visualizationType === 'Pie' ? [config.yAxis.dataKey] : config.runtime.seriesKeys), [config.runtime.seriesKeys])
|
|
108
104
|
|
|
109
105
|
// Change accessibility label depending on expanded status
|
|
110
106
|
useEffect(() => {
|
|
111
|
-
const expandedLabel = 'Accessible data table.'
|
|
112
|
-
const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
|
|
107
|
+
const expandedLabel = 'Accessible data table.'
|
|
108
|
+
const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
|
|
113
109
|
|
|
114
110
|
if (tableExpanded === true && accessibilityLabel !== expandedLabel) {
|
|
115
|
-
setAccessibilityLabel(expandedLabel)
|
|
111
|
+
setAccessibilityLabel(expandedLabel)
|
|
116
112
|
}
|
|
117
113
|
|
|
118
114
|
if (tableExpanded === false && accessibilityLabel !== collapsedLabel) {
|
|
119
|
-
setAccessibilityLabel(collapsedLabel)
|
|
115
|
+
setAccessibilityLabel(collapsedLabel)
|
|
120
116
|
}
|
|
121
117
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
122
|
-
}, [tableExpanded])
|
|
118
|
+
}, [tableExpanded])
|
|
123
119
|
|
|
124
120
|
const defaultColumn = useMemo(
|
|
125
121
|
() => ({
|
|
126
122
|
minWidth: 150,
|
|
127
123
|
width: 200,
|
|
128
|
-
maxWidth: 400
|
|
124
|
+
maxWidth: 400
|
|
129
125
|
}),
|
|
130
126
|
[]
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
const {
|
|
134
|
-
getTableProps,
|
|
135
|
-
getTableBodyProps,
|
|
136
|
-
headerGroups,
|
|
137
|
-
rows,
|
|
138
|
-
prepareRow,
|
|
139
|
-
} = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns);
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns)
|
|
140
130
|
return (
|
|
141
|
-
<ErrorBoundary component=
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
131
|
+
<ErrorBoundary component='DataTable'>
|
|
132
|
+
<CoveMediaControls.Section classes={['download-links']}>
|
|
133
|
+
<CoveMediaControls.Link config={config} />
|
|
134
|
+
{config.table.download && <DownloadButton data={rawData} type='link' />}
|
|
135
|
+
</CoveMediaControls.Section>
|
|
136
|
+
|
|
137
|
+
<section id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
|
|
138
|
+
<div
|
|
139
|
+
role='button'
|
|
140
|
+
className={tableExpanded ? 'data-table-heading' : 'collapsed data-table-heading'}
|
|
141
|
+
tabIndex={0}
|
|
142
|
+
onClick={() => {
|
|
143
|
+
setTableExpanded(!tableExpanded)
|
|
144
|
+
}}
|
|
145
|
+
onKeyDown={e => {
|
|
146
|
+
if (e.keyCode === 13) {
|
|
147
|
+
setTableExpanded(!tableExpanded)
|
|
148
|
+
}
|
|
149
|
+
}}
|
|
150
|
+
>
|
|
151
|
+
{config.table.label}
|
|
152
|
+
</div>
|
|
153
|
+
<div className='table-container' hidden={!tableExpanded} style={{ maxHeight: config.table.limitHeight && `${config.table.height}px`, overflowY: 'scroll' }}>
|
|
154
|
+
<table className={tableExpanded ? 'data-table' : 'data-table cdcdataviz-sr-only'} {...getTableProps()} aria-rowcount={config?.series?.length ? config?.series?.length : '-1'}>
|
|
155
|
+
<caption className='cdcdataviz-sr-only'>{config.table.caption ? config.table.caption : ''}</caption>
|
|
156
|
+
<caption className='visually-hidden'>{config.table.label}</caption>
|
|
157
|
+
<thead>
|
|
158
|
+
{headerGroups.map((headerGroup, index) => (
|
|
159
|
+
<tr {...headerGroup.getHeaderGroupProps()} key={`headerGroups--${index}`}>
|
|
160
|
+
{headerGroup.headers.map((column, index) => (
|
|
161
|
+
<th
|
|
162
|
+
tabIndex='0'
|
|
163
|
+
title={column.Header}
|
|
164
|
+
key={`trth--${index}`}
|
|
165
|
+
role='columnheader'
|
|
166
|
+
scope='col'
|
|
167
|
+
{...column.getHeaderProps(column.getSortByToggleProps())}
|
|
168
|
+
className={column.isSorted ? (column.isSortedDesc ? 'sort sort-desc' : 'sort sort-asc') : 'sort'}
|
|
169
|
+
{...(column.isSorted ? (column.isSortedDesc ? { 'aria-sort': 'descending' } : { 'aria-sort': 'ascending' }) : null)}
|
|
170
|
+
>
|
|
171
|
+
{index === 0 ? (config.table.indexLabel ? config.table.indexLabel : column.render('Header')) : column.render('Header')}
|
|
172
|
+
<button>
|
|
173
|
+
<span className='cdcdataviz-sr-only'>{`Sort by ${typeof column.render('Header') === 'string' ? column.render('Header').toLowerCase() : column.render('Header')} in ${column.isSorted ? (column.isSortedDesc ? 'descending' : 'ascending') : 'no'} `} order</span>
|
|
174
|
+
</button>
|
|
175
|
+
<div {...column.getResizerProps()} className='resizer' />
|
|
176
|
+
</th>
|
|
177
|
+
))}
|
|
178
|
+
</tr>
|
|
179
|
+
))}
|
|
180
|
+
</thead>
|
|
181
|
+
<tbody {...getTableBodyProps()}>
|
|
182
|
+
{rows.map((row, index) => {
|
|
183
|
+
prepareRow(row)
|
|
184
|
+
return (
|
|
185
|
+
<tr {...row.getRowProps()} key={`tbody__tr-${index}`}>
|
|
186
|
+
{row.cells.map((cell, index) => {
|
|
187
|
+
return (
|
|
188
|
+
<td tabIndex='0' {...cell.getCellProps()} key={`tbody__tr__td-${index}`} role='gridcell'>
|
|
189
|
+
{cell.render('Cell')}
|
|
190
|
+
</td>
|
|
191
|
+
)
|
|
192
|
+
})}
|
|
189
193
|
</tr>
|
|
190
|
-
)
|
|
194
|
+
)
|
|
195
|
+
})}
|
|
196
|
+
</tbody>
|
|
197
|
+
</table>
|
|
198
|
+
{config.regions && config.regions.length > 0 ? (
|
|
199
|
+
<table className='region-table data-table'>
|
|
200
|
+
<caption className='visually-hidden'>Table of the highlighted regions in the visualization</caption>
|
|
201
|
+
<thead>
|
|
202
|
+
<tr>
|
|
203
|
+
<th>Region Name</th>
|
|
204
|
+
<th>Start Date</th>
|
|
205
|
+
<th>End Date</th>
|
|
206
|
+
</tr>
|
|
191
207
|
</thead>
|
|
192
|
-
<tbody
|
|
193
|
-
{
|
|
194
|
-
|
|
208
|
+
<tbody>
|
|
209
|
+
{config.regions.map((region, index) => {
|
|
210
|
+
if (!Object.keys(region).includes('from') || !Object.keys(region).includes('to')) return null
|
|
211
|
+
|
|
195
212
|
return (
|
|
196
|
-
<tr
|
|
197
|
-
{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
tabIndex="0"
|
|
201
|
-
{...cell.getCellProps()}
|
|
202
|
-
key={`tbody__tr__td-${index}`}
|
|
203
|
-
role="gridcell">
|
|
204
|
-
{ cell.render('Cell') }
|
|
205
|
-
</td>
|
|
206
|
-
)
|
|
207
|
-
}
|
|
208
|
-
)}
|
|
213
|
+
<tr key={`row-${region.label}--${index}`}>
|
|
214
|
+
<td>{region.label}</td>
|
|
215
|
+
<td>{formatDate(parseDate(region.from))}</td>
|
|
216
|
+
<td>{formatDate(parseDate(region.to))}</td>
|
|
209
217
|
</tr>
|
|
210
|
-
)
|
|
218
|
+
)
|
|
211
219
|
})}
|
|
212
220
|
</tbody>
|
|
213
221
|
</table>
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
<tr>
|
|
219
|
-
<th>Region Name</th>
|
|
220
|
-
<th>Start Date</th>
|
|
221
|
-
<th>End Date</th>
|
|
222
|
-
</tr>
|
|
223
|
-
</thead>
|
|
224
|
-
<tbody>
|
|
225
|
-
{config.regions.map((region,index) => {
|
|
226
|
-
if(!Object.keys(region).includes('from') || !Object.keys(region).includes('to')) return null
|
|
227
|
-
|
|
228
|
-
return (
|
|
229
|
-
<tr key={`row-${region.label}--${index}`}>
|
|
230
|
-
<td>{region.label}</td>
|
|
231
|
-
<td>{formatDate(parseDate(region.from))}</td>
|
|
232
|
-
<td>{formatDate(parseDate(region.to))}</td>
|
|
233
|
-
</tr>
|
|
234
|
-
)
|
|
235
|
-
})}
|
|
236
|
-
</tbody>
|
|
237
|
-
</table>
|
|
238
|
-
) : ''}
|
|
239
|
-
</div>
|
|
240
|
-
{config.table.download && <DownloadButton data={rawData} />}
|
|
222
|
+
) : (
|
|
223
|
+
''
|
|
224
|
+
)}
|
|
225
|
+
</div>
|
|
241
226
|
</section>
|
|
242
227
|
</ErrorBoundary>
|
|
243
|
-
)
|
|
228
|
+
)
|
|
244
229
|
}
|