@cdc/chart 4.22.11 → 4.23.2
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/dist/cdcchart.js +54569 -16
- package/examples/Barchart_with_negative.json +34 -0
- package/examples/box-plot-data.json +71 -0
- package/examples/box-plot.csv +5 -0
- package/examples/box-plot.json +124 -0
- package/examples/dynamic-legends.json +1 -1
- package/examples/example-bar-chart-nonnumeric.json +36 -0
- package/examples/example-bar-chart.json +33 -0
- package/examples/example-combo-bar-nonnumeric.json +105 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +3 -1
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +1 -1
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +86 -17
- package/examples/gallery/paired-bar/paired-bar-chart.json +65 -13
- package/examples/line-chart-nonnumeric.json +32 -0
- package/examples/line-chart.json +21 -63
- package/examples/new-data.csv +17 -0
- package/examples/newdata.json +90 -0
- package/examples/planet-combo-example-config.json +143 -20
- package/examples/planet-example-data-nonnumeric.json +56 -0
- package/examples/planet-example-data.json +2 -2
- package/examples/planet-pie-example-config-nonnumeric.json +30 -0
- package/examples/scatterplot-continuous.csv +17 -0
- package/examples/{private/yaxis-test.json → scatterplot.json} +53 -50
- package/examples/sparkline-chart-nonnumeric.json +76 -0
- package/examples/stacked-vertical-bar-example-negative.json +154 -0
- package/examples/stacked-vertical-bar-example-nonnumerics.json +154 -0
- package/{src/index.html → index.html} +18 -11
- package/package.json +29 -22
- package/src/{CdcChart.tsx → CdcChart.jsx} +193 -119
- package/src/components/BarChart.jsx +517 -0
- package/src/components/BoxPlot.jsx +88 -0
- package/src/components/{DataTable.tsx → DataTable.jsx} +125 -32
- package/src/components/{EditorPanel.js → EditorPanel.jsx} +376 -115
- package/src/components/Filters.jsx +125 -0
- package/src/components/Legend.jsx +303 -0
- package/src/components/{LineChart.tsx → LineChart.jsx} +87 -22
- package/src/components/{LinearChart.tsx → LinearChart.jsx} +172 -113
- package/src/components/{PairedBarChart.tsx → PairedBarChart.jsx} +46 -79
- package/src/components/{PieChart.tsx → PieChart.jsx} +29 -34
- package/src/components/ScatterPlot.jsx +48 -0
- package/src/components/{SparkLine.js → SparkLine.jsx} +49 -18
- package/src/components/useIntersectionObserver.jsx +29 -0
- package/src/data/initial-state.js +44 -8
- package/src/hooks/{useColorPalette.ts → useColorPalette.js} +10 -28
- package/src/hooks/{useReduceData.ts → useReduceData.js} +27 -13
- package/src/hooks/useRightAxis.js +3 -1
- package/src/index.jsx +16 -0
- package/src/scss/DataTable.scss +23 -1
- package/src/scss/main.scss +83 -32
- package/vite.config.js +4 -0
- package/examples/private/filters.json +0 -170
- package/examples/private/line-test-data.json +0 -22
- package/examples/private/line-test-two.json +0 -210
- package/examples/private/line-test.json +0 -102
- package/examples/private/new.json +0 -48800
- package/examples/private/newtest.csv +0 -101
- package/examples/private/shawn.json +0 -1106
- package/examples/private/test.json +0 -10124
- package/examples/private/yaxis-testing.csv +0 -27
- package/examples/private/yaxis.json +0 -28
- package/src/components/BarChart.tsx +0 -579
- package/src/components/Legend.js +0 -284
- package/src/components/useIntersectionObserver.tsx +0 -27
- package/src/index.tsx +0 -18
- /package/src/{context.tsx → ConfigContext.jsx} +0 -0
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import React, { useContext, useEffect, useState, useMemo
|
|
1
|
+
import React, { useContext, useEffect, useState, useMemo } from 'react'
|
|
2
2
|
import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
|
|
3
3
|
import Papa from 'papaparse'
|
|
4
4
|
import { Base64 } from 'js-base64'
|
|
5
5
|
|
|
6
6
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
7
|
import LegendCircle from '@cdc/core/components/LegendCircle'
|
|
8
|
+
import Icon from '@cdc/core/components/ui/Icon'
|
|
8
9
|
|
|
9
|
-
import
|
|
10
|
+
import ConfigContext from '../ConfigContext'
|
|
11
|
+
|
|
12
|
+
import CoveMediaControls from '@cdc/core/components/CoveMediaControls'
|
|
10
13
|
|
|
11
14
|
export default function DataTable() {
|
|
12
|
-
const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes } = useContext
|
|
15
|
+
const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes, imageId } = useContext(ConfigContext)
|
|
16
|
+
|
|
17
|
+
// Debugging.
|
|
18
|
+
// if (config.visualizationType === 'Box Plot') return null
|
|
13
19
|
|
|
14
|
-
const legendGlyphSize = 15
|
|
15
|
-
const legendGlyphSizeHalf = legendGlyphSize / 2
|
|
16
20
|
const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
|
|
17
|
-
const [tableExpanded, setTableExpanded] = useState
|
|
21
|
+
const [tableExpanded, setTableExpanded] = useState(config.table.expanded)
|
|
18
22
|
const [accessibilityLabel, setAccessibilityLabel] = useState('')
|
|
19
23
|
|
|
20
|
-
const DownloadButton = ({ data }
|
|
24
|
+
const DownloadButton = ({ data }, type) => {
|
|
21
25
|
const fileName = `${config.title.substring(0, 50)}.csv`
|
|
22
26
|
|
|
23
27
|
const csvData = Papa.unparse(data)
|
|
@@ -31,11 +35,20 @@ export default function DataTable() {
|
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
switch (type) {
|
|
39
|
+
case 'download':
|
|
40
|
+
return (
|
|
41
|
+
<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`}>
|
|
42
|
+
Download Data (CSV)
|
|
43
|
+
</a>
|
|
44
|
+
)
|
|
45
|
+
default:
|
|
46
|
+
return (
|
|
47
|
+
<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`}>
|
|
48
|
+
Download Data (CSV)
|
|
49
|
+
</a>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
// Creates columns structure for the table
|
|
@@ -43,52 +56,127 @@ export default function DataTable() {
|
|
|
43
56
|
const newTableColumns =
|
|
44
57
|
config.visualizationType === 'Pie'
|
|
45
58
|
? []
|
|
46
|
-
:
|
|
59
|
+
: config.visualizationType === 'Box Plot'
|
|
60
|
+
? [
|
|
61
|
+
{
|
|
62
|
+
Header: 'Measures',
|
|
63
|
+
Cell: props => {
|
|
64
|
+
const resolveName = () => {
|
|
65
|
+
let {
|
|
66
|
+
boxplot: { labels }
|
|
67
|
+
} = config
|
|
68
|
+
const columnLookup = {
|
|
69
|
+
columnMean: labels.mean,
|
|
70
|
+
columnMax: labels.maximum,
|
|
71
|
+
columnMin: labels.minimum,
|
|
72
|
+
columnIqr: labels.iqr,
|
|
73
|
+
columnCategory: 'Category',
|
|
74
|
+
columnMedian: labels.median,
|
|
75
|
+
columnFirstQuartile: labels.q1,
|
|
76
|
+
columnThirdQuartile: labels.q3,
|
|
77
|
+
columnOutliers: labels.outliers,
|
|
78
|
+
values: labels.values,
|
|
79
|
+
columnCount: labels.count,
|
|
80
|
+
columnSd: 'Standard Deviation',
|
|
81
|
+
nonOutlierValues: 'Non Outliers'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let resolvedName = columnLookup[props.row.original[0]]
|
|
85
|
+
|
|
86
|
+
return resolvedName
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return resolveName()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
: [
|
|
47
94
|
{
|
|
48
95
|
Header: '',
|
|
49
96
|
Cell: ({ row }) => {
|
|
50
97
|
const seriesLabel = config.runtime.seriesLabels ? config.runtime.seriesLabels[row.original] : row.original
|
|
51
98
|
return (
|
|
52
|
-
|
|
99
|
+
<>
|
|
53
100
|
{config.visualizationType !== 'Pie' && (
|
|
54
101
|
<LegendCircle
|
|
55
102
|
fill={
|
|
56
|
-
// non
|
|
103
|
+
// non-dynamic leged
|
|
57
104
|
!config.legend.dynamicLegend
|
|
58
105
|
? colorScale(seriesLabel)
|
|
59
106
|
: // dynamic legend
|
|
60
107
|
config.legend.dynamicLegend
|
|
61
|
-
|
|
62
|
-
|
|
108
|
+
? colorPalettes[config.palette][row.index]
|
|
109
|
+
: // fallback
|
|
63
110
|
'#000'
|
|
64
111
|
}
|
|
65
112
|
/>
|
|
66
113
|
)}
|
|
67
114
|
<span>{seriesLabel}</span>
|
|
68
|
-
|
|
115
|
+
</>
|
|
69
116
|
)
|
|
70
117
|
},
|
|
71
118
|
id: 'series-label'
|
|
72
119
|
}
|
|
73
120
|
]
|
|
121
|
+
if (config.visualizationType !== 'Box Plot') {
|
|
122
|
+
data.forEach((d, index) => {
|
|
123
|
+
const resolveTableHeader = () => {
|
|
124
|
+
if (config.runtime[section].type === 'date') return formatDate(parseDate(d[config.runtime.originalXAxis.dataKey]))
|
|
125
|
+
return d[config.runtime.originalXAxis.dataKey]
|
|
126
|
+
}
|
|
127
|
+
const newCol = {
|
|
128
|
+
Header: resolveTableHeader(),
|
|
129
|
+
Cell: ({ row }) => {
|
|
130
|
+
return <>{numberFormatter(d[row.original])}</>
|
|
131
|
+
},
|
|
132
|
+
id: `${d[config.runtime.originalXAxis.dataKey]}--${index}`,
|
|
133
|
+
canSort: true
|
|
134
|
+
}
|
|
74
135
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
Cell: ({ row }) => {
|
|
79
|
-
return <>{numberFormatter(d[row.original])}</>
|
|
80
|
-
},
|
|
81
|
-
id: d[config.runtime.originalXAxis.dataKey],
|
|
82
|
-
canSort: true
|
|
83
|
-
}
|
|
136
|
+
newTableColumns.push(newCol)
|
|
137
|
+
})
|
|
138
|
+
}
|
|
84
139
|
|
|
85
|
-
|
|
86
|
-
|
|
140
|
+
if (config.visualizationType === 'Box Plot') {
|
|
141
|
+
config.boxplot.tableData.map((plot, index) => {
|
|
142
|
+
const newCol = {
|
|
143
|
+
Header: plot.columnCategory,
|
|
144
|
+
Cell: props => {
|
|
145
|
+
let resolveCell = () => {
|
|
146
|
+
if (Number(props.row.id) === 0) return true
|
|
147
|
+
if (Number(props.row.id) === 1) return plot.columnMax
|
|
148
|
+
if (Number(props.row.id) === 2) return plot.columnThirdQuartile
|
|
149
|
+
if (Number(props.row.id) === 3) return plot.columnMedian
|
|
150
|
+
if (Number(props.row.id) === 4) return plot.columnFirstQuartile
|
|
151
|
+
if (Number(props.row.id) === 5) return plot.columnMin
|
|
152
|
+
if (Number(props.row.id) === 6) return plot.columnCount
|
|
153
|
+
if (Number(props.row.id) === 7) return plot.columnSd
|
|
154
|
+
if (Number(props.row.id) === 8) return plot.columnMean
|
|
155
|
+
if (Number(props.row.id) === 9) return plot.columnOutliers.length > 0 ? plot.columnOutliers.toString() : '-'
|
|
156
|
+
if (Number(props.row.id) === 10) return plot.values.length > 0 ? plot.values.toString() : '-'
|
|
157
|
+
return <p>-</p>
|
|
158
|
+
}
|
|
159
|
+
return resolveCell()
|
|
160
|
+
},
|
|
161
|
+
id: `${index}`,
|
|
162
|
+
canSort: false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
newTableColumns.push(newCol)
|
|
166
|
+
})
|
|
167
|
+
}
|
|
87
168
|
|
|
88
169
|
return newTableColumns
|
|
89
170
|
}, [config, colorScale])
|
|
90
171
|
|
|
91
|
-
|
|
172
|
+
// prettier-ignore
|
|
173
|
+
const tableData = useMemo(() => (
|
|
174
|
+
config.visualizationType === 'Pie'
|
|
175
|
+
? [config.yAxis.dataKey]
|
|
176
|
+
: config.visualizationType === 'Box Plot'
|
|
177
|
+
? Object.entries(config.boxplot.tableData[0])
|
|
178
|
+
: config.runtime.seriesKeys),
|
|
179
|
+
[config.runtime.seriesKeys])
|
|
92
180
|
|
|
93
181
|
// Change accessibility label depending on expanded status
|
|
94
182
|
useEffect(() => {
|
|
@@ -117,6 +205,11 @@ export default function DataTable() {
|
|
|
117
205
|
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns)
|
|
118
206
|
return (
|
|
119
207
|
<ErrorBoundary component='DataTable'>
|
|
208
|
+
<CoveMediaControls.Section classes={['download-links']}>
|
|
209
|
+
<CoveMediaControls.Link config={config} />
|
|
210
|
+
{config.table.download && <DownloadButton data={rawData} type='link' />}
|
|
211
|
+
</CoveMediaControls.Section>
|
|
212
|
+
|
|
120
213
|
<section id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
|
|
121
214
|
<div
|
|
122
215
|
role='button'
|
|
@@ -131,6 +224,7 @@ export default function DataTable() {
|
|
|
131
224
|
}
|
|
132
225
|
}}
|
|
133
226
|
>
|
|
227
|
+
<Icon display={tableExpanded ? 'minus' : 'plus'} base/>
|
|
134
228
|
{config.table.label}
|
|
135
229
|
</div>
|
|
136
230
|
<div className='table-container' hidden={!tableExpanded} style={{ maxHeight: config.table.limitHeight && `${config.table.height}px`, overflowY: 'scroll' }}>
|
|
@@ -165,7 +259,7 @@ export default function DataTable() {
|
|
|
165
259
|
{rows.map((row, index) => {
|
|
166
260
|
prepareRow(row)
|
|
167
261
|
return (
|
|
168
|
-
<tr {...row.getRowProps()} key={`tbody__tr-${index}`}>
|
|
262
|
+
<tr {...row.getRowProps()} key={`tbody__tr-${index}`} className={`row-${String(config.visualizationType).replace(' ', '-')}--${index}`}>
|
|
169
263
|
{row.cells.map((cell, index) => {
|
|
170
264
|
return (
|
|
171
265
|
<td tabIndex='0' {...cell.getCellProps()} key={`tbody__tr__td-${index}`} role='gridcell'>
|
|
@@ -206,7 +300,6 @@ export default function DataTable() {
|
|
|
206
300
|
''
|
|
207
301
|
)}
|
|
208
302
|
</div>
|
|
209
|
-
{config.table.download && <DownloadButton data={rawData} />}
|
|
210
303
|
</section>
|
|
211
304
|
</ErrorBoundary>
|
|
212
305
|
)
|