@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.
Files changed (65) hide show
  1. package/dist/cdcchart.js +54569 -16
  2. package/examples/Barchart_with_negative.json +34 -0
  3. package/examples/box-plot-data.json +71 -0
  4. package/examples/box-plot.csv +5 -0
  5. package/examples/box-plot.json +124 -0
  6. package/examples/dynamic-legends.json +1 -1
  7. package/examples/example-bar-chart-nonnumeric.json +36 -0
  8. package/examples/example-bar-chart.json +33 -0
  9. package/examples/example-combo-bar-nonnumeric.json +105 -0
  10. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +3 -1
  11. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +1 -1
  12. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +86 -17
  13. package/examples/gallery/paired-bar/paired-bar-chart.json +65 -13
  14. package/examples/line-chart-nonnumeric.json +32 -0
  15. package/examples/line-chart.json +21 -63
  16. package/examples/new-data.csv +17 -0
  17. package/examples/newdata.json +90 -0
  18. package/examples/planet-combo-example-config.json +143 -20
  19. package/examples/planet-example-data-nonnumeric.json +56 -0
  20. package/examples/planet-example-data.json +2 -2
  21. package/examples/planet-pie-example-config-nonnumeric.json +30 -0
  22. package/examples/scatterplot-continuous.csv +17 -0
  23. package/examples/{private/yaxis-test.json → scatterplot.json} +53 -50
  24. package/examples/sparkline-chart-nonnumeric.json +76 -0
  25. package/examples/stacked-vertical-bar-example-negative.json +154 -0
  26. package/examples/stacked-vertical-bar-example-nonnumerics.json +154 -0
  27. package/{src/index.html → index.html} +18 -11
  28. package/package.json +29 -22
  29. package/src/{CdcChart.tsx → CdcChart.jsx} +193 -119
  30. package/src/components/BarChart.jsx +517 -0
  31. package/src/components/BoxPlot.jsx +88 -0
  32. package/src/components/{DataTable.tsx → DataTable.jsx} +125 -32
  33. package/src/components/{EditorPanel.js → EditorPanel.jsx} +376 -115
  34. package/src/components/Filters.jsx +125 -0
  35. package/src/components/Legend.jsx +303 -0
  36. package/src/components/{LineChart.tsx → LineChart.jsx} +87 -22
  37. package/src/components/{LinearChart.tsx → LinearChart.jsx} +172 -113
  38. package/src/components/{PairedBarChart.tsx → PairedBarChart.jsx} +46 -79
  39. package/src/components/{PieChart.tsx → PieChart.jsx} +29 -34
  40. package/src/components/ScatterPlot.jsx +48 -0
  41. package/src/components/{SparkLine.js → SparkLine.jsx} +49 -18
  42. package/src/components/useIntersectionObserver.jsx +29 -0
  43. package/src/data/initial-state.js +44 -8
  44. package/src/hooks/{useColorPalette.ts → useColorPalette.js} +10 -28
  45. package/src/hooks/{useReduceData.ts → useReduceData.js} +27 -13
  46. package/src/hooks/useRightAxis.js +3 -1
  47. package/src/index.jsx +16 -0
  48. package/src/scss/DataTable.scss +23 -1
  49. package/src/scss/main.scss +83 -32
  50. package/vite.config.js +4 -0
  51. package/examples/private/filters.json +0 -170
  52. package/examples/private/line-test-data.json +0 -22
  53. package/examples/private/line-test-two.json +0 -210
  54. package/examples/private/line-test.json +0 -102
  55. package/examples/private/new.json +0 -48800
  56. package/examples/private/newtest.csv +0 -101
  57. package/examples/private/shawn.json +0 -1106
  58. package/examples/private/test.json +0 -10124
  59. package/examples/private/yaxis-testing.csv +0 -27
  60. package/examples/private/yaxis.json +0 -28
  61. package/src/components/BarChart.tsx +0 -579
  62. package/src/components/Legend.js +0 -284
  63. package/src/components/useIntersectionObserver.tsx +0 -27
  64. package/src/index.tsx +0 -18
  65. /package/src/{context.tsx → ConfigContext.jsx} +0 -0
@@ -1,23 +1,27 @@
1
- import React, { useContext, useEffect, useState, useMemo, memo, Fragment } from 'react'
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 Context from '../context'
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<any>(Context)
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<boolean>(config.table.expanded)
21
+ const [tableExpanded, setTableExpanded] = useState(config.table.expanded)
18
22
  const [accessibilityLabel, setAccessibilityLabel] = useState('')
19
23
 
20
- const DownloadButton = ({ data }: any) => {
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
- return (
35
- <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`}>
36
- Download Data (CSV)
37
- </a>
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
- <Fragment>
99
+ <>
53
100
  {config.visualizationType !== 'Pie' && (
54
101
  <LegendCircle
55
102
  fill={
56
- // non dynamic leged
103
+ // non-dynamic leged
57
104
  !config.legend.dynamicLegend
58
105
  ? colorScale(seriesLabel)
59
106
  : // dynamic legend
60
107
  config.legend.dynamicLegend
61
- ? colorPalettes[config.palette][row.index]
62
- : // fallback
108
+ ? colorPalettes[config.palette][row.index]
109
+ : // fallback
63
110
  '#000'
64
111
  }
65
112
  />
66
113
  )}
67
114
  <span>{seriesLabel}</span>
68
- </Fragment>
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
- data.forEach(d => {
76
- const newCol = {
77
- Header: config.runtime[section].type === 'date' ? formatDate(parseDate(d[config.runtime.originalXAxis.dataKey])) : d[config.runtime.originalXAxis.dataKey],
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
- newTableColumns.push(newCol)
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
- const tableData = useMemo(() => (config.visualizationType === 'Pie' ? [config.yAxis.dataKey] : config.runtime.seriesKeys), [config.runtime.seriesKeys])
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
  )