@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.
Files changed (80) hide show
  1. package/README.md +5 -5
  2. package/dist/495.js +3 -0
  3. package/dist/703.js +1 -0
  4. package/dist/cdcchart.js +723 -6
  5. package/examples/age-adjusted-rates.json +1486 -1218
  6. package/examples/box-plot-data.json +71 -0
  7. package/examples/box-plot.csv +5 -0
  8. package/examples/{private/yaxis-test.json → box-plot.json} +46 -54
  9. package/examples/case-rate-example-config.json +1 -1
  10. package/examples/covid-confidence-example-config.json +33 -33
  11. package/examples/covid-example-config.json +34 -34
  12. package/examples/covid-example-data-confidence.json +30 -30
  13. package/examples/covid-example-data.json +20 -20
  14. package/examples/cutoff-example-config.json +36 -36
  15. package/examples/cutoff-example-data.json +36 -36
  16. package/examples/date-exclusions-config.json +1 -1
  17. package/examples/dynamic-legends.json +124 -124
  18. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +191 -197
  19. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +230 -240
  20. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +239 -247
  21. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +138 -136
  22. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +79 -79
  23. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +80 -80
  24. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +67 -67
  25. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +179 -110
  26. package/examples/gallery/lollipop/lollipop-style-horizontal.json +215 -219
  27. package/examples/gallery/paired-bar/paired-bar-chart.json +195 -195
  28. package/examples/horizontal-chart.json +35 -35
  29. package/examples/horizontal-stacked-bar-chart.json +34 -34
  30. package/examples/line-chart.json +75 -75
  31. package/examples/new-data.csv +17 -0
  32. package/examples/newdata.json +90 -0
  33. package/examples/paired-bar-data.json +16 -14
  34. package/examples/paired-bar-example.json +48 -48
  35. package/examples/paired-bar-formatted.json +36 -36
  36. package/examples/planet-chart-horizontal-example-config.json +33 -33
  37. package/examples/planet-combo-example-config.json +34 -31
  38. package/examples/planet-example-config.json +35 -33
  39. package/examples/planet-example-data.json +56 -56
  40. package/examples/planet-pie-example-config.json +28 -28
  41. package/examples/stacked-vertical-bar-example.json +1 -1
  42. package/examples/temp-example-config.json +61 -54
  43. package/examples/temp-example-data.json +1 -1
  44. package/package.json +3 -2
  45. package/src/CdcChart.tsx +449 -434
  46. package/src/components/BarChart.tsx +383 -497
  47. package/src/components/BoxPlot.js +92 -0
  48. package/src/components/DataTable.tsx +182 -197
  49. package/src/components/EditorPanel.js +1068 -722
  50. package/src/components/Filters.js +131 -0
  51. package/src/components/Legend.js +286 -329
  52. package/src/components/LineChart.tsx +143 -81
  53. package/src/components/LinearChart.tsx +432 -451
  54. package/src/components/PairedBarChart.tsx +197 -213
  55. package/src/components/PieChart.tsx +105 -151
  56. package/src/components/SparkLine.js +179 -201
  57. package/src/components/useIntersectionObserver.tsx +19 -20
  58. package/src/context.tsx +3 -3
  59. package/src/data/initial-state.js +44 -17
  60. package/src/hooks/useActiveElement.js +13 -13
  61. package/src/hooks/useChartClasses.js +34 -28
  62. package/src/hooks/useColorPalette.ts +56 -63
  63. package/src/hooks/useLegendClasses.js +18 -10
  64. package/src/hooks/useReduceData.ts +64 -77
  65. package/src/hooks/useRightAxis.js +25 -0
  66. package/src/hooks/useTopAxis.js +6 -0
  67. package/src/index.html +19 -19
  68. package/src/index.tsx +13 -16
  69. package/src/scss/DataTable.scss +6 -5
  70. package/src/scss/editor-panel.scss +71 -69
  71. package/src/scss/main.scss +188 -114
  72. package/src/scss/variables.scss +1 -1
  73. package/examples/private/line-test-data.json +0 -22
  74. package/examples/private/line-test-two.json +0 -216
  75. package/examples/private/line-test.json +0 -102
  76. package/examples/private/newtest.csv +0 -101
  77. package/examples/private/shawn.json +0 -1296
  78. package/examples/private/test.json +0 -10124
  79. package/examples/private/yaxis-testing.csv +0 -27
  80. package/examples/private/yaxis.json +0 -28
@@ -1,55 +1,61 @@
1
- import React, { useContext, useState, useEffect, useRef } from 'react';
2
- import { animated, useTransition, interpolate } from 'react-spring';
3
- import ReactTooltip from 'react-tooltip';
1
+ import React, { useContext, useState, useEffect, useRef } from 'react'
2
+ import { animated, useTransition, interpolate } from 'react-spring'
3
+ import ReactTooltip from 'react-tooltip'
4
4
 
5
- import Pie, { ProvidedProps, PieArcDatum } from '@visx/shape/lib/shapes/Pie';
6
- import chroma from "chroma-js";
7
- import { Group } from '@visx/group';
8
- import { Text } from '@visx/text';
9
- import useIntersectionObserver from "./useIntersectionObserver";
5
+ import Pie, { ProvidedProps, PieArcDatum } from '@visx/shape/lib/shapes/Pie'
6
+ import chroma from 'chroma-js'
7
+ import { Group } from '@visx/group'
8
+ import { Text } from '@visx/text'
9
+ import useIntersectionObserver from './useIntersectionObserver'
10
10
 
11
- import Context from '../context';
11
+ import Context from '../context'
12
12
 
13
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
13
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
14
14
 
15
15
  // react-spring transition definitions
16
- type PieStyles = { startAngle: number; endAngle: number };
16
+ type PieStyles = { startAngle: number; endAngle: number }
17
17
 
18
18
  const enterUpdateTransition = ({ startAngle, endAngle }: PieArcDatum<any>) => ({
19
19
  startAngle,
20
- endAngle,
21
- });
20
+ endAngle
21
+ })
22
22
 
23
23
  export default function PieChart() {
24
- const { transformedData: data, config, dimensions, seriesHighlight, colorScale, formatNumber, currentViewport, handleChartAriaLabels } = useContext<any>(Context);
24
+ const { transformedData: data, config, dimensions, seriesHighlight, colorScale, formatNumber, currentViewport, handleChartAriaLabels } = useContext<any>(Context)
25
25
 
26
- const [filteredData, setFilteredData] = useState<any>(undefined);
27
- const [animatedPie, setAnimatePie] = useState<boolean>(false);
26
+ const [filteredData, setFilteredData] = useState<any>(undefined)
27
+ const [animatedPie, setAnimatePie] = useState<boolean>(false)
28
28
 
29
- const triggerRef = useRef();
29
+ const triggerRef = useRef()
30
30
  const dataRef = useIntersectionObserver(triggerRef, {
31
31
  freezeOnceVisible: false
32
- });
32
+ })
33
33
 
34
- useEffect( () => {
34
+ // Make sure the chart is visible if in the editor
35
+ useEffect(() => {
36
+ const element = document.querySelector('.isEditor')
37
+ if (element) {
38
+ // parent element is visible
39
+ console.log('setAnimation')
40
+ setAnimatePie(prevState => true)
41
+ }
42
+ })
43
+
44
+ useEffect(() => {
35
45
  if (dataRef?.isIntersecting && config.animate && !animatedPie) {
36
46
  setTimeout(() => {
37
- setAnimatePie(true);
38
- }, 500);
47
+ setAnimatePie(true)
48
+ }, 500)
39
49
  }
40
50
  }, [dataRef?.isIntersecting, config.animate])
41
51
 
42
52
  type AnimatedPieProps<Datum> = ProvidedProps<Datum> & {
43
- animate?: boolean;
44
- getKey: (d: PieArcDatum<Datum>) => string;
45
- delay?: number;
46
- };
47
-
48
- function AnimatedPie<Datum>({
49
- arcs,
50
- path,
51
- getKey,
52
- }: AnimatedPieProps<Datum>) {
53
+ animate?: boolean
54
+ getKey: (d: PieArcDatum<Datum>) => string
55
+ delay?: number
56
+ }
57
+
58
+ function AnimatedPie<Datum>({ arcs, path, getKey }: AnimatedPieProps<Datum>) {
53
59
  const transitions = useTransition<PieArcDatum<Datum>, PieStyles>(
54
60
  arcs,
55
61
  getKey,
@@ -58,159 +64,107 @@ export default function PieChart() {
58
64
  from: enterUpdateTransition,
59
65
  enter: enterUpdateTransition,
60
66
  update: enterUpdateTransition,
61
- leave: enterUpdateTransition,
62
- },
63
- );
67
+ leave: enterUpdateTransition
68
+ }
69
+ )
64
70
 
65
71
  return (
66
72
  <>
67
- {transitions.map(
68
- ({
69
- item: arc,
70
- props,
71
- key,
72
- }: {
73
- item: PieArcDatum<Datum>;
74
- props: PieStyles;
75
- key: string;
76
- }) => {
77
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(arc.data[config.runtime.yAxis.dataKey])}` : formatNumber(arc.data[config.runtime.yAxis.dataKey])
78
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${arc.data[config.runtime.xAxis.dataKey]}` : arc.data[config.runtime.xAxis.dataKey]
79
-
80
- const tooltip = `<div>
73
+ {transitions.map(({ item: arc, props, key }: { item: PieArcDatum<Datum>; props: PieStyles; key: string }) => {
74
+ let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(arc.data[config.runtime.yAxis.dataKey])}` : formatNumber(arc.data[config.runtime.yAxis.dataKey])
75
+ let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${arc.data[config.runtime.xAxis.dataKey]}` : arc.data[config.runtime.xAxis.dataKey]
76
+
77
+ const tooltip = `<div>
81
78
  ${yAxisTooltip}<br />
82
79
  ${xAxisTooltip}<br />
83
- Percent: ${Math.round(
84
- (((arc.endAngle - arc.startAngle) * 180) /
85
- Math.PI /
86
- 360) *
87
- 100
88
- ) + "%"}
80
+ Percent: ${Math.round((((arc.endAngle - arc.startAngle) * 180) / Math.PI / 360) * 100) + '%'}
89
81
  `
90
82
 
91
- return (
92
- <Group key={key} style={{ opacity: (config.legend.behavior === "highlight" && seriesHighlight.length > 0 && seriesHighlight.indexOf(arc.data[config.runtime.xAxis.dataKey]) === -1) ? 0.5 : 1 }}>
93
- <animated.path
94
- // compute interpolated path d attribute from intermediate angle values
95
- d={interpolate([props.startAngle, props.endAngle], (startAngle, endAngle) => path({
83
+ return (
84
+ <Group key={key} style={{ opacity: config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(arc.data[config.runtime.xAxis.dataKey]) === -1 ? 0.5 : 1 }}>
85
+ <animated.path
86
+ // compute interpolated path d attribute from intermediate angle values
87
+ d={interpolate([props.startAngle, props.endAngle], (startAngle, endAngle) =>
88
+ path({
96
89
  ...arc,
97
90
  startAngle,
98
- endAngle,
99
- }))}
100
- fill={colorScale(arc.data[config.runtime.xAxis.dataKey])}
101
- data-tip={tooltip}
102
- data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
103
- />
104
- </Group>
105
- );
106
- },
107
- )}
108
- {transitions.map(
109
- ({
110
- item: arc,
111
- key,
112
- }: {
113
- item: PieArcDatum<Datum>;
114
- props: PieStyles;
115
- key: string;
116
- }) => {
117
-
118
- const [centroidX, centroidY] = path.centroid(arc);
119
- const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.1;
120
-
121
- let textColor = "#FFF";
122
- if (colorScale(arc.data[config.runtime.xAxis.dataKey]) && chroma.contrast(textColor, colorScale(arc.data[config.runtime.xAxis.dataKey])) < 3.5) {
123
- textColor = "000";
124
- }
125
-
126
- return (
127
- <animated.g key={key}>
128
- {hasSpaceForLabel && (
129
- <Text
130
- style={{ fill: textColor }}
131
- x={centroidX}
132
- y={centroidY}
133
- dy=".33em"
134
- textAnchor="middle"
135
- pointerEvents="none"
136
- >
137
- {Math.round(
138
- (((arc.endAngle - arc.startAngle) * 180) /
139
- Math.PI /
140
- 360) *
141
- 100
142
- ) + "%"}
143
- </Text>
91
+ endAngle
92
+ })
144
93
  )}
145
- </animated.g>
146
- );
147
- },
148
- )}
94
+ fill={colorScale(arc.data[config.runtime.xAxis.dataKey])}
95
+ data-tip={tooltip}
96
+ data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
97
+ />
98
+ </Group>
99
+ )
100
+ })}
101
+ {transitions.map(({ item: arc, key }: { item: PieArcDatum<Datum>; props: PieStyles; key: string }) => {
102
+ const [centroidX, centroidY] = path.centroid(arc)
103
+ const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.1
104
+
105
+ let textColor = '#FFF'
106
+ if (colorScale(arc.data[config.runtime.xAxis.dataKey]) && chroma.contrast(textColor, colorScale(arc.data[config.runtime.xAxis.dataKey])) < 3.5) {
107
+ textColor = '000'
108
+ }
109
+
110
+ return (
111
+ <animated.g key={key}>
112
+ {hasSpaceForLabel && (
113
+ <Text style={{ fill: textColor }} x={centroidX} y={centroidY} dy='.33em' textAnchor='middle' pointerEvents='none'>
114
+ {Math.round((((arc.endAngle - arc.startAngle) * 180) / Math.PI / 360) * 100) + '%'}
115
+ </Text>
116
+ )}
117
+ </animated.g>
118
+ )
119
+ })}
149
120
  </>
150
- );
121
+ )
151
122
  }
152
123
 
153
- let [ width ] = dimensions;
124
+ let [width] = dimensions
154
125
 
155
- if(config && config.legend && !config.legend.hide && currentViewport === 'lg') {
156
- width = width * 0.73;
126
+ if (config && config.legend && !config.legend.hide && currentViewport === 'lg') {
127
+ width = width * 0.73
157
128
  }
158
129
 
159
- const height = config.aspectRatio ? (width * config.aspectRatio) : config.height;
130
+ const height = config.heights.vertical
160
131
 
161
- const radius = Math.min(width, height) / 2;
162
- const centerY = height / 2;
163
- const centerX = width / 2;
164
- const donutThickness = (config.pieType === "Donut") ? 75 : radius;
132
+ const radius = Math.min(width, height) / 2
133
+ const centerY = height / 2
134
+ const centerX = width / 2
135
+ const donutThickness = config.pieType === 'Donut' ? 75 : radius
165
136
 
166
137
  useEffect(() => {
167
- if(seriesHighlight.length > 0 && config.legend.behavior !== "highlight"){
168
- let newFilteredData = [];
138
+ if (seriesHighlight.length > 0 && config.legend.behavior !== 'highlight') {
139
+ let newFilteredData = []
169
140
 
170
- data.forEach((d) => {
171
- if(seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
172
- newFilteredData.push(d);
141
+ data.forEach(d => {
142
+ if (seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
143
+ newFilteredData.push(d)
173
144
  }
174
- });
145
+ })
175
146
 
176
- setFilteredData(newFilteredData);
147
+ setFilteredData(newFilteredData)
177
148
  } else {
178
- setFilteredData(undefined);
149
+ setFilteredData(undefined)
179
150
  }
180
- }, [seriesHighlight]);
151
+ }, [seriesHighlight])
181
152
 
182
153
  useEffect(() => {
183
- ReactTooltip.rebuild();
184
- });
154
+ ReactTooltip.rebuild()
155
+ })
185
156
 
186
157
  return (
187
- <ErrorBoundary component="PieChart">
188
- <svg
189
- width={width}
190
- height={height}
191
- className={`group ${animatedPie ? 'animated' : ''}`}
192
- role="img"
193
- aria-label={handleChartAriaLabels(config)}
194
- >
158
+ <ErrorBoundary component='PieChart'>
159
+ <svg width={width} height={height} className={`animated-pie group ${config.animate === false || animatedPie ? 'animated' : ''}`} role='img' aria-label={handleChartAriaLabels(config)}>
195
160
  <Group top={centerY} left={centerX}>
196
- <Pie
197
- data={filteredData || data}
198
- pieValue={d => d[config.runtime.yAxis.dataKey]}
199
- pieSortValues={() => -1}
200
- innerRadius={radius - donutThickness}
201
- outerRadius={radius}
202
- >
203
- {pie => (
204
- <AnimatedPie<any>
205
- {...pie}
206
- getKey={d => d.data[config.runtime.xAxis.dataKey]}
207
- />
208
- )}
161
+ <Pie data={filteredData || data} pieValue={d => d[config.runtime.yAxis.dataKey]} pieSortValues={() => -1} innerRadius={radius - donutThickness} outerRadius={radius}>
162
+ {pie => <AnimatedPie<any> {...pie} getKey={d => d.data[config.runtime.xAxis.dataKey]} />}
209
163
  </Pie>
210
164
  </Group>
211
165
  </svg>
212
166
  <div ref={triggerRef} />
213
- <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type="light" arrowColor="rgba(0,0,0,0)" className="tooltip"/>
167
+ <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type='light' arrowColor='rgba(0,0,0,0)' className='tooltip' />
214
168
  </ErrorBoundary>
215
169
  )
216
170
  }